diff --git a/docs/guides/operator-checklist.md b/docs/guides/operator-checklist.md index 0e72e19..6b5ed19 100644 --- a/docs/guides/operator-checklist.md +++ b/docs/guides/operator-checklist.md @@ -120,6 +120,101 @@ to extend — and the decision becomes an ADR-022 amendment in a new ADR. --- +## Analytics backend (ADR-024) + +**13. Choose and wire an analytics vendor — or skip.** `@repo/core-analytics` ships +`IAnalytics` as a vendor-neutral contract with no default backend. The analytics +backend is **consumer-chosen**: the template deliberately ships no vendor because +the choice requires ADR-022's library evaluation gate (EU residency, license, +Socket.dev) and your product's consent model. + +If you want product analytics: + +- **Evaluate the vendor first.** Run + `/evaluate-library --tier core --target packages/core-analytics`. The + resulting trace at `docs/library-decisions/-.md` is the required + evidence before adding the package to your lockfile. +- **Implement `IAnalytics`.** Write a wrapper around the vendor SDK that satisfies + the four-method interface (`track`, `identify`, `pageView`, `flush`). +- **Wire at DI bind time.** Pass the implementation into `ctx.analytics` in + `bind-production.ts`. Feature binders pick it up and compose it into the + `withAnalytics(...)` wrapper chain automatically. +- **Wire `flush()` into graceful shutdown.** Hook `analytics.flush()` into your + app's `SIGTERM` / `beforeExit` handler to drain the in-memory batch before the + process exits — event loss on container/serverless shutdown is the most common + analytics bug. +- **Client side (optional).** Wrap your app root in + `` from `@repo/core-analytics/react`; expose + `IAnalytics` to components via `useAnalytics()`. + +If you don't want analytics, do nothing — the template boots with `NoopAnalytics` +by default and no wiring is required. + +--- + +## Compliance directory (ADR-025) + +**14. Generate and commit the `compliance/` YAML files.** Three audit-evidence +files live at the repo root under `compliance/`, generated from Payload schema +declarations and library traces: + +```bash +pnpm compliance:emit-all +# produces: +# compliance/data-map.yml (from Payload field custom.pii tags) +# compliance/retention-policy.yml (from Payload collection custom.retention) +# compliance/sub-processors.yml (from docs/library-decisions/ traces flagged +# is-sub-processor: true) +git add compliance/ +git commit -m "compliance: initial audit-evidence YAML files" +``` + +Run once after your Payload schema stabilises. Re-run and commit whenever schema +changes. The CI drift gate (`pnpm compliance:emit-all --check`) fails if generated +output diverges from source. + +**15. Verify the compliance drift gate in pre-commit and CI.** + +- **Pre-commit:** `.husky/pre-commit` should include the + `pnpm compliance:emit-all --check` step. Verify after `pnpm install`. +- **CI:** `ci.yml`'s `validate` job runs the same check on every PR. Add it to + branch-protection required checks (step **6** above) so drift can't land on + `main`. + +**16. Schedule the retention purge job.** `core-shared/jobs/retention-purge.job.ts` +reads `custom.retention` from each Payload collection at boot and enqueues +per-collection purge runs on the declared `purgeSchedule`. To activate: + +1. Set `custom.retention: { activeRetention, postDeletion, purgeSchedule, +hardDeleteAfter }` on each Payload collection you want auto-purged. See + `docs/compliance/retention-policy.example.yml` for the schema. +2. Confirm the job runner is live in production — the purge job enqueues via + `IJobQueue`, which requires `@repo/core-events` or Payload's native jobs queue. +3. Verify `audit_events` gains `{ action: "DELETE", reason: "retention-policy" }` + entries after the first purge cycle. + +**17. Hand-author `compliance/sub-processors.manual.yml` for non-npm vendors.** +The sub-processors generator only surfaces vendors that have an npm package in +`docs/library-decisions/`. Any vendor you call via a pure REST API — no SDK, no +library trace — needs a manual entry: + +```yaml +# compliance/sub-processors.manual.yml +- name: SendGrid + is-sub-processor: true + processes-pii: true + data-sent: [email-address, display-name] + region: US + dpa-signed: 2026-01-15 + sccs-required: true + contact: privacy@sendgrid.com +``` + +Commit this file alongside `compliance/sub-processors.yml`. Both are treated as +audit evidence; unlike the generated files, this one is always hand-maintained. + +--- + ## Read once the docs land - `docs/guides/adding-a-library.md` (library-evaluation epic story 05) @@ -145,6 +240,8 @@ to extend — and the decision becomes an ADR-022 amendment in a new ADR. - ADR-022 — Library evaluation policy - ADR-023 — CI security + supply-chain enforcement stack +- ADR-024 — Product analytics channel +- ADR-025 — EU compliance baseline (DPA/GDPR scope) - `docs/guides/runbook.md` — first-time template setup (Postgres, dev servers, sandcastle auth) - `docs/guides/adding-a-library.md` — adding a runtime dep