# Project Architecture This project is a Next.js 16 App Router training-system dashboard using Auth.js, Drizzle ORM, PostgreSQL, shadcn/ui, Tailwind CSS v4, TanStack Query, TanStack Table, TanStack Form, and nuqs. ## Top-Level Structure ```text src/ app/ api/ auth/ dashboard/ components/ layout/ ui/ forms/ config/ db/ features/ hooks/ lib/ styles/ types/ ``` ## App Router Dashboard pages live under `src/app/dashboard`. Common page pattern: ```text page.tsx -> require*DashboardAccess() -> parse search params -> PageContainer -> feature listing/detail/form component ``` API route handlers live under `src/app/api`. Route handlers are the app boundary for persistence and access enforcement. ## Feature Modules Feature modules live under `src/features/`. Strong feature examples: - `training-records`: complete DB-backed feature with tables, forms, upload, review, and certificates. - `courses`: DB-backed CRUD with table and form. - `users`: app-owned user management. - `employee-directory`: responsive directory table and detail/edit flows. - `announcements`: content publishing with role-aware visibility. - `online-lessons`: DB-backed lessons with upload, role-aware list/detail/manage flows. - `audit-logs`: read-only audit table. Feature dependency direction: ```text feature components -> feature api queries/mutations -> feature api service -> apiClient -> route handlers -> feature server data helpers -> db/schema and db client ``` Feature components may import shared UI, hooks, utilities, and feature contracts. They must not import Drizzle or database schema directly. ## Shared Modules Shared UI: - `src/components/ui/*`: shadcn/Radix primitives and app wrappers. - `src/components/ui/table/*`: canonical DataTable stack. - `src/components/ui/tanstack-form.tsx`: canonical form stack. - `src/components/layout/page-container.tsx`: dashboard page shell. - `src/components/icons.tsx`: icon registry. Shared hooks: - `use-data-table` - `use-debounce` - `use-debounced-callback` - `use-nav` - `use-mobile` - `use-media-query` Shared lib: - `api-client.ts` - `db.ts` - `query-client.ts` - `searchparams.ts` - `parsers.ts` - `format.ts` - `auth/session.ts` - `auth/roles.ts` - storage helpers for certificates, announcements, and online lessons ## Data Model Core runtime identity is `users`, not legacy `employees`. During the current remediation phase, the implementation is intentionally split across two related domains: - `users`: authentication, session, permissions, organization context, and audit actor - `employees`: HR-owned worker profile, training owner, matrix targeting, and compliance/reporting subject Current compatibility seams: - `users.employeeId` - `user_employee_maps` Current canonical relationship: - `User 0..1 <-> 0..1 Employee` This means some authenticated users may not have employee profiles, and some employees may exist before a user account is provisioned. Important tables and domains: - `users` - `organizations` - `memberships` - `courses` - `training_records` - `training_matrix` - `reports` - `announcements` - `online_lessons` - audit logs `employees` is legacy migration data and should not be used for new runtime behavior. ## Auth And RBAC Authentication is Auth.js Credentials. Access helpers: - `requireSession()` - `requireOrganizationAccess()` - `requireEmployeeDashboardAccess()` - `requireHRDDashboardAccess()` - `requireITDashboardAccess()` Business roles: - `IT` - `HRD` - `EMPLOYEE` System role: - `super_admin` Access must be enforced server-side in pages and route handlers. Sidebar filtering is user experience only. ## Data Fetching Preferred list flow: ```text server listing component -> getQueryClient() -> fetchQuery(queryOptions(filters)) -> HydrationBoundary -> client component -> useSuspenseQuery(queryOptions(filters)) ``` Query options live in `src/features//api/queries.ts`. Mutations live in `src/features//api/mutations.ts`. Service functions call local route handlers through `apiClient`. ## Tables Canonical stack: - TanStack Table - `useDataTable` - `DataTable` - `DataTableToolbar` - `DataTablePagination` - `DataTableViewOptions` - `DataTableColumnHeader` Tables should manage URL state through nuqs via `useDataTable` and parser helpers. ## Forms Canonical stack: - TanStack Form - Zod - `useAppForm` - project field wrappers Form submit should call feature mutation options. Forms should not call route handlers or Drizzle directly. ## Uploads Upload flows are feature-specific but should reuse existing helpers: - certificates: training records - announcements: announcement attachments - online lessons: video, attachment, thumbnail Route handlers validate file type and size before storage. ## Navigation Navigation lives in `src/config/nav-config.ts`. Role-aware display is handled through nav access metadata and `use-nav`. This does not replace server-side guards. ## Current Legacy Areas Some template or older areas remain: - `products` - `employees` - `forms` - `kanban` - `chat` - demo/react-query pages Treat these as legacy/template features unless the user specifically asks to modernize them.