# AGENTS.md - AI Coding Agent Reference This file provides project-specific guidance for AI coding agents working in this repository. It reflects the current architecture and migration status of the codebase. --- ## Project Overview This project is a Next.js admin dashboard starter that is being migrated from template scaffolding to an app-owned architecture. Current core stack: - **Framework**: Next.js 16 (App Router) - **Language**: TypeScript 5.7 - **UI**: shadcn/ui + Tailwind CSS v4 - **Authentication**: Auth.js - **Persistence**: PostgreSQL + Drizzle ORM - **Data Fetching**: TanStack React Query - **URL State**: nuqs - **Forms**: TanStack Form + Zod - **Charts**: Recharts - **Monitoring**: Sentry - **Package Manager**: Bun preferred, npm acceptable Current migration status: - Auth has been moved to **Auth.js** - Multi-tenant data now uses app-owned **`users`**, **`organizations`**, and **`memberships`** - **`products`** has been migrated to Route Handlers + Drizzle - **`users`** has been migrated to Route Handlers + Drizzle - RBAC now uses a global `users.system_role` plus organization-scoped `memberships.role` - self-service sign-up is disabled; accounts must be created by an admin - some legacy pages still exist as placeholders or transitional seams --- ## Governance Layer This repository now treats governance documentation as implementation input, not optional background reading. Before any task that changes behavior, architecture, permissions, reporting, exports, PDFs, approvals, or CRM workflow, agents must review the relevant standards and foundations first. Primary governance documents: - `AGENTS.md` - `docs/standards/task-contract-template.md` - `docs/standards/task-catalog.md` - `docs/standards/project-foundations.md` - `docs/standards/architecture-rules.md` - `docs/standards/ui-ux-rules.md` - `docs/standards/task-review-checklist.md` - `docs/adr/**` - `docs/business/**` - `docs/security/**` - `docs/implementation/**` for the related feature lineage ### Task Execution Rules All tasks follow these rules: - review first; implementation without review is prohibited - reuse existing foundations before creating new modules, helpers, or flows - extend existing services before creating duplicate services - extend existing route groups before creating duplicate APIs - extend existing permission models before creating duplicate permission systems - extend existing export/report foundations before creating duplicate export flows - keep business logic in feature service layers, not in route handlers or client components - document any exception when an existing foundation cannot be reused Required review order for non-trivial work: 1. `AGENTS.md` 2. `docs/standards/**` 3. relevant `docs/adr/**` 4. relevant `docs/business/**` 5. related completed tasks from `docs/standards/task-catalog.md` and `docs/implementation/**` 6. existing foundations under `src/features/foundation/**` 7. existing feature implementations under `src/features/**` 8. existing APIs under `src/app/api/**` 9. permission and access enforcement under `src/lib/auth/**`, `src/features/crm/security/**`, and `docs/security/**` 10. existing audit patterns under `src/features/foundation/audit-log/**` ### Historical Knowledge Rule Before implementing any feature: 1. review related foundations 2. review related ADRs 3. review related completed tasks from `docs/standards/task-catalog.md` 4. reuse before creating Implementation without historical review is prohibited. ### Required Foundations The following reusable foundations are mandatory whenever the task touches their area: - Audit Foundation: `src/features/foundation/audit-log/**` - Approval Foundation: `src/features/foundation/approval/**` - Storage Foundation: `src/features/foundation/storage/**` and `src/features/foundation/document-artifact/**` - PDF Foundation: `src/features/foundation/pdf-generator/**` and `src/features/crm/quotations/document/**` - Report Foundation: `src/features/crm/reports/**`, `docs/adr/0017-report-foundation.md` - CRM Authorization Foundation: `src/lib/auth/crm-access.ts`, `src/features/crm/security/**`, `docs/security/**` - Customer Ownership Foundation: `docs/adr/0015-customer-ownership-contact-sharing.md`, `src/features/crm/customers/**` - Contact Sharing Foundation: `docs/adr/0015-customer-ownership-contact-sharing.md`, `src/app/api/crm/customers/[id]/contacts/[contactId]/shares/**` If a task touches CRM leads, enquiries, quotations, approvals, reports, exports, storage, or PDFs, agents must explicitly check whether one of these foundations already solves part of the problem. ### Architecture Constraints Frontend constraints: - Next.js App Router only - server components first - `PageContainer` for dashboard page headers - shadcn/ui primitives and existing app UI wrappers - TanStack React Query with server prefetch + `HydrationBoundary` + client `useSuspenseQuery()` for data-heavy app pages - TanStack Form + Zod for forms - `nuqs` for URL state - existing CRM terminology helpers and Thai labels for business-facing CRM UI Backend constraints: - Route Handlers are the main HTTP boundary - feature service layer owns business logic - Drizzle ORM owns database access - auth and organization access go through `@/auth` and `src/lib/auth/session.ts` - CRM scope resolution goes through resolved-access helpers, not direct role-string branching - audit logging goes through `src/features/foundation/audit-log/service.ts` Forbidden patterns: - Redux for new application state - SWR for new server-state fetching - React Hook Form for new forms in this repo - direct database access from client components - business logic inside route handlers - new Clerk usage - direct role-string authorization such as `if (role === 'sales')` - report-specific export systems that bypass `src/features/crm/reports/server/exports/service.ts` ### Mandatory Task Review Before implementation, every non-trivial task must review: - reusable foundations - relevant ADRs - related completed tasks from `docs/standards/task-catalog.md` - related existing APIs - permission and scope enforcement - audit events and existing entity/action naming - duplication risk across services, routes, exports, datasets, and UI shells Implementation without this review is prohibited. --- ## Technology Stack Details ### Core Runtime - Next.js 16.x with App Router - React 19.x - TypeScript strict mode ### Styling & UI - Tailwind CSS v4 - shadcn/ui components - CSS custom properties and theme registry ### State Management - Zustand for local UI state - nuqs for URL search params - TanStack Form + Zod for forms ### Data Fetching - TanStack React Query for server state - server prefetch with `HydrationBoundary` + `dehydrate` - `useSuspenseQuery()` for client consumption of prefetched data ### Authentication & Authorization - Auth.js for authentication - app-owned `organizations` and `memberships` for multi-tenant access - global system role stored on `users.system_role` - organization role and permissions stored on `memberships` - client-side nav filtering is UX-only; real protection must be server-side ### Persistence & APIs - PostgreSQL + Drizzle ORM - Route Handlers under `src/app/api/**` are the main server boundary - feature services call those route handlers through `src/lib/api-client.ts` - mock APIs remain only as **legacy migration seams** --- ## Current Auth Model The current auth model is app-owned and centered around: - `users` - `organizations` - `memberships` Important files: - `src/auth.ts` - Auth.js config and exported helpers - `src/lib/auth/session.ts` - shared server-side auth helpers - `src/proxy.ts` - route protection - `src/db/schema.ts` - current database schema Current behavior: - authentication uses an Auth.js **Credentials** provider - passwords are verified against `users.password_hash` - global RBAC uses `users.system_role` with `super_admin | user` - organization RBAC uses `memberships.role` with `admin | user` - the user row stores `active_organization_id` - session enrichment loads organization and membership data on each request - self-service sign-up is disabled - initial super admin bootstrap is done with the seed script, not through the UI Preferred server-side helpers: - `requireSession()` - `requireSystemRole()` - `requireOrganizationAccess(options?)` Do not introduce new Clerk usage. --- ## Project Structure ```text /src ├── app/ # Next.js App Router │ ├── auth/ # Auth pages │ ├── dashboard/ # Dashboard routes │ ├── api/ # Route handlers │ ├── layout.tsx # Root layout │ └── page.tsx # Landing / redirect entry │ ├── components/ │ ├── ui/ # shadcn/ui and app UI primitives │ ├── layout/ # Sidebar, header, providers │ ├── forms/ # Form field wrappers │ ├── themes/ # Theme system │ └── icons.tsx # Single icon registry │ ├── db/ │ └── schema.ts # Drizzle schema │ ├── features/ │ ├── auth/ │ ├── overview/ │ ├── products/ # Migrated: React Query + Route Handlers + Drizzle │ ├── users/ # Migrated: React Query + Route Handlers + Drizzle + RBAC │ ├── react-query-demo/ │ ├── kanban/ │ ├── chat/ │ ├── notifications/ │ └── profile/ │ ├── config/ │ └── nav-config.ts │ ├── hooks/ │ ├── use-nav.ts │ └── use-data-table.ts │ ├── lib/ │ ├── api-client.ts │ ├── auth/ │ ├── db.ts │ ├── query-client.ts │ └── searchparams.ts │ ├── styles/ └── types/ ``` Relevant docs/plans: - `plans/req.md` - `plans/implementation-plan.md` - `docs/themes.md` - `docs/nav-rbac.md` - `docs/clerk_setup.md` is legacy historical reference only --- ## Build & Development Commands ```bash # Install dependencies bun install # or npm install # Development server bun run dev # or npm run dev # Build bun run build # or npm run build # Start bun run start # or npm run start # Lint bun run lint # or npm run lint # Format bun run format # or npm run format ``` --- ## Environment Configuration Copy `env.example.txt` to `.env.local` and configure: ### Required ```env AUTH_SECRET=your-long-random-secret DATABASE_URL=postgres://postgres:postgres@localhost:5432/training_system SUPER_ADMIN_EMAIL=admin@example.com SUPER_ADMIN_PASSWORD=change-this-password ``` ### Optional for Sentry ```env NEXT_PUBLIC_SENTRY_DSN=https://...@....ingest.sentry.io/... NEXT_PUBLIC_SENTRY_ORG=your-org NEXT_PUBLIC_SENTRY_PROJECT=your-project SENTRY_AUTH_TOKEN=sntrys_... NEXT_PUBLIC_SENTRY_DISABLED="false" ``` Notes: - keep auth and database secrets server-only - OAuth providers can be added later through Auth.js - billing is currently modeled as app-owned organization plan data, not a live provider integration - run `npm run setup:db` on first setup to apply migrations and seed the initial super admin --- ## Code Style Guidelines ### TypeScript - strict mode enabled - use explicit return types for public functions when useful - prefer `interface` for object contracts - use `@/*` imports from `src` ### Component Conventions - use function declarations for components - server components by default - add `'use client'` only when needed - use `cn()` for className merging ### Forms - use TanStack Form via `useAppForm` from `@/components/ui/tanstack-form` - use Zod for submit validation - avoid `useState` inside `AppField` render props ### Buttons - use `