Files
alla-tms/docs/PROJECT_ARCHITECTURE.md
2026-07-16 09:53:14 +07:00

5.1 KiB

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

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:

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:

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:

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.