This commit is contained in:
2026-07-16 09:53:14 +07:00
parent 0fc112a2e8
commit 29cec708a3
1236 changed files with 212848 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
# 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/<name>`.
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/<feature>/api/queries.ts`.
Mutations live in `src/features/<feature>/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.