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

257 lines
7.9 KiB
Markdown

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