Update CLAUDE.md to use correct mixed-case URL without trailing slash (lusa-Back-Planner) to match what is registered in Azure AD. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.7 KiB
4.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
npm run dev # Dev server at localhost:3000
npm run build # Production build → dist/
npm run build:dev # Development build
npm run preview # Preview production build
npm run lint # ESLint
npm run test # Vitest (single run)
npm run test:watch # Vitest (watch mode)
npm run test -- src/test/example.test.ts # Run a single test file
Architecture
Client-side React SPA (no backend) for generating production timelines for L'Oréal USA brand teams. Users set a deadline, pick a production lane, and get a workback timeline with milestones.
Key source paths
src/pages/Index.tsx— Main page; owns form state (lane, date, revisions) and orchestrates child componentssrc/lib/templates.ts— Lane definitions (Rush/Express/Production/Specialist) and timeline generation logic (generateTimeline)src/lib/workdays.ts— Business day math: federal holiday set,subtractWorkdays,countWorkdays, weekend/holiday detectionsrc/lib/parse-brief.ts— Extracts due date, brand, project name from uploaded PDF briefs using pdfjs-dist; uses keyword proximity scoring and multi-regex date detectionsrc/lib/parse-timeline-pdf.ts— Parses existing timeline PDFs for the change request workflowsrc/lib/sla-data.ts— SLA durations for 90+ asset typessrc/lib/brands.ts— 38 L'Oréal brand definitionssrc/components/TimelineView.tsx— Timeline display, inline editing, PDF export (jsPDF + html2canvas)src/components/ChangeRequestTab.tsx— Upload existing timeline, add update reason, re-exportsrc/components/AuthGuard.tsx— Wraps the app; shows a login page with SSO button for unauthenticated users, handles MSAL redirect flowsrc/components/ui/— shadcn/ui primitives (do not manually edit; usenpx shadcn-ui@latest add <component>to add new ones)
Data flow
- User lands on app →
AuthGuardchecks MSAL session; unauthenticated users see a login page with "Sign in with Microsoft" button - After SSO, user uploads a PDF brief →
parse-brief.tsextracts date/brand/lane suggestion - User confirms lane + deadline →
templates.ts:generateTimeline()creates milestones by subtracting workdays from the deadline TimelineViewrenders milestones and handles PDF export- Change requests: upload existing timeline PDF → parser extracts milestones → user selects update reason → new PDF exported
Component tree
main.tsx renders AuthGuard → MsalProvider → App → BrowserRouter → Routes. Auth wraps outside the router, so all routes require authentication. New routes go in App.tsx above the catch-all * route.
Authentication (MSAL / Azure AD SSO)
src/lib/msal-config.tsexportsmsalInstanceandloginRequest; all config is read from env vars at module load timeAuthGuardcallsinstance.initialize()thenhandleRedirectPromise()before rendering; does not auto-redirect — it renders a login page and the user clicks to initiate the redirect- Required
.envvariables (must useVITE_prefix):VITE_AZURE_TENANT_IDVITE_AZURE_CLIENT_IDVITE_AZURE_REDIRECT_URI
- Cache strategy:
sessionStorage; login scope:User.Read - Two environments (see
.env.examplefor full values):- Local:
VITE_AZURE_CLIENT_ID=15c0c4e2-..., redirecthttp://localhost:3000/ - Server:
VITE_AZURE_CLIENT_ID=9079054c-..., redirecthttps://ai-sandbox.oliver.solutions/lusa-Back-Planner
- Local:
- Base path in
vite.config.tsis/lusa-Back-Planner/in production,/in dev — the redirect URI registered in Azure AD must match exactly
Deployment
Static site deployed to Apache on Ubuntu. Production build outputs to dist/. Hosted at https://ai-sandbox.oliver.solutions/lusa-Back-Planner as a subdirectory with FallbackResource for SPA routing. See README.md for full Apache config.
Conventions
- Path alias:
@/*maps tosrc/* - Styling: Tailwind CSS with custom theme (purple primary HSL 258 60% 55%, Montserrat font)
- UI components: shadcn/ui (Radix UI + Tailwind); config in
components.json - Forms: react-hook-form + zod
- Date handling: date-fns (not native Date methods)
- All processing is client-side — no API calls, no server state
- Test environment: Vitest with jsdom; globals enabled (no need to import
describe/it/expect); setup file atsrc/test/setup.ts - TypeScript strict mode is disabled —
strict,strictNullChecks,noImplicitAnyare all off templates.tsbuilds stages dynamically viabuildStages()based on revision count before callinggenerateTimeline()