commit
This commit is contained in:
160
docs/standards/architecture-rules.md
Normal file
160
docs/standards/architecture-rules.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Architecture Rules
|
||||
|
||||
These rules describe the approved implementation patterns for ALLA OS.
|
||||
|
||||
New work should extend these patterns instead of inventing parallel architecture.
|
||||
|
||||
## Frontend Architecture
|
||||
|
||||
- Use Next.js App Router.
|
||||
- Prefer server components by default.
|
||||
- Use client components only for interactivity, browser APIs, or client-side state/query hooks.
|
||||
- Use `PageContainer` for dashboard page headers and top-level content framing.
|
||||
- Keep business-facing CRM UI aligned with `docs/business/crm-terminology.md` and `src/features/crm/shared/terminology.ts`.
|
||||
|
||||
### Data Loading Pattern
|
||||
|
||||
- For data-heavy dashboard/app pages, prefer server prefetch plus `HydrationBoundary`.
|
||||
- Client tables and detail panes should consume prefetched data with `useSuspenseQuery()`.
|
||||
- Define query options and query keys in `src/features/<feature>/api/queries.ts`.
|
||||
- Keep filters in URL state with `nuqs` when the page supports shareable filtering.
|
||||
|
||||
Reference examples:
|
||||
|
||||
- `src/features/users/components/user-listing.tsx`
|
||||
- `src/features/crm/customers/components/customer-listing.tsx`
|
||||
- `src/app/dashboard/crm/settings/user-role-assignments/page.tsx`
|
||||
|
||||
### UI Composition Rules
|
||||
|
||||
- Reuse shadcn/ui primitives from `src/components/ui/**`.
|
||||
- Reuse table shell components from `src/components/ui/table/**`.
|
||||
- Reuse `useDataTable` for table state orchestration.
|
||||
- Reuse TanStack Form wrappers from `@/components/ui/tanstack-form` and field components from `@/components/forms/fields`.
|
||||
- Do not create a parallel CRM design system or terminology layer.
|
||||
|
||||
## Backend Architecture
|
||||
|
||||
- Use Route Handlers under `src/app/api/**` as the HTTP boundary.
|
||||
- Keep route handlers thin: auth, validation, service call, response mapping, and audit.
|
||||
- Put business logic in feature or foundation service layers under `src/features/**`.
|
||||
- Use Drizzle ORM for database access.
|
||||
- Keep direct database access out of client components.
|
||||
|
||||
### Route Structure Pattern
|
||||
|
||||
Approved structure:
|
||||
|
||||
1. `requireOrganizationAccess()` or another shared auth helper
|
||||
2. request parsing and schema validation
|
||||
3. build resolved access/security context when the feature is scope-sensitive
|
||||
4. call feature/foundation service
|
||||
5. emit audit/security events through shared audit services
|
||||
6. return typed JSON/stream response
|
||||
|
||||
Reference examples:
|
||||
|
||||
- `src/app/api/crm/quotations/route.ts`
|
||||
- `src/app/api/crm/approvals/route.ts`
|
||||
- `src/app/api/crm/reports/pipeline/route.ts`
|
||||
- `src/app/api/crm/reports/export/route.ts`
|
||||
|
||||
## Module Structure
|
||||
|
||||
Preferred feature layout:
|
||||
|
||||
```text
|
||||
src/features/<feature>/
|
||||
api/
|
||||
types.ts
|
||||
service.ts
|
||||
queries.ts
|
||||
mutations.ts
|
||||
components/
|
||||
schemas/
|
||||
server/
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- components import contracts from `api/types.ts`
|
||||
- UI calls query options from `api/queries.ts`
|
||||
- UI mutations reuse shared mutation configs from `api/mutations.ts`
|
||||
- services in `api/service.ts` call route handlers through `src/lib/api-client.ts`
|
||||
- server business logic stays under feature/foundation server services
|
||||
|
||||
## Service Layer Pattern
|
||||
|
||||
- Services own business rules, persistence orchestration, and reusable data shaping.
|
||||
- Services may call other services when extending an existing foundation.
|
||||
- Services should not depend on UI concerns.
|
||||
- Report services must use dataset/builders/filter layers instead of embedding ad hoc SQL in routes.
|
||||
- PDF flows must use the PDF and artifact foundations instead of custom rendering paths.
|
||||
|
||||
Reference services:
|
||||
|
||||
- `src/features/crm/reports/server/service.ts`
|
||||
- `src/features/foundation/approval/server/service.ts`
|
||||
- `src/features/foundation/pdf-generator/server/service.ts`
|
||||
- `src/features/foundation/storage/service.ts`
|
||||
|
||||
## Query Pattern
|
||||
|
||||
- Define centralized query key factories in each feature's `api/queries.ts`.
|
||||
- Keys should group into `all`, `lists()`, `list(filters)`, `details()`, `detail(id)`, and child-resource keys where applicable.
|
||||
- Server pages prefetch query options and dehydrate.
|
||||
- Clients read the same keys with `useSuspenseQuery()`.
|
||||
|
||||
Reference examples:
|
||||
|
||||
- `src/features/products/api/queries.ts`
|
||||
- `src/features/users/api/queries.ts`
|
||||
- `src/features/crm/reports/api/queries.ts`
|
||||
|
||||
## Mutation Pattern
|
||||
|
||||
- Centralize mutation configs in `api/mutations.ts`.
|
||||
- Shared mutation configs must retain cache invalidation.
|
||||
- After create: invalidate list-level keys.
|
||||
- After update: invalidate list and detail keys.
|
||||
- After delete: invalidate lists and remove stale detail queries.
|
||||
- Refresh related tabs, counts, previews, and approval panels when they depend on the changed entity.
|
||||
|
||||
## Audit Pattern
|
||||
|
||||
- Use `auditCreate()`, `auditUpdate()`, `auditDelete()`, or `auditAction()` from `src/features/foundation/audit-log/service.ts`.
|
||||
- Reuse existing entity types and action naming where possible.
|
||||
- Security-sensitive denials use `crm_security_access` through `auditCrmSecurityEvent()`.
|
||||
- Report view/export events use `crm_report`.
|
||||
|
||||
Reference examples:
|
||||
|
||||
- `src/features/foundation/audit-log/service.ts`
|
||||
- `src/features/crm/security/server/service.ts`
|
||||
- `src/features/crm/reports/server/exports/service.ts`
|
||||
|
||||
## Security Pattern
|
||||
|
||||
- Organization access starts with `requireOrganizationAccess()`.
|
||||
- CRM authorization must use resolved access, not raw role strings.
|
||||
- Use `resolveCrmMembershipAccess()` for effective permission/scope unions.
|
||||
- Use `buildCrmSecurityContext()` for scope-aware CRM services.
|
||||
- Use `resolveCrmAccess()` / report-context builders for report routes.
|
||||
- Scope checks must enforce branch, product, ownership, and pricing visibility server-side.
|
||||
|
||||
Reference docs:
|
||||
|
||||
- `docs/security/crm-authorization-boundaries.md`
|
||||
- `docs/security/crm-access-enforcement-inventory.md`
|
||||
- `docs/security/team-scope-limitations.md`
|
||||
|
||||
## Explicitly Forbidden
|
||||
|
||||
- business logic in route handlers
|
||||
- client-side only authorization
|
||||
- direct role-string CRM authorization
|
||||
- direct DB access from client code
|
||||
- duplicate export/report/PDF/approval/security foundations
|
||||
- new Clerk integration
|
||||
- new SWR or Redux data architecture for app-owned features
|
||||
- new React Hook Form usage in this repo
|
||||
Reference in New Issue
Block a user