Imported from yassshhhh22/CRM (
AGENTS.md). Install upstream withnpx skills add yassshhhh22/CRM. Copyright stays with the author.
AGENTS.md
1. Project Overview
This repository implements a Milestone Escrow and Settlement Tracker.
The application manages milestone-based agreements between clients and service providers. It uses simulated funds and does not move real money.
The system must prove that:
- milestone terms are versioned,
- both parties approve the same milestone version,
- no party can release funds alone,
- unresolved disputes block release,
- invalid fund-state transitions are rejected,
- ledger balances remain correct,
- every state change has an audit record,
- duplicate requests do not duplicate financial effects.
Before changing business logic, read:
SRS.mdARCHITECTURE.mddocs/TRANSITION_TABLE.mddocs/TEST_STRATEGY.md
2. Repository Structure
The repository contains exactly two npm workspaces:
client/
server/
Do not create additional workspaces or top-level code directories such as:
packages/
shared/
common/
libs/
ui/
core/
The root repository may contain:
docs/
scripts/
.github/
These are not npm workspaces.
3. Technology Stack
Client
- React
- TypeScript
- Existing dashboard and landing-page template
- Existing component and styling system
- React Testing Library
- Vitest
Server
- Node.js
- Express
- TypeScript
- MVC with service and repository layers
- Zod
- OpenAPI 3.1
- Swagger UI
- SQLite
- Drizzle ORM
better-sqlite3- Vitest
- Supertest
Repository tooling
- npm workspaces
- Turborepo
- ESLint
- Prettier
- GitHub Actions
Do not introduce:
- Playwright
- Selenium
- Cypress
- another ORM
- another HTTP framework
- another frontend design system
- another package manager
Do not replace npm with pnpm, Yarn or Bun.
4. Architecture Rules
The server follows MVC with additional service, repository, validator and presenter layers.
Route
↓
Middleware
↓
Validator
↓
Controller
↓
Service
↓
Repository
↓
Database
Responses flow back through presenters:
Database result
↓
Service result
↓
Presenter
↓
Controller response
Models
Models define persistent data using Drizzle.
Models may contain:
- table definitions,
- columns,
- foreign keys,
- indexes,
- unique constraints,
- check constraints,
- inferred database types.
Models must not contain:
- Express request handling,
- controller logic,
- transaction orchestration,
- UI formatting,
- HTTP status codes.
Repositories
Repositories perform database access.
Repositories may:
- read records,
- insert records,
- update records through controlled methods,
- execute queries,
- participate in transactions.
Repositories must not decide whether a business action is legally allowed.
For example, a repository may answer:
Does an unresolved dispute exist?
It must not decide:
Should the milestone be released?
Services
Services contain:
- business rules,
- financial policies,
- workflow coordination,
- transaction boundaries,
- idempotency behaviour,
- audit coordination,
- ledger coordination.
All important settlement decisions belong in services or service policy modules.
Services must not depend on:
- React,
- client files,
- Swagger UI,
- Express response objects.
Controllers
Controllers translate HTTP requests into service calls.
Controllers may:
- read validated parameters,
- read authenticated actor information,
- call a service,
- call a presenter,
- select an HTTP success status.
Controllers must not:
- query the database directly,
- implement fund-transition rules,
- calculate ledger balances,
- approve releases,
- perform transaction management,
- trust actor roles from request bodies.
Controllers should remain small.
Presenters
Presenters define API response shapes.
Presenters may:
- remove internal database fields,
- rename response properties,
- format timestamps,
- represent money in a client-friendly structure,
- present stable error responses.
Presenters must not:
- change business state,
- perform database operations,
- decide whether an action is allowed.
Routes
Routes connect:
- paths,
- middleware,
- validators,
- controllers.
Routes must not contain business logic.
Validators
Validators contain Zod schemas for:
- path parameters,
- query parameters,
- headers,
- request bodies,
- API responses.
The same schemas should be registered for OpenAPI generation where applicable.
5. Financial Invariants
The following rules are mandatory.
They must not be weakened, bypassed or implemented only in the client.
INV-001: Legal fund-state transitions
The core fund states are:
UNFUNDED
HELD
RELEASED
REFUNDED
The only valid forward transitions are:
UNFUNDED → HELD
HELD → RELEASED
HELD → REFUNDED
The following are invalid:
UNFUNDED → RELEASED
UNFUNDED → REFUNDED
RELEASED → HELD
RELEASED → REFUNDED
REFUNDED → HELD
REFUNDED → RELEASED
INV-002: Dual-party settlement consent
A release requires:
current client approval of the latest submission
AND
latest valid service-provider submission for the active version
The provider submission is consent evidence; no separate provider settlement-approval row is required or permitted for new commands.
INV-003: Current-version approval
The client approval and provider submission must reference the active milestone version and the approval must reference the latest submission.
Approval of an older milestone version remains visible historically but cannot authorise release.
INV-004: Agreement fingerprint equality
The following fingerprints must match:
current milestone version fingerprint
client approval fingerprint
service-provider term-acceptance fingerprint
INV-005: Dispute blocking
A milestone cannot be released while a dispute is:
OPEN
UNDER_REVIEW
INV-006: Ledger reconciliation
For each milestone:
fundedAmount
- heldAmount
- releasedAmount
- refundedAmount
= 0
The residual must remain zero after every accepted financial operation.
INV-007: Integer money
All money must be stored as integer paise.
Example:
₹1,250.50 = 125050 paise
Do not use floating-point values for persisted money.
INV-008: Atomic settlement
A financial command must commit the following together:
- fund-state update,
- ledger movement,
- audit event,
- idempotency result.
If any operation fails, all related changes must roll back.
INV-009: Idempotency
Repeated execution of the same financial command must produce one financial effect.
Reusing the same idempotency key with different command input must be rejected.
INV-010: Append-only audit history
Audit events must not be updated or deleted through application repositories or APIs.
Corrections must create new events.
INV-011: Server authority
The server must not trust these values from the client:
- actor identity,
- actor role,
- milestone amount,
- current fund state,
- current milestone version,
- timestamps,
- ledger balances,
- approval validity.
INV-012: Versioned scope
Changing any material milestone term must create a new milestone version.
Material terms include:
- amount,
- deliverable definition,
- acceptance criteria,
- deadline,
- settlement conditions.
6. Request and Command Rules
Financial state must change through named command endpoints.
Preferred endpoints:
POST /api/v1/milestones/:milestoneId/commands/fund
POST /api/v1/milestones/:milestoneId/commands/approve
POST /api/v1/milestones/:milestoneId/commands/release
POST /api/v1/milestones/:milestoneId/commands/refund
Do not create endpoints such as:
PATCH /api/v1/milestones/:milestoneId/status
PATCH /api/v1/milestones/:milestoneId/funds-state
Users request actions. They do not directly select financial states.
7. OpenAPI and Swagger Rules
The server is the API contract source of truth.
The server must generate:
server/generated/openapi.json
The application must expose:
GET /openapi.json
GET /api-docs
/openapi.json returns the OpenAPI document.
/api-docs serves Swagger UI.
Every public endpoint must define:
operationId,- summary,
- description,
- tags,
- authentication requirements,
- path parameters,
- query parameters,
- required headers,
- request body,
- success response,
- validation errors,
- business-rule errors,
- authorisation errors.
Financial endpoints must document the Idempotency-Key header.
The client API types are generated from:
server/generated/openapi.json
Generated types are stored under:
client/src/api/generated/
Do not manually edit generated API types.
When an API contract changes:
- update the server Zod schemas,
- update OpenAPI registration,
- regenerate
openapi.json, - regenerate client API types,
- run type checking,
- update affected client API functions.
Do not manually duplicate server request and response interfaces in the client.
8. Client Template Rules
The client contains an existing dashboard and landing-page template.
Preserve:
- dashboard layout,
- landing-page structure,
- navigation,
- grid components,
- cards,
- buttons,
- inputs,
- tables,
- modals,
- tabs,
- charts,
- responsive behaviour.
Do not create replacement components when the template already provides an equivalent component.
Do not introduce a second design system.
Change branding through:
- theme variables,
- design tokens,
- typography tokens,
- chart tokens,
- semantic status tokens.
Do not hardcode product colours repeatedly in feature components.
Client business-rule boundary
The client may:
- hide unavailable actions for usability,
- display the current server state,
- show server rejection messages,
- display approval and dispute status.
The client must not be the authority for:
- release eligibility,
- refund eligibility,
- fund-state transitions,
- approval validity,
- dispute blocking,
- ledger reconciliation.
Do not use optimistic updates for:
- funding,
- release,
- refund,
- dispute creation,
- dispute resolution.
After these commands, refetch authoritative server state.
9. Error Handling Rules
All application errors must have stable machine-readable codes.
Example:
{
"error": {
"code": "RELEASE_BLOCKED_BY_DISPUTE",
"message": "The milestone cannot be released while a dispute is unresolved.",
"requestId": "req_123",
"details": {
"milestoneId": "mil_123"
}
}
}
Do not expose:
- database stack traces,
- SQL statements,
- internal filesystem paths,
- secrets,
- raw exceptions.
Controllers should pass errors to central error middleware.
Do not duplicate error formatting in individual controllers.
10. Database Rules
SQLite must be configured with:
PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL;
PRAGMA synchronous = FULL;
PRAGMA busy_timeout = 5000;
Critical financial transactions must:
- remain short,
- avoid network calls,
- avoid file processing,
- avoid email sending,
- avoid unrelated queries.
Use:
- foreign keys,
- unique constraints,
- check constraints,
- indexes,
- optimistic
lockVersion, - bounded retry for database-busy errors.
Do not use PostgreSQL-specific locking syntax in SQLite.
Do not directly insert final financial states in seeds.
Seed data must use application services or commands so the ledger and audit trail remain correct.
11. Audit Rules
Every accepted state-changing action must produce an audit event.
Audit events should include:
- actor ID,
- actor role,
- action,
- timestamp,
- project ID,
- milestone ID,
- milestone-version ID,
- before state,
- after state,
- command ID,
- request ID,
- relevant metadata.
Audit writes must occur in the same transaction as the state change.
A financial state change without an audit event is a failed transaction and must roll back.
12. Testing Rules
Use:
- Vitest for unit tests,
- Vitest with real temporary SQLite files for database tests,
- Supertest for Express API integration tests,
- React Testing Library for client component tests.
Do not add browser E2E frameworks.
Required test suites
unit
integration
transitions
ledger
concurrency
audit coverage
idempotency
deterministic replay
Transition fixture
The committed transition fixture must contain at least 200 cases.
Expected results must be explicitly stored.
Do not calculate expected outcomes by calling production policy code.
Ledger fixture
The committed ledger fixture must contain at least 300 operations.
After every accepted financial operation:
funded - held - released - refunded = 0
After every rejected operation:
- state remains unchanged,
- ledger remains unchanged,
- no settlement audit event is created.
Test integrity
Do not:
- weaken tests to make code pass,
- delete failing cases without explanation,
- modify committed KPI fixtures to match implementation bugs,
- mock the core transaction boundary in integration tests,
- use an in-memory fake repository for concurrency proof.
13. Codex Working Rules
Before changing files:
- inspect relevant files,
- identify applicable instructions,
- describe current behaviour,
- propose files to change,
- identify tests to add or update,
- identify OpenAPI impact.
Work on one phase or one narrow feature at a time.
Do not perform unrelated refactoring.
After implementation, report:
- files changed,
- tests added,
- commands run,
- OpenAPI changes,
- remaining risks.
For complex work, use separate Codex sessions for:
- planning,
- implementation,
- review.
Do not allow the implementation session to be the only reviewer.
14. Required Verification Commands
Before declaring a normal task complete, run:
npm run typecheck
npm run lint
npm test
For server API changes, also run:
npm run test:integration
npm run openapi:generate
npm run openapi:check
npm run client:types
For financial behaviour changes, also run:
npm run test:transitions
npm run test:ledger
npm run test:concurrency
npm run kpi:run
Do not report a phase as complete while required checks are failing.
15. Git Rules
Use small, descriptive commits.
Examples:
feat(server): add atomic milestone release service
feat(server): enforce dispute release blocking
feat(client): add milestone control centre
docs: register settlement endpoints in openapi
test(server): commit transition acceptance fixture
Avoid combining:
- database migrations,
- theme redesign,
- API changes,
- unrelated refactoring
inside one commit.
The committed transition and ledger fixtures are acceptance criteria and should not be silently rewritten.