# Phase 4 — Extraction gates & candidates **Status:** Planning / measurement only (ADR-003) **Date:** 2026-08-12 **Prerequisite:** Phase 3 exit evidence (soak, pen-test, canary, key rotation) should be underway before any extraction design review. ## Rule Extract a bounded context into its **own deployable** only if measurement shows the monolith cannot meet SLOs or blast-radius requirements **and** ownership is staffed. Otherwise scale the existing `api` + `api-worker` topology. ## Candidates (from diligence / readiness plan) | Candidate | Today | Extract when… | Prefer first | |-----------|--------|---------------|--------------| | **Notification worker** | Already a separate **process** (`apps/api` worker / Compose `api-worker`) sharing the API package | Worker CPU/memory or release cadence is blocked by API deploys; or need multi-language worker fleet with independent scaling | Scale `api-worker` replicas; keep shared package | | **Payments / webhooks** | Modules inside API (`payments`, `billing`, `subscriptions`, webhook routes) | Webhook lag or payment CPU dominates API p95; or PCI/provider isolation requires a smaller trust boundary | Dedicated webhook ingress + queue inside monolith; idempotent consumers | | **Media processing** | Upload + storage drivers in API; local/S3 | Image/PDF processing blocks request threads or storage I/O saturates API | Async job on `api-worker`; object storage (MinIO/S3) already preferred | ## Hard gates (all required per candidate) Copy to an evidence note before any extract ADR: | # | Gate | Evidence | |---|------|----------| | G1 | Phase 3 soak baseline exists | Dated `test:soak` / k6 + `/metrics` snapshot | | G2 | Bottleneck attributed | Profile or metrics: p95, queue lag, CPU by route/job — not anecdote | | G3 | Blast radius / compliance need | Written threat or compliance reason (e.g. webhook storm, media malware scan) | | G4 | Ownership | Named eng + on-call for the new service | | G5 | Contract | OpenAPI or event schema + consumer contract tests | | G6 | Dual-run | Shadow or dual-publish ≥ 1 release cycle with zero silent divergence | | G7 | Rollback | Documented cutback to monolith path in < 30 minutes | If any gate fails → **do not extract**; file an in-monolith improvement instead. ## In-monolith improvements (do these before/instead of extract) 1. Keep payment/webhook handlers thin; push side effects through outbox/jobs. 2. Run N `api-worker` replicas with DB leases (already Phase 1). 3. Move heavy media work to worker jobs + S3; never resize on the request path. 4. Publish domain events internally (same DB outbox) so a future service can subscribe without a big-bang rewrite. ## Explicit non-goals for Phase 4 - Rewriting the monorepo into many services - Separate databases per module “for purity” - Per-tenant container orchestration (still ADR-001)