# 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 /template-vertical --source=. --private --push` (or `--public`) - Or push to an existing remote: `git remote add origin && 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` → `@` 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 --tier --target `). **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 --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) — 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