commit
This commit is contained in:
256
docs/AI_DEVELOPMENT_GUIDE.md
Normal file
256
docs/AI_DEVELOPMENT_GUIDE.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user