Frontend: - Replace Next.js with Vite + React + TypeScript - Add new component architecture (app-shell, sidebar, dashboard modules) - Implement product modules: FRAME, safety protocols, walkthrough checkin, campus/staff attendance, personality quiz, sign language, classroom timer - Add shadcn/ui component library with Tailwind CSS - Remove legacy generated components, stores, and pages Backend: - Add product migrations: frame_entries, user_progress, safety_quiz_results, walkthrough_checkins, communication_events, personality_quiz_results, campus_attendance_config/summaries, staff_attendance_records, content_catalog - Add corresponding models, services, and routes - Implement cookie-based auth with refresh token rotation - Add content catalog seeder with product content - Migrate to ESLint flat config - Switch from yarn to npm Infrastructure: - Update .gitignore for new tooling - Add project documentation (CLAUDE.md, docs/) - Remove deprecated config files and yarn.lock Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
Frontend Architecture
Purpose
The frontend uses a three-layer architecture:
- View layer
- Business logic layer
- API/data access layer
The goal is to keep UI components thin, keep business rules testable, and keep all backend communication centralized.
Layer 1: View
Location:
frontend/src/components/frontend/src/pages/
Responsibilities:
- Render UI.
- Own visual composition and layout.
- Call business-layer hooks/actions.
- Show loading, empty, and error states from business-layer state.
- Keep form markup and user interaction wiring close to the component.
- Compose shared UI primitives from
frontend/src/components/ui/for common controls and repeated states.
View components must not:
- Call
fetchdirectly. - Import backend API modules directly.
- Contain tenant, role, permission, or workflow rules.
- Transform backend DTOs into product state when that transformation belongs to business logic.
- Hide failed persisted workflows with static data.
Layer 2: Business Logic
Location:
frontend/src/business/frontend/src/shared/business/
Responsibilities:
- Own React Query hooks for server state.
- Own local workflow state when it is not purely visual.
- Transform backend DTOs into UI-facing view models.
- Apply role, permission, tenant, campus, and workflow rules received from backend contracts.
- Own calculations, filters, sorting, validation helpers, and derived state.
- Coordinate multiple API calls for one user workflow.
Business logic may import:
frontend/src/shared/api/frontend/src/shared/types/frontend/src/shared/constants/frontend/src/shared/business/
Business logic must not:
- Render JSX.
- Read or write secrets.
- Duplicate backend authorization or tenant enforcement.
- Create another HTTP client.
Shared business helpers should be used for repeated cross-module mechanics. frontend/src/shared/business/queryMutations.ts centralizes React Query mutation invalidation, frontend/src/shared/business/apiListRows.ts centralizes ApiListResponse.rows extraction and mapping, and frontend/src/shared/business/queryState.ts centralizes multi-query loading/error aggregation.
Layer 3: API/Data Access
Location:
frontend/src/shared/api/frontend/src/shared/types/
Responsibilities:
- Own all HTTP calls to
backend/. - Send backend-owned auth cookies through the shared HTTP client.
- Define request and response types.
- Preserve backend errors and expose them to business logic.
- Keep endpoint paths and payload shapes in one place.
API/data access modules must not:
- Render UI.
- Own component state.
- Apply product workflow decisions that belong to business logic.
- Return mock/static data for persisted workflows.
- Swallow backend failures.
Import Direction
Allowed direction:
View -> Business Logic -> API/Data Access -> Backend
Shared constants and shared types may be imported by any layer.
Error Handling
Backend/API errors are parsed in frontend/src/shared/api/httpClient.ts and normalized for UI rendering through frontend/src/shared/errors/errorMessages.ts.
Feature hooks and components must use the shared error formatter instead of reading .message directly or creating local formatter helpers. Detailed rules live in frontend/docs/error-handling.md.
npm run test includes frontend/src/shared/architecture/import-boundaries.test.ts, which enforces these import boundaries and keeps runtime data access centralized in the shared API layer.
Disallowed direction:
API/Data Access -> Business Logic
API/Data Access -> View
Business Logic -> View
Feature Structure
For new or updated product modules, use this shape:
frontend/src/business/<module>/
hooks.ts
mappers.ts
selectors.ts
validators.ts
types.ts
frontend/src/shared/api/<module>.ts
frontend/src/shared/types/<module>.ts
frontend/src/components/<module>/
Only create files that are actually needed for the module.
Routing
The frontend uses React Router. Top-level URL route declarations live in a typed object route config instead of inline JSX in App.tsx.
Target structure:
frontend/src/app/AppProviders.tsx
frontend/src/app/AppRouter.tsx
frontend/src/app/appRoutes.tsx
frontend/src/app/ModuleRouteGuard.tsx
frontend/src/app/shellOutletContext.ts
frontend/src/shared/constants/routes.ts
frontend/src/shared/constants/moduleRoutes.ts
Rules:
App.tsxcomposes providers and renders the router only.appRoutes.tsxowns top-level and product URL route objects.- Product routes are lazy-loaded route elements under the shared app shell layout.
- Route page adapters stay thin and delegate product behavior to business hooks.
AppRouter.tsxusesuseRoutes(appRoutes).APP_ROUTE_PATHSowns path constants and module route metadata maps eachModuleIdto exactly one route path.- The browser URL is the source of truth for the active product module.
- Sidebar, footer, dashboard actions, and other module navigation should navigate by route path instead of storing active module state.
/loginremains the deterministic destination for expired access plus expired refresh sessions.- Restricted module routes redirect to
/dashboard.
Update Rule
When updating an existing module:
- Add or update backend API endpoints first.
- Add typed API functions in
frontend/src/shared/api/. - Add business hooks and mappers in
frontend/src/business/<module>/. - Update view components to call the business layer.
- Remove direct data access from the component.
- Add or update module documentation.
Current Baseline
The active frontend already has:
- React 19, Vite 8, TypeScript 6, Tailwind 4, Vitest 4, and ESLint 10 as the current active tooling baseline.
- Current top-level URL routes are
/,/login, and*; product module routes are nested under the shared shell layout and lazy-loaded fromfrontend/src/pages/modules/. - View components under
frontend/src/components/andfrontend/src/pages/. - Shared backend API foundation under
frontend/src/shared/api/. - Shared frontend constants and types under
frontend/src/shared/. - Cross-module UI-facing product types under
frontend/src/shared/types/app.ts. - Static app navigation/media config under
frontend/src/shared/constants/appData.tsand static personality catalog metadata underfrontend/src/shared/constants/personalityCatalog.ts. - Backend-owned campus records and branding load through
frontend/src/shared/api/campuses.tsandfrontend/src/business/campuses/; frontend keeps only generic campus helpers and allowed Tailwind branding tokens. - Test-only seed records under
frontend/src/test-seeds/; runtime code must not import that directory. - Theme names, default theme values, CSS class names, and media query constants under
frontend/src/shared/constants/theme.ts; global light/dark CSS tokens remain infrontend/src/index.cssand Tailwind maps to those variables infrontend/tailwind.config.ts. - React Query keys, UI timing values, storage keys, and sidebar runtime constants live in dedicated files under
frontend/src/shared/constants/. - Auth/profile session logic under
frontend/src/business/auth/, withAuthContextacting as a thin provider. The auth transport is backend-owned HttpOnly cookie auth documented inbackend/docs/cookie-auth.mdandfrontend/docs/auth-integration.md. - App shell state, access selection, campus display lookup, mobile overlay visibility, shell outlet context, and prepared Sidebar/TopBar/GuestBanner/Footer props live under
frontend/src/business/app-shell/. The shared shell layout remains a thin view composition infrontend/src/components/AppLayout.tsx. - Top bar shell state under
frontend/src/business/top-bar/, with search, badges, notifications, profile menu, and sign-in modal composition split underfrontend/src/components/top-bar/. - FRAME entries under
frontend/src/business/frame/, with typed API calls infrontend/src/shared/api/frame.tsand explicit empty/error states in the view. - Current-user progress under
frontend/src/business/user-progress/, with typed API calls infrontend/src/shared/api/userProgress.tsfor learned signs and zone check-ins. - Safety quiz results under
frontend/src/business/safety-quiz/, with typed API calls infrontend/src/shared/api/safetyQuizResults.ts. - Walk-through check-ins under
frontend/src/business/walkthrough/, with typed API calls infrontend/src/shared/api/walkthrough.ts, shared constants infrontend/src/shared/constants/walkthrough.ts, and summary calculations in typed selectors. - Communications under
frontend/src/business/communications/, with typed API calls infrontend/src/shared/api/communications.tsfor parent messages, internal alerts, and dashboard upcoming events. - EI/personality results under
frontend/src/business/personality/, with typed API calls infrontend/src/shared/api/personality.ts, DTO mappers, distribution selectors, workflow-specific hook files, and explicit loading/error states in the view. - Campus attendance config and daily summaries under
frontend/src/business/campus-attendance/, with typed API calls infrontend/src/shared/api/campusAttendance.ts, DTO mappers, summary selectors, and explicit loading/error states in the view. - Staff attendance snapshot and director staff counts under
frontend/src/business/staff-attendance/, with typed API calls infrontend/src/shared/api/staffAttendance.ts, DTO mappers, rollup selectors, and explicit loading/error states in the view. - Handbook policies under
frontend/src/business/policies/, with typed document API calls infrontend/src/shared/api/documents.ts, DTO mappers, selectors, and explicit loading/error states in the view. - Classroom timer built-in sounds are local Web Audio behavior. AI-generated sounds are not exposed until a backend audio provider contract exists.
- UI component variants live in dedicated non-component files such as
frontend/src/components/ui/button-variants.ts,badge-variants.ts,toggle-variants.ts, andnavigation-menu-variants.ts. - Loading, empty, and error state panels are centralized through
frontend/src/components/ui/state-panel.tsx, with tone/size/alignment variants infrontend/src/components/ui/state-panel-variants.ts. - Repeated module headings use
frontend/src/components/ui/module-header.tsx; simple native dropdowns usefrontend/src/components/ui/native-select.tsx. - Reusable UI/context hooks live outside provider component files, including
frontend/src/components/theme-context.ts,frontend/src/components/ui/form-field-context.ts,frontend/src/components/ui/sidebar-context.ts, andfrontend/src/contexts/auth-context.ts. - The tracked large framework components have been split into thin wrappers and focused view pieces backed by business hooks/selectors.
- Frontend TypeScript runs in strict mode through
npm run typecheck;npm run buildruns typecheck before Vite. - Frontend unit tests run through
npm run testwith Vitest. Current coverage includes business-layer selectors and mappers for app-shell/sidebar, auth, campuses, campus attendance, classroom support, classroom timer, communications, community, dashboard, director dashboard, ESA funding, FRAME, personality, policies, safety quiz, sign language, staff attendance, top bar, user progress, vocational, walk-through check-in/summary/form workflows, and zones. npm run testalso enforces API/business/view import boundaries throughfrontend/src/shared/architecture/import-boundaries.test.ts.- Frontend backend-free smoke tests run through
npm run test:e2ewith Playwright. Current smoke coverage verifies teacher, director, and superintendent guest navigation/access paths. - Frontend backend-seeded content tests run through
npm run test:e2e:contentwith Playwright after backend migrations, seeders, and the backend server are running. - Frontend dependency verification is clean:
npm run lint,npm run test,npm run build,npm audit --audit-level=low, andnpm outdatedpass for stable package releases.
Known Remaining Gaps
- New or changed framework wrappers should follow the same thin-view plus business-hook pattern.
- New product routes should be added to module route metadata,
frontend/src/app/appRoutes.tsx, and covered by route metadata tests. - TypeScript compiler strictness is enabled for the current baseline. Keep future slices compatible with
strict,noUnusedLocals, andnoUnusedParameters. - Unit test coverage exists for route config, module route metadata, API/data-access behavior, auth refresh/retry behavior, business-layer selector/mapper/report slices, and import-boundary guardrails. Guest-role Playwright smoke tests cover the current backend-free staff/director/superintendent paths.