# 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.
