Act III · What keeps it safe
AI Factory · Quality gates
Gates are commands, not opinions
preflight.sh changes in the same PR, so local and CI never drift.Before the push
Plan check
Every mandatory section and task group is present, and the Issue exists and is open on GitHub.
Preflight (pre-push hook)
A local mirror of the CI gates. mvn verify alone does not predict CI: Spotless is deliberately unbound from the Maven lifecycle.
Full pipeline (pre-PR)
Brings the Docker stack up, runs the security case catalog and preflight --full, lints markdown, and writes an HTML dashboard.
Light CI is not enough
PR Validation, Frontend CI and Process Checks finish first and can report "all N checks success" while the backend Integration suite and Playwright are still queued. A merge needs the heavy set to be terminal success: Unit, Integration, Coverage Gate, Bruno API and Playwright UI. check-heavy-ci.sh <pr> must exit 0. The protect-main ruleset also requires five named checks: CI, Frontend CI, Playwright E2E, Code Lint and PR Validation.
Path-scoped CI
On pull requests, docs, OpenSpec and agent-only paths skip the Java and Playwright leaf jobs. Suite aggregators keep the required check names green by treating an intentional skipped as success. Pushes to main, schedules and manual dispatch always run the full suite, and a test guards those invariants.
Coverage and tests
| Level | Where | Gate |
|---|---|---|
| Unit + integration (backend) | backend-api/src/test/java/…/unit, …/integration | JaCoCo ratchet floor in mvn verify (80% line / 65% branch) |
| Component (frontend) | frontend/src/**/*.test.tsx (Vitest) | raise-only floors in vitest.config.ts |
| API contract | Bruno suite + OpenAPI | CU-API matrix + oasdiff breaking diff |
| E2E | testing/e2e/tests/TS-nnnn-*.spec.ts | ≥1 suite per critical Use Case; inventory drift guard |
| Database | Flyway migrations on PostgreSQL | Database V&V workflow |
Security by design
One security case catalog runs locally and in CI. Its families are threat-model, secrets, sast, sca, dast, policy. CI adds CodeQL (advanced setup only) and a blocking weekly OWASP ZAP baseline with a reviewed allowlist. A diff that touches authentication, authorization, personal data, secrets, dependencies or a public endpoint updates the threat model and the catalog in the same change. SonarQube runs in the local quality stack under infra/.
Every workflow and its job
| Workflow | When | What it proves | Tier |
|---|---|---|---|
| PR Validation pr-validation.yml | PR | Title, branch naming, SDLC plan validation, Spotless/Checkstyle lint, quick build | light |
| SDLC Process sdlc-process.yml | PR · push · daily | Process Checks on PRs; Main Health on main (archive hygiene, plans conform, harness self-tests) | light |
| Frontend CI frontend-ci.yml | PR · push | TypeScript, ESLint, Vitest with raise-only coverage floors, Next.js build | light |
| OpenAPI Contract openapi-contract.yml | PR | Committed OpenAPI matches the code; oasdiff flags breaking changes | light |
| CI - Build, Test & Security ci.yml | PR · push | Build, unit, integration, coverage gate (mvn verify), security scan, Docker image, reports | heavy |
| Playwright E2E — Full Suite playwright-e2e.yml | PR · push · schedule | Bruno API suite and Playwright UI in 3 shards, business coverage report | heavy |
| CodeQL codeql.yml | PR · push · schedule | Advanced-setup static analysis (never alongside default setup) | heavy |
| Database V&V database-vv.yml | PR · push | Flyway migrations verified against PostgreSQL | heavy |
| CD - Build & Publish Docker cd.yml | after CI on main · tags | Release identity, sign and publish images to GHCR, SBOM assets on releases | after |
| Release Please release-please.yml | push to main | Semver release PR: poms, frontend package.json, release/product-release.json and CHANGELOG from merged commits | after |
| Deploy GitHub Page deploy-github-page.yml | after CI on main | Builds this site with fresh coverage and E2E reports | after |
| DAST — OWASP ZAP Baseline dast-zap.yml | weekly | Blocking ZAP baseline with a reviewed allowlist | scheduled |
| Performance - k6 Load Test performance-test.yml | weekly | k6 load test against a live API | scheduled |
| Backup → Restore → Smoke backup-restore-smoke.yml | weekly | Restores a backup and smoke-tests it | scheduled |
| Test Coverage Report test-coverage-report.yml | push · schedule | Coverage trend for the site and reports | scheduled |
| Cleanup Actions artifacts and logs leanup-actions.yml | schedule | Keeps artifact storage under quota | scheduled |
Release and deploy
One product version
Backend, frontend and the Flyway schema ship under one SemVer tag. The version shows on /actuator/info, in OpenAPI and in the UI shell, and a coherence check runs in preflight, CI and CD.
Release Please
Merged Conventional Commits drive the release PR and the CHANGELOG. The Unreleased section is curated per release.