# AI Development Guide

This document is the project operating guide for AI coding agents. It records the current implementation patterns that must be reused before adding new code.

## Priority Order

When instructions conflict, follow this order:

1. Existing project implementation
2. `docs/AI_DEVELOPMENT_GUIDE.md`
3. `docs/PROJECT_ARCHITECTURE.md`
4. `AGENTS.md`
5. `kiranism-shadcn-dashboard`
6. shadcn/ui
7. TanStack Table, TanStack Query, TanStack Form, and nuqs docs
8. Next.js best practices

## Canonical Features

Use these features as references before creating or changing a feature:

1. `training-records`: canonical full feature for DB-backed CRUD, tables, forms, upload, review flow, React Query, and Route Handlers.
2. `employee-directory`: canonical responsive DataTable and table toolbar customization.
3. `announcements`: canonical lightweight content feature with publish/archive state and file attachment.
4. `audit-logs`: canonical read-only table with filters.

## Feature Structure

Runtime features should live under `src/features/<feature-name>/`.

Preferred structure:

```text
src/features/<feature>/
  api/
    types.ts
    service.ts
    queries.ts
    mutations.ts
  components/
  constants/
  schemas/
  server/
```

Use only the folders a feature actually needs. Do not create placeholder folders.

Dashboard routes live in `src/app/dashboard/<route>/page.tsx`.
Route handlers live in `src/app/api/<feature>/route.ts` and `src/app/api/<feature>/[id]/route.ts`.

## Naming Rules

- Use kebab-case filenames for feature components, routes, and docs.
- Use PascalCase React components.
- Keep API contracts in `api/types.ts`.
- Name table files after local convention: either `<feature>-table.tsx` and `<feature>-columns.tsx`, or `components/<feature>-tables/index.tsx` and `columns.tsx` when the feature already uses that folder.
- Name action menu components consistently, for example `pending-review-action-menu.tsx` or `employee-directory-action-menu.tsx`.

## Data Flow

Use the established app-owned flow:

```text
Page Server Component
  -> require*DashboardAccess()
  -> searchParamsCache.parse()
  -> Listing Component
  -> getQueryClient().fetchQuery()
  -> HydrationBoundary
  -> Client Table/Form Component
  -> useSuspenseQuery()/useQuery()
  -> api/service.ts
  -> local Route Handler
  -> server/* data helper
  -> Drizzle
```

Do not import Drizzle into UI components.
Do not import mock API data into runtime UI.

## Authentication And Authorization

Use Auth.js and the shared helpers:

- `requireEmployeeDashboardAccess()`
- `requireHRDDashboardAccess()`
- `requireITDashboardAccess()`
- `requireOrganizationAccess()`
- `requireHRD()`
- `isHRD()`, `isIT()`, `getBusinessRole()`

Nav filtering is only UX. Route handlers and server pages must enforce access.

## User And Employee Boundary

Use these definitions consistently during the current migration state:

- `users` = system identity, authentication, session, permissions, and audit actor
- `employees` = HR master data, employee profile, and training ownership

Current runtime reality is transitional:

- `users.employeeId` still exists as a compatibility seam
- `user_employee_maps` still exists as an explicit linking table
- training ownership and reporting scope still resolve primarily through `employees`

Treat the canonical relationship as `User 0..1 <-> 0..1 Employee` until a later migration removes the seam.

Rules:

- actor fields such as `createdBy`, `approvedBy`, `publishedBy`, and audit actor must point to `users`
- owner fields for training targets, compliance, and matrix applicability must point to `employees`
- do not introduce a third user-employee linking mechanism

## Table Pattern

Default table implementation must reuse:

- `DataTable`
- `DataTableToolbar`
- `DataTablePagination`
- `DataTableViewOptions`
- `DataTableColumnHeader`
- `useDataTable`
- TanStack `ColumnDef`
- action menu components for row commands

Canonical references:

- `src/features/training-records/components/training-record-tables/index.tsx`
- `src/features/training-records/components/pending-review-table.tsx`
- `src/features/employee-directory/components/employee-directory-table.tsx`

Rules:

- Do not build manual table pagination for new data tables.
- Do not create a new toolbar if `DataTableToolbar` or a small wrapper around it is enough.
- Use `columnPinning: { right: ['actions'] }` for row actions.
- Use `DataTableColumnHeader` for sortable headers.
- Use `meta` on columns for labels, placeholders, filter variants, options, and class names.
- Put horizontal overflow inside the DataTable shell, not the full page.

Manual tables are acceptable only for tiny static layouts or legacy code being intentionally left unchanged.

## Form Pattern

The project uses TanStack Form, not React Hook Form.

Use:

- `useAppForm`
- `useFormFields`
- field wrappers from `@/components/ui/tanstack-form`
- Zod schemas from `src/features/<feature>/schemas`
- `scrollToFirstError()` where helpful

Canonical references:

- `src/features/training-records/components/training-record-form.tsx`
- `src/features/courses/components/course-form.tsx`
- `src/features/training-policy/components/training-policy-form.tsx`

## Mutation Pattern

Use TanStack Query mutation option factories in `api/mutations.ts`.

```text
component -> useMutation({ ...featureMutation })
mutation -> api/service.ts
service -> apiClient()
route handler -> Drizzle
```

This repo does not use `next-safe-action` as a canonical runtime pattern.

## Persistence Pattern

The project uses PostgreSQL with Drizzle ORM.

Use:

- `src/db/schema.ts`
- `src/lib/db.ts`
- feature `server/*-data.ts` helpers
- route handlers under `src/app/api`

Do not introduce Prisma.

## Dialog And Action Pattern

Use existing shadcn/Radix wrappers:

- `Dialog`
- `Sheet`
- `AlertDialog`
- `AlertModal`
- dropdown action menus via `DropdownMenu`

Row actions should be grouped into action menu components when there are multiple commands.

## Upload Pattern

Reuse existing upload utilities and storage helpers:

- `FileUploader`
- `certificate-storage.ts`
- `announcement-storage.ts`
- `online-lesson-storage.ts`

Do not create new storage logic until the existing helper cannot support the feature.

## Layout Pattern

Dashboard pages must use `PageContainer`.

Rules:

- Do not create a new dashboard shell.
- Do not nest cards inside cards.
- Use cards for forms, filters, empty states, and repeated content items.
- Use `w-full min-w-0 max-w-full` on table containers.
- Keep overflow scoped to tables with `overflow-x-auto`.
- Buttons must not clip on mobile; use wrapping containers and `shrink-0 whitespace-nowrap` when needed.

## UI Rules

- Use `@/components/icons` only for icons.
- Use `cn()` for className composition.
- Use shadcn/ui primitives from `@/components/ui`.
- Use `Badge` for status.
- Use `Button` variants rather than custom button styling.
- Prefer Thai labels in user-facing training-system UI.

## Refactoring Rules

- First inspect existing feature, shared components, hooks, forms, tables, and dialogs.
- If code is off-pattern, propose or perform a scoped refactor before expanding it.
- Do not propagate legacy patterns into new work.
- Avoid broad rewrites unless the requested change touches shared contracts or UI behavior.
- Dashboard `page.tsx` entrypoints must call a shared `require*DashboardAccess()` helper unless the route is an explicit redirect shell or documented exception.

## Required Checklist

Before final response, verify:

- Existing pattern was inspected.
- Shared components/hooks were reused.
- DataTable was used for data tables.
- TanStack Form and Zod were used for forms.
- Route handlers and Drizzle were used for persistence.
- Server-side access checks remain in place.
- Page layout is responsive and does not overflow.
- Icons come from `@/components/icons`.
- No mock data was imported into runtime UI.

Final principle: consistency is more important than novelty. New work should look like it has always belonged to this codebase.
