Quality Gates
Every module must pass ALL gates in order before proceeding to the next phase.
Gate 1: Spec Gate
When: Before coding starts Owner: Product Owner + Architect
| Check | Pass Criteria |
|---|---|
| Requirements documented | 10_REQUIREMENTS.md complete with FR/NFR/Edge cases |
| Data model reviewed | 20_DATA_MODEL.md reviewed by Architect |
| API contract agreed | 30_API_CONTRACT.md reviewed by FE + BE |
| Events defined | 40_EVENTS.md contracts agreed with consumer modules |
| RBAC defined | 50_RBAC.md permissions registered |
| Tasks imported | 60_TASKS.csv in project board, estimates refined |
| Conflicts logged | All spec/UI/backend conflicts in DECISION_LOG.md |
Gate 2: API Contract Gate
When: After schema + endpoints coded, before business logic Owner: Tech Lead
| Check | Pass Criteria |
|---|---|
| Schemas match spec | DB schemas match 20_DATA_MODEL.md |
| Endpoints registered | All endpoints from 30_API_CONTRACT.md registered in controllers |
| DTOs validated | Request/response DTOs with class-validator decorators |
| Swagger generated | @nestjs/swagger decorators on all endpoints |
| Guards applied | Correct guard chain on every endpoint |
| Error codes defined | All error codes from API contract implemented |
Gate 3: Data Gate
When: After data layer implementation Owner: Backend Dev + DBA
| Check | Pass Criteria |
|---|---|
| Indexes created | All indexes from 20_DATA_MODEL.md exist |
| Tenant isolation | Every query filters by tenantId |
| Soft delete | isDeleted filter applied by default |
| Audit fields | createdById, updatedById populated on mutations (NOT createdBy) |
| Migration tested | Migration script tested on staging data |
| Seed data | Default/system data seeded correctly |
Gate 3.5: POPULATION_CONTRACT_GATE
When: After API endpoints coded, before merge Owner: Tech Lead + API Governance Lead
Governance Ref:
RELATIONSHIP_POPULATION_RULES.md
| Check | Pass Criteria |
|---|---|
| Relation field naming | All FK fields use <name>Id / <name>Ids — no bare createdBy: ObjectId |
| Audit fields correct | createdById, updatedById (ObjectId) present on all mutable entities |
| Include whitelist defined | Per-endpoint include config with allowed relations |
| Projection map defined | Each allowed include has a Summary shape (e.g., UserSummary, CategorySummary) |
| Default response minimal | API response without ?include has NO populated relations |
| Depth limit enforced | ?include=a.b returns 400 INCLUDE_DEPTH_EXCEEDED |
| Unauthorized include blocked | ?include=forbidden_field returns 400 INCLUDE_NOT_ALLOWED |
| RBAC on population | Permission checked before populating sensitive relations |
| No N+1 queries | List endpoints use batch lookup for populations |
.lean() on all populated queries | Verified in service code |
| Error codes registered | INCLUDE_NOT_ALLOWED, INCLUDE_DEPTH_EXCEEDED, INCLUDE_FORBIDDEN_FIELD |
Required artifacts per module:
- Relation field list (in
20_DATA_MODEL.md→ §Relation Fields) - Allowed include list (in
30_API_CONTRACT.md→ §Include/Expand Policy) - Projection map (in
POPULATION_WHITELISTS.md) - Tests for depth limit + unauthorized include blocked (in
70_TESTPLAN.md)
Gate 3.6: AUDIT_STAMP_GATE
When: After entity schemas + CRUD services coded, before merge Owner: Tech Lead + API Governance Lead
Governance Ref:
AUDIT_STAMPING_STANDARD.md
| Check | Pass Criteria |
|---|---|
createdById present | All mutable entities have createdById: ObjectId |
updatedById present | All mutable entities have updatedById: ObjectId |
| Soft-delete fields | If soft-delete: isDeleted, deletedAt, deletedById all present |
| Timestamps enabled | { timestamps: true } on all @Schema() declarations |
| Service-layer stamping | createdById/updatedById set in service, NOT middleware/controller |
| DTO exclusion | Create/Update DTOs do NOT declare audit fields |
| Client override blocked | Test: sending createdById in POST body has no effect |
| Naming correct | No legacy createdBy: ObjectId — must be createdById |
Required artifacts per module:
- Audit fields listed in
20_DATA_MODEL.md→ §Audit Fields - Reserved fields policy in
30_API_CONTRACT.md - Tests for client override in
70_TESTPLAN.md
Gate 3.7: TIME_STANDARD_GATE
When: After API endpoints return datetime fields, before merge Owner: Tech Lead + API Governance Lead
Governance Ref:
TIME_DATE_STANDARD.md
| Check | Pass Criteria |
|---|---|
| Instant fields UTC | All Date fields stored and returned as UTC |
| API format | All instant fields output as YYYY-MM-DDTHH:mm:ss.sssZ |
| Date-only fields | Date-only fields stored as String in YYYY-MM-DD format |
| Input validation | Instant inputs validated with @IsISO8601() |
| Suffix naming | *At = server instant, *Date = business instant, *On = date-only |
| No local timezone | Server never converts to local timezone |
| Period validation | startDate < endDate validated where applicable |
Required artifacts per module:
- Date/time fields classified in
20_DATA_MODEL.md→ §Date/Time Fields - Canonical format stated in
30_API_CONTRACT.md - Timezone/date tests in
70_TESTPLAN.md
Gate 4: RBAC Gate
When: After permission enforcement implemented Owner: Security Lead / Tech Lead
| Check | Pass Criteria |
|---|---|
| Permissions enforced | @Permissions() decorators match 50_RBAC.md |
| Guard chain verified | JWT → Tenant → Permissions on all non-public routes |
| Cross-tenant tested | Cannot access another tenant's data |
| Role-based tested | Each role sees only permitted operations |
| Admin bypass | SystemAdmin bypasses correctly |
| Audit logged | Permission denials logged |
Gate 5: Test Gate
When: Before merge to main branch Owner: QA + Dev
| Check | Pass Criteria |
|---|---|
| Unit coverage | ≥ 80% line coverage on service layer |
| Integration tests | All integration test cases pass from 70_TESTPLAN.md |
| E2E tests | Critical path E2E tests pass |
| No regressions | Full CI suite green |
| Edge cases | All edge cases from 10_REQUIREMENTS.md have test coverage |
| Performance | API response < NFR targets (p95) |
Gate 6: Release Gate
When: Before deploy to production Owner: Tech Lead + DevOps + PM
| Check | Pass Criteria |
|---|---|
| All PRs merged | No open PRs for this module/phase |
| Swagger accurate | OpenAPI spec matches implementation |
| Runbook updated | 80_RUNBOOK.md has correct env vars, alerts |
| Status report | 90_STATUS_REPORT.md updated, no blockers |
| Rollback tested | Rollback procedure verified on staging |
| Sign-off | Dev + QA + TL signatures in 90_STATUS_REPORT.md |
| Handoff doc | HANDOFF_TEMPLATE.md filled if this is a module delivery |
Gate Enforcement
| Gate | Blocker? | Evidence Required |
|---|---|---|
| Gate 1 (Spec) | ✅ Hard | Signed-off design review |
| Gate 2 (API) | ✅ Hard | Swagger output reviewed |
| Gate 3 (Data) | ✅ Hard | Migration log + isolation test |
| Gate 3.5 (Population) | ✅ Hard | Include whitelist + depth test + projection map |
| Gate 3.6 (Audit Stamp) | ✅ Hard | Audit fields + DTO exclusion + client override test |
| Gate 3.7 (Time Standard) | ✅ Hard | Datetime format test + suffix review + UTC verification |
| Gate 4 (RBAC) | ✅ Hard | Security test report |
| Gate 5 (Test) | ✅ Hard | CI coverage report |
| Gate 6 (Release) | ✅ Hard | Deployment checklist signed |
Changelog
| Date | Change |
|---|---|
| 2026-02-23 | Initial — 6 gates |
| 2026-02-23 | Added Gate 3.5 POPULATION_CONTRACT_GATE; fixed audit fields to use createdById |
| 2026-02-23 | Added Gate 3.6 AUDIT_STAMP_GATE + Gate 3.7 TIME_STANDARD_GATE |