670 lines
21 KiB
Markdown
670 lines
21 KiB
Markdown
# 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 `<Button isLoading={isPending}>` for loading states
|
|
|
|
---
|
|
|
|
## Navigation & RBAC
|
|
|
|
Navigation is configured in `src/config/nav-config.ts`.
|
|
|
|
Current access properties:
|
|
|
|
- `systemRole`
|
|
- `requireOrg`
|
|
- `permission`
|
|
- `role`
|
|
- `plan`
|
|
- `feature`
|
|
|
|
Notes:
|
|
|
|
- `systemRole` is for global access such as `super_admin`
|
|
- `requireOrg` remains a compatibility seam and means the user must have an active organization
|
|
- nav filtering in `src/hooks/use-nav.ts` uses Auth.js session data
|
|
- server routes and server pages must enforce real access independently
|
|
|
|
---
|
|
|
|
## Date & Time Formatting Rules
|
|
|
|
- All date and time rendering must use the shared formatter in `src/lib/date-format.ts`.
|
|
- Never use `Date.prototype.toLocaleString()`, `toLocaleDateString()`, `toLocaleTimeString()`, or `Intl.DateTimeFormat()` directly inside React components.
|
|
- UI date display standard:
|
|
- Date: `YYYY-MM-DD`
|
|
- DateTime: `YYYY-MM-DD HH:mm:ss`
|
|
- Time: `HH:mm:ss`
|
|
- API responses must remain ISO-8601 UTC.
|
|
- UI is responsible for formatting.
|
|
- Timezone is fixed to `Asia/Bangkok`.
|
|
- Calendar system must always use Gregorian (AD), never Buddhist Era (BE).
|
|
- All formatting must be deterministic to ensure identical SSR and Client rendering and prevent React hydration mismatches.
|
|
|
|
---
|
|
|
|
## Authentication Patterns
|
|
|
|
### Protected Routes
|
|
|
|
Dashboard routes are protected through `src/proxy.ts`.
|
|
|
|
Example protected page:
|
|
|
|
```tsx
|
|
import { auth } from '@/auth';
|
|
import { redirect } from 'next/navigation';
|
|
|
|
export default async function Page() {
|
|
const session = await auth();
|
|
|
|
if (!session?.user) {
|
|
redirect('/auth/sign-in');
|
|
}
|
|
|
|
if (!session.user.activeOrganizationId) {
|
|
redirect('/dashboard/workspaces');
|
|
}
|
|
|
|
return <div>Protected</div>;
|
|
}
|
|
```
|
|
|
|
### Shared Server Helpers
|
|
|
|
Prefer:
|
|
|
|
- `requireSession()`
|
|
- `requireSystemRole()`
|
|
- `requireOrganizationAccess(options?)`
|
|
|
|
### Plan / Feature Gating
|
|
|
|
Do not use vendor-specific gating components.
|
|
|
|
Read plan or feature state from app-owned organization data and enforce it server-side.
|
|
|
|
---
|
|
|
|
## Data Fetching Patterns
|
|
|
|
### Service Layer Architecture
|
|
|
|
Each feature should use:
|
|
|
|
```text
|
|
src/features/<name>/api/
|
|
types.ts
|
|
service.ts
|
|
queries.ts
|
|
mutations.ts # when mutations exist
|
|
```
|
|
|
|
Rules:
|
|
|
|
- components import types from `types.ts`
|
|
- components call query options from `queries.ts`
|
|
- services call local route handlers through `apiClient`
|
|
- route handlers talk to Drizzle / database
|
|
|
|
### Backend Patterns
|
|
|
|
Preferred patterns in this repo:
|
|
|
|
| Pattern | Guidance |
|
|
| --- | --- |
|
|
| Route Handlers + ORM | Preferred for app-owned features |
|
|
| Server Actions + ORM | Acceptable when it fits the feature well |
|
|
| BFF | Acceptable when proxying to an external backend |
|
|
| Mock | Legacy only, not the preferred path |
|
|
|
|
### React Query
|
|
|
|
Preferred pattern for new pages:
|
|
|
|
1. define query options in `queries.ts`
|
|
2. prefetch in the server page
|
|
3. hydrate with `HydrationBoundary`
|
|
4. read with `useSuspenseQuery()`
|
|
|
|
Required pattern for CRUD mutations:
|
|
|
|
1. every feature must define centralized query key factories in `queries.ts`
|
|
2. use grouped keys such as `all`, `lists()`, `list(filters)`, `details()`, `detail(id)`, plus child-resource keys like `contacts(id)` or `followups(id)` when needed
|
|
3. after create, explicitly invalidate the list-level key
|
|
4. after update, explicitly invalidate both list and detail keys
|
|
5. after delete, explicitly invalidate the list key and remove stale detail queries with `removeQueries`
|
|
6. invalidate related queries affected by the mutation, such as counts, child tabs, document previews, approval panels, and cross-feature related lists
|
|
7. do not rely on `staleTime` alone to refresh production CRUD data
|
|
8. do not rely on `router.refresh()` alone for CRUD freshness; React Query invalidation is required first, and `router.refresh()` is optional only as a supplement
|
|
|
|
Mutation callback safety rule:
|
|
|
|
- if a shared mutation object from `api/mutations.ts` is spread into `useMutation({ ...sharedMutation, ... })`, do not override `onSuccess` or `onSettled` in a way that drops cache invalidation
|
|
- prefer keeping cache invalidation inside the shared mutation definition
|
|
- if component-level success behavior is needed, either:
|
|
- put invalidation in shared `onSettled` and keep UI concerns like toast and closing dialogs in component `onSuccess`, or
|
|
- call the shared invalidate helper explicitly from the component before closing the sheet/dialog
|
|
|
|
UI completion rule after successful mutation:
|
|
|
|
- close sheet/dialog only after the mutation promise resolves successfully
|
|
- table/detail views must show fresh data immediately without a full browser refresh
|
|
- related tabs and counts must refresh in the same interaction when their backing data changed
|
|
|
|
### URL State
|
|
|
|
Use `nuqs` for table search params and list filters.
|
|
|
|
### Tables
|
|
|
|
Use:
|
|
|
|
- TanStack Table
|
|
- React Query
|
|
- `useDataTable`
|
|
- column definitions under the feature component tree
|
|
|
|
---
|
|
|
|
## Current Migration Guidance
|
|
|
|
Use the migrated `products` feature as the main reference for new CRUD work.
|
|
|
|
Important current status:
|
|
|
|
- `products` is migrated to Auth.js + Route Handlers + Drizzle
|
|
- `users` is migrated to Auth.js + Route Handlers + Drizzle
|
|
- new features should follow the `products` and `users` pattern, not the old mock pattern
|
|
|
|
Legacy seams still present:
|
|
|
|
- `src/constants/mock-api.ts`
|
|
- `src/constants/mock-api-users.ts`
|
|
- some placeholder pages under workspaces, billing, profile, and exclusive sections
|
|
|
|
Treat those as migration seams, not target architecture.
|
|
|
|
---
|
|
|
|
## Deployment Notes
|
|
|
|
### Production Requirements
|
|
|
|
Ensure these are set:
|
|
|
|
- `AUTH_SECRET`
|
|
- `DATABASE_URL`
|
|
- `SUPER_ADMIN_EMAIL`
|
|
- `SUPER_ADMIN_PASSWORD`
|
|
- relevant `SENTRY_*` variables if using Sentry
|
|
|
|
### Build Considerations
|
|
|
|
- app builds as standalone
|
|
- database migrations must be applied before runtime
|
|
- production secrets must not be exposed as `NEXT_PUBLIC_*`
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Auth fails in development
|
|
|
|
- verify `AUTH_SECRET`
|
|
- verify `DATABASE_URL`
|
|
- verify migrations are applied
|
|
- verify the super admin seed has run and seeded users have valid `password_hash`
|
|
|
|
### Theme not applying
|
|
|
|
- verify theme CSS import in `src/styles/theme.css`
|
|
- verify theme registration in `theme.config.ts`
|
|
|
|
### Navigation items not showing
|
|
|
|
- check `access` in `nav-config.ts`
|
|
- verify session has active organization, role, or permissions as needed
|
|
|
|
### Feature data looks stale
|
|
|
|
- verify mutation invalidates the feature query key factory
|
|
- verify filters are included in the query key
|
|
|
|
---
|
|
|
|
## External Documentation
|
|
|
|
- [Next.js App Router](https://nextjs.org/docs/app)
|
|
- [Auth.js](https://authjs.dev)
|
|
- [Drizzle ORM](https://orm.drizzle.team)
|
|
- [shadcn/ui](https://ui.shadcn.com/docs)
|
|
- [Tailwind CSS v4](https://tailwindcss.com/docs)
|
|
- [TanStack Query](https://tanstack.com/query)
|
|
- [TanStack Table](https://tanstack.com/table/latest)
|
|
- [TanStack Form](https://tanstack.com/form)
|
|
- [Sentry Next.js](https://docs.sentry.io/platforms/javascript/guides/nextjs/)
|
|
|
|
---
|
|
|
|
## Notes for AI Agents
|
|
|
|
1. Always use `cn()` for className merging.
|
|
2. Respect the feature-based structure and keep new work inside `src/features/`.
|
|
3. Server components are the default.
|
|
4. Avoid `any`; keep contracts explicit.
|
|
5. Use `PageContainer` for page headers instead of importing `Heading` directly in pages.
|
|
6. Use TanStack Form + Zod via the existing project wrappers.
|
|
7. Use icons only through `@/components/icons`.
|
|
8. For new app-owned features, prefer Route Handlers + Drizzle + React Query.
|
|
9. Never import from `@/constants/mock-api*` directly in components.
|
|
10. Use `@/auth` and `src/lib/auth/session.ts` for auth and organization checks.
|
|
11. Do not introduce new Clerk usage.
|
|
12. Treat legacy mock-backed modules as migration seams.
|
|
13. Follow the migrated `products` and `users` feature patterns when building new CRUD modules.
|
|
14. Do not re-enable self-service sign-up unless the product requirement changes explicitly.
|
|
15. For every CRUD mutation, explicitly invalidate React Query caches for list/detail/related data; never rely on passive staleness recovery.
|
|
16. Centralize query keys in each feature's `api/queries.ts`; do not scatter manual string query keys in components.
|
|
17. When deleting entities, remove stale detail queries with `removeQueries` in addition to invalidating lists.
|
|
18. If a component overrides `useMutation` callbacks on top of a shared mutation config, preserve or explicitly call the shared invalidation behavior before closing UI.
|
|
19. After successful create/update/delete, sheets, dialogs, and destructive modals must close only after cache invalidation has been triggered and the UI can refresh from fresh data.
|
|
20. Review `docs/standards/**`, relevant `docs/adr/**`, `docs/business/**`, and `docs/security/**` before implementing non-trivial changes.
|
|
21. Review related completed task notes in `docs/standards/task-catalog.md` and `docs/implementation/**` before implementing non-trivial changes.
|
|
22. Reuse foundations under `src/features/foundation/**` and `src/features/crm/**` before introducing new services, routes, permissions, exports, or datasets.
|
|
23. Do not create duplicate report/export/PDF/approval/security plumbing when a project foundation already exists.
|
|
24. CRM authorization must flow through resolved access helpers such as `resolveCrmMembershipAccess()`, `buildCrmSecurityContext()`, or report-context builders; do not authorize with raw role strings alone.
|
|
|
|
Before implementing any task, review:
|
|
- AGENTS.md
|
|
- docs/standards/*
|
|
- docs/standards/task-catalog.md
|
|
- related ADRs
|
|
- related completed task documents
|
|
|
|
Implementation without review is prohibited.
|