Files
agentic-dev/docs/guides/operator-checklist.md
Danijel Martinek b23b1d0b89 docs(compliance): refresh operator-checklist with ADR-024 and ADR-025 actions
ADR-024: analytics backend is consumer-chosen; operator must decide
whether to wire a vendor and, if so, run /evaluate-library first
(ADR-022 gate applies). Documents IAnalytics wiring, flush() shutdown
hook, and optional React provider.

ADR-025: compliance directory setup — generate and commit compliance/
YAML files as audit evidence; verify drift gate in pre-commit + CI;
schedule retention purge job per custom.retention; hand-author
compliance/sub-processors.manual.yml for non-npm vendors.

All existing ADR-022/023 content preserved unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:06:42 +00:00

249 lines
10 KiB
Markdown

# Operator checklist
The decisions and code that make this template's security + supply-chain
stack work are landed in code (ADR-022, ADR-023, the library-evaluation
epic, the CI-security epic). This doc covers the **human-side actions**
required to put it into operation in a real GitHub-hosted repo. Read top
to bottom on first adoption; revisit the "Ongoing" section weekly.
The biggest leverage move is **#1 (push to a remote)** — until that
happens, the entire `.github/workflows/` surface is inert. Everything
else cascades from there.
---
## Right now (unblocks everything else)
**1. Push to a GitHub remote.** No remote is configured by default on a
fresh template clone, which means CI doesn't run anywhere. Either:
- `gh repo create <owner>/template-vertical --source=. --private --push` (or `--public`)
- Or push to an existing remote: `git remote add origin <url> && git push -u origin main`
**Decision attached:** public vs private. Public → CodeQL is free, Socket
free tier just works. Private → CodeQL needs GitHub Pro/Team/Enterprise
plan (workflow runs unconditionally but GitHub gates execution).
---
## During the dispatch loop (the agent drives this; you watch)
**2. Continue the in-flight library-evaluation epic.** Run
`pnpm work dispatch --execute`. The dispatcher picks up the next unticked
bullet and marches through.
Refresh `~/.claude/.credentials.json` from the macOS keychain when
sandcastle returns 401 (the keychain one-liner; happens ~every 30 days):
```bash
security find-generic-password -s "Claude Code-credentials" -a "$USER" -w \
> ~/.claude/.credentials.json
chmod 600 ~/.claude/.credentials.json
```
**3. After library-evaluation epic completes**, the CI-security epic
unblocks. `pnpm work dispatch --execute` picks up its story 01
automatically.
---
## After all implementation lands (one-time setup, ~30 minutes total)
**4. Install GitHub Apps** (one click each, free tier):
- **Renovate** → `https://github.com/apps/renovate` → grant repo access.
After install, Renovate opens an onboarding PR — merge it to enable.
**First real PR is the Action SHA-pin sweep** (rewrites `@v4`
`@<sha>` across all workflows). Merge that too.
- **Socket Security** → `https://github.com/apps/socket-security`
grant repo access. PR comments start appearing on the next
`package.json` diff.
**5. Toggle GitHub repo settings** (Settings → Code security and
analysis):
- ✅ Dependabot **alerts** (server-side vuln scan) — your passive
monitoring surface
- ✅ Dependabot **security updates** — OFF (Renovate handles bumps;
alerts stay on for visibility)
- ✅ Secret scanning + **push protection** — blocks known token
patterns at the GitHub edge
- ✅ CodeQL alerts (auto-enabled by the workflow)
**6. Configure branch protection on `main`** (Settings → Branches →
main):
- Require status checks: `validate`, `socket-security`, `CodeQL`
- Require linear history (matches release-please's expectations)
- Do **not** add `library-policy/re-evaluation` as a blocker — ADR-023
explicitly decided against gating main on revalidation issues
**7. Add `TURBO_TOKEN` + `TURBO_TEAM`** as repo secrets/variables for
Turborepo remote caching (already documented in `ci.yml`'s comment
block).
**8. Sentry DSNs** if you want production observability per ADR-014 /
ADR-017 (`WEB_NEXT_SENTRY_DSN`, `CMS_SENTRY_DSN`, etc.) — set as repo
secrets for the apps you actually deploy.
---
## Ongoing (per-decision, weekly cadence)
**9. Renovate's weekly PR stream.**
- **Minor + patch** bumps auto-merge if green. Nothing to do.
- **Major** bumps block until `evaluate-library` re-runs and refreshes
the trace's `last-revalidated`. The dispatch loop can pick these up
via story-style task — or you walk the skill manually
(`/evaluate-library <name> --tier <feature|core> --target <path>`).
**10. Weekly trace-revalidation cron fires** every Monday 06:30 UTC.
- Soft divergence → appended to the rolling `library-policy/dashboard`
issue. Skim weekly; mostly no-action.
- Hard divergence → fresh `library-policy/re-evaluation` issue per
affected dep. **Human triage required** (ADR-023 §3, no
auto-dispatch). Decide: re-walk evaluate-library, accept-with-
allowlist, or migrate off the library. Add the issue to the dispatch
queue if the re-walk is mechanical.
**11. CVE accepted-risk decisions.** When `pnpm audit` flags something
with no patch available, add `accepted-cves: [CVE-XXXX-YYYY]` to the
relevant trace's frontmatter with a note explaining why the risk is
accepted.
**12. License-allowlist requests.** ADR-022 names
`MIT/Apache-2.0/BSD/ISC/MPL-2.0` as allowlisted. If a real need surfaces
(e.g. a `GPL-3.0-with-classpath-exception` library), you decide whether
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 <name> --tier core --target packages/core-analytics`. The
resulting trace at `docs/library-decisions/<date>-<name>.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
`<AnalyticsProvider value={...}>` 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)
— human reading-room for the 9 filters + 3 prompts
- `docs/guides/ci-security.md` (CI-security epic story 09) — human
reading-room for the four pillars + failure-mode hierarchy table
---
## Cleanup notes
- **Untracked files in repo root** — `check-shas-cjs.js`,
`check-shas.mjs`, `check-shas2.mjs`, `check-shas3.mjs`. These appeared
during SHA-experimentation work and aren't part of any commit. Decide
whether to delete or `.gitignore`.
- **`apps/*/tsconfig.tsbuildinfo`** continues to churn on every
typecheck. A `chore: gitignore tsbuildinfo` commit would stop that
drift.
---
## Related
- 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
- `docs/guides/ci-security.md` — security stack reference