Skip to main content

Frontend Overview

Lumie's frontend is a Next.js 16 App Router application that serves the public site, authentication flows, tenant onboarding, the staff admin workspace, and the student dashboard. Routing lives in app/, product logic lives in src/, and browser requests go through the frontend's own /api proxy instead of calling the backend directly from the browser.

What This Repo Owns

  • Public marketing and academy landing pages
  • Login, owner signup, student self-registration, and session refresh flows
  • Owner onboarding after registration
  • Admin-facing academy operations pages under /admin
  • Admin OMR grading, grade-management tables, and result correction actions
  • Student-facing pages under /dashboard, including assignment list and submission flows
  • Frontend-side proxying, auth-cookie handling, and tenant header propagation

Runtime Shape

In local development, the frontend runs on http://localhost:3000 while the backend and stateful services run in the dev cluster. Browser code calls /api/v1/..., and app/api/[...path]/route.ts forwards those requests to NEXT_PUBLIC_API_BASE, rewrites response headers for localhost cookies, and attaches tenant context when custom-domain resolution is enabled.

The root layout in app/layout.tsx wires up:

  • QueryProvider for TanStack Query
  • AuthModalUrlSync plus the shared auth modal
  • the global Toaster
  • local Noto Sans KR fonts and the document shell

Main Implementation Conventions

AreaCurrent approach
RoutingNext.js App Router with route groups and nested layouts
Application structureFeature-Sliced Design under src/
Server stateTanStack Query
Client UI stateZustand and local component state
FormsReact Hook Form with Zod validation
API clientsShared fetch layer plus Orval-generated hooks and query helpers
E2E testsPlaywright
Unit testsVitest with jsdom

Code Map

PathResponsibility
app/Routes, layouts, loading states, error boundaries, and route handlers
src/shared/API primitives, config, generic UI, providers, and utilities
src/entities/Domain models, generated API hooks, and entity-level helpers
src/features/User actions and feature-specific UI or state
src/widgets/Composed screens and shells such as headers, sidebars, and auth modal
components/ui/Forked shadcn primitives kept at the repo root by convention

Source Paths

ClaimSource path
Same-origin /api proxy and cookie rewritinglumie-frontend/app/api/[...path]/route.ts
Browser API base is /apilumie-frontend/src/shared/config/env.ts
Root providers and global shelllumie-frontend/app/layout.tsx
TanStack Query providerlumie-frontend/src/shared/providers/QueryProvider.tsx
Feature-Sliced Design aliaseslumie-frontend/tsconfig.json
Student assignment routeslumie-frontend/app/dashboard/assignments/page.tsx, lumie-frontend/app/dashboard/assignments/[id]/page.tsx
Student assignment API hookslumie-frontend/src/entities/assignment/api/student-queries.ts
Student assignment feature UIlumie-frontend/src/features/assignment-management/list-student-assignments/, lumie-frontend/src/features/assignment-management/view-student-assignment/
OMR result phone correction dialoglumie-frontend/src/entities/exam/ui/ExamResultPhoneEditDialog.tsx
OMR completion modal phone-correction entry pointlumie-frontend/src/features/grade-omr/track-omr-grading/ui/OmrResultPreview.tsx
Student-grade table registration entry pointlumie-frontend/src/features/grade-management/view-grade-detail/ui/StudentGradeTable.tsx

Admin OMR Result Correction

When OMR recognition reads a phone number incorrectly, staff can correct the phone from the OMR completion modal. The shared dialog validates the phone number with React Hook Form and Zod, then calls the exam result phone-correction mutation. If the corrected phone matches an active registered student, the backend response returns the result as registered and the frontend invalidates the exam-result, student-grade, student-result, statistics, and OMR-job caches affected by the correction.

The grade table exposes student registration for unregistered result rows. If staff changes the prefilled OMR phone while registering a student from that row, StudentGradeTable compares the created student's normalized phone with the original row phone and calls the same result-phone correction mutation for that resultId before invalidating the grade and statistics queries. Deleted student rows are blocked from opening grade detail in the table click handler, but this page does not promise broader "view-only" behavior beyond that check.

Verification

cd lumie-frontend
rg -n "API_URL: '/api'|app/api/\\[\\.\\.\\.path\\]|QueryProvider|@/shared" \
app src tsconfig.json
rg -n "dashboard/assignments|useStudentAssignments|useSubmitStudentAssignment" \
app/dashboard src/entities/assignment src/features/assignment-management src/widgets/student-sidebar
rg -n "ExamResultPhoneEditDialog|useUpdateExamResultPhone|RegisterStudentModal" \
src/entities/exam src/entities/student src/features/grade-omr src/features/grade-management
npm run lint

Success means the grep finds the proxy, root provider, FSD alias surfaces, student assignment routes, query hooks, sidebar entry, and OMR result correction entry points, and npm run lint completes with the repo's current ESLint plus Lumie-lint sweep.