Skip to content

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

CheckPass Criteria
Requirements documented10_REQUIREMENTS.md complete with FR/NFR/Edge cases
Data model reviewed20_DATA_MODEL.md reviewed by Architect
API contract agreed30_API_CONTRACT.md reviewed by FE + BE
Events defined40_EVENTS.md contracts agreed with consumer modules
RBAC defined50_RBAC.md permissions registered
Tasks imported60_TASKS.csv in project board, estimates refined
Conflicts loggedAll spec/UI/backend conflicts in DECISION_LOG.md

Gate 2: API Contract Gate

When: After schema + endpoints coded, before business logic Owner: Tech Lead

CheckPass Criteria
Schemas match specDB schemas match 20_DATA_MODEL.md
Endpoints registeredAll endpoints from 30_API_CONTRACT.md registered in controllers
DTOs validatedRequest/response DTOs with class-validator decorators
Swagger generated@nestjs/swagger decorators on all endpoints
Guards appliedCorrect guard chain on every endpoint
Error codes definedAll error codes from API contract implemented

Gate 3: Data Gate

When: After data layer implementation Owner: Backend Dev + DBA

CheckPass Criteria
Indexes createdAll indexes from 20_DATA_MODEL.md exist
Tenant isolationEvery query filters by tenantId
Soft deleteisDeleted filter applied by default
Audit fieldscreatedById, updatedById populated on mutations (NOT createdBy)
Migration testedMigration script tested on staging data
Seed dataDefault/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

CheckPass Criteria
Relation field namingAll FK fields use <name>Id / <name>Ids — no bare createdBy: ObjectId
Audit fields correctcreatedById, updatedById (ObjectId) present on all mutable entities
Include whitelist definedPer-endpoint include config with allowed relations
Projection map definedEach allowed include has a Summary shape (e.g., UserSummary, CategorySummary)
Default response minimalAPI 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 populationPermission checked before populating sensitive relations
No N+1 queriesList endpoints use batch lookup for populations
.lean() on all populated queriesVerified in service code
Error codes registeredINCLUDE_NOT_ALLOWED, INCLUDE_DEPTH_EXCEEDED, INCLUDE_FORBIDDEN_FIELD

Required artifacts per module:

  1. Relation field list (in 20_DATA_MODEL.md → §Relation Fields)
  2. Allowed include list (in 30_API_CONTRACT.md → §Include/Expand Policy)
  3. Projection map (in POPULATION_WHITELISTS.md)
  4. 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

CheckPass Criteria
createdById presentAll mutable entities have createdById: ObjectId
updatedById presentAll mutable entities have updatedById: ObjectId
Soft-delete fieldsIf soft-delete: isDeleted, deletedAt, deletedById all present
Timestamps enabled{ timestamps: true } on all @Schema() declarations
Service-layer stampingcreatedById/updatedById set in service, NOT middleware/controller
DTO exclusionCreate/Update DTOs do NOT declare audit fields
Client override blockedTest: sending createdById in POST body has no effect
Naming correctNo legacy createdBy: ObjectId — must be createdById

Required artifacts per module:

  1. Audit fields listed in 20_DATA_MODEL.md → §Audit Fields
  2. Reserved fields policy in 30_API_CONTRACT.md
  3. 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

CheckPass Criteria
Instant fields UTCAll Date fields stored and returned as UTC
API formatAll instant fields output as YYYY-MM-DDTHH:mm:ss.sssZ
Date-only fieldsDate-only fields stored as String in YYYY-MM-DD format
Input validationInstant inputs validated with @IsISO8601()
Suffix naming*At = server instant, *Date = business instant, *On = date-only
No local timezoneServer never converts to local timezone
Period validationstartDate < endDate validated where applicable

Required artifacts per module:

  1. Date/time fields classified in 20_DATA_MODEL.md → §Date/Time Fields
  2. Canonical format stated in 30_API_CONTRACT.md
  3. Timezone/date tests in 70_TESTPLAN.md

Gate 4: RBAC Gate

When: After permission enforcement implemented Owner: Security Lead / Tech Lead

CheckPass Criteria
Permissions enforced@Permissions() decorators match 50_RBAC.md
Guard chain verifiedJWT → Tenant → Permissions on all non-public routes
Cross-tenant testedCannot access another tenant's data
Role-based testedEach role sees only permitted operations
Admin bypassSystemAdmin bypasses correctly
Audit loggedPermission denials logged

Gate 5: Test Gate

When: Before merge to main branch Owner: QA + Dev

CheckPass Criteria
Unit coverage≥ 80% line coverage on service layer
Integration testsAll integration test cases pass from 70_TESTPLAN.md
E2E testsCritical path E2E tests pass
No regressionsFull CI suite green
Edge casesAll edge cases from 10_REQUIREMENTS.md have test coverage
PerformanceAPI response < NFR targets (p95)

Gate 6: Release Gate

When: Before deploy to production Owner: Tech Lead + DevOps + PM

CheckPass Criteria
All PRs mergedNo open PRs for this module/phase
Swagger accurateOpenAPI spec matches implementation
Runbook updated80_RUNBOOK.md has correct env vars, alerts
Status report90_STATUS_REPORT.md updated, no blockers
Rollback testedRollback procedure verified on staging
Sign-offDev + QA + TL signatures in 90_STATUS_REPORT.md
Handoff docHANDOFF_TEMPLATE.md filled if this is a module delivery

Gate Enforcement

GateBlocker?Evidence Required
Gate 1 (Spec)✅ HardSigned-off design review
Gate 2 (API)✅ HardSwagger output reviewed
Gate 3 (Data)✅ HardMigration log + isolation test
Gate 3.5 (Population)✅ HardInclude whitelist + depth test + projection map
Gate 3.6 (Audit Stamp)✅ HardAudit fields + DTO exclusion + client override test
Gate 3.7 (Time Standard)✅ HardDatetime format test + suffix review + UTC verification
Gate 4 (RBAC)✅ HardSecurity test report
Gate 5 (Test)✅ HardCI coverage report
Gate 6 (Release)✅ HardDeployment checklist signed

Changelog

DateChange
2026-02-23Initial — 6 gates
2026-02-23Added Gate 3.5 POPULATION_CONTRACT_GATE; fixed audit fields to use createdById
2026-02-23Added Gate 3.6 AUDIT_STAMP_GATE + Gate 3.7 TIME_STANDARD_GATE

FitZalo Platform Documentation