# Task 1.6 — Schema snapshot/apply tooling **Phase:** 1 — Slice 1 schema + deploy pipeline **Status:** ⬜ Not started **Depends on:** 1.4, 1.5 (collections must exist before there's anything to snapshot) **Wiki refs:** `docs/wiki/entities/directus.md` (Schema management section) ## Goal Wrap Directus's native `schema snapshot` and `schema apply` commands in repo-local scripts and npm aliases so the snapshot/apply lifecycle is one command, ergonomic for daily dev, and reliable in the entrypoint and CI. Commit the first generated `snapshots/schema.yaml` containing the 12 Phase 1 collections. ## Deliverables - `scripts/schema-snapshot.sh`: - Runs against a *running* Directus container (the local `directus` service from compose.dev.yaml). - Invokes `directus schema snapshot --yes /tmp/snapshot.yaml` inside the container. - Copies the generated snapshot out to `./snapshots/schema.yaml`. - Exits non-zero if Directus isn't reachable or the snapshot command fails. - One-line success log: `snapshot written to snapshots/schema.yaml ( bytes)`. - `scripts/schema-apply.sh`: - Used at boot (entrypoint) and in CI dry-run. - Invokes `directus schema apply --yes /directus/snapshots/schema.yaml`. - Logs the diff before applying (`directus schema apply --dry-run` then real apply). - Exits non-zero on failure. - `package.json` scripts (already stubbed in 1.1): - `schema:snapshot` → runs the snapshot script (dev-time only). - `schema:apply` → runs the apply script (used by entrypoint, also useful for local "apply this committed snapshot to my running dev DB"). - `schema:diff` → wraps `directus schema apply --dry-run` to preview pending changes without applying. - `snapshots/schema.yaml` — first committed snapshot, containing the 12 Phase 1 collections from tasks 1.4 + 1.5. - `snapshots/README.md` — short note explaining: this directory is **generated**, edit Directus via the admin UI and re-snapshot, do not hand-edit YAML. ## Specification - **Snapshot script runs against a running container, not via Node.** The `directus` CLI requires the same env (DB connection, KEY, SECRET) the server uses; easiest is to `docker compose exec directus directus schema snapshot ...`. Document this assumption — the script fails clearly if no compose stack is running. - **Apply script is environment-agnostic.** It runs inside the image at boot (where Directus is in PATH) and in CI (where it runs against a throwaway Postgres). Don't assume compose; the script just calls `directus schema apply` with paths injected via env or arguments. - **Snapshot format.** Directus 11 snapshots are YAML by default. Pin the format explicitly via the `--format=yaml` flag if available — otherwise rely on the default. Verify the chosen Directus 11 patch version's snapshot format is stable across patch bumps. - **Diff before apply, always.** The apply script logs `directus schema apply --dry-run` output before the real apply. This makes container boot logs self-explanatory: "applying these changes". On a clean re-deploy, the diff is empty. - **Snapshot regeneration is a manual, conscious action.** Don't auto-regenerate on file save. The dev edits the schema in admin UI, decides the change is good, then runs `pnpm run schema:snapshot` to capture it. ## Acceptance criteria - [ ] With Phase 1's 12 collections in the running dev Directus, `pnpm run schema:snapshot` produces a `snapshots/schema.yaml` file. - [ ] `snapshots/schema.yaml` contains all 12 collections (verified by grep for `collection: organizations`, `collection: events`, etc.). - [ ] The snapshot is < 200 KB (sanity check — much larger means something is wrong like committed data). - [ ] `pnpm run schema:diff` against the same running Directus shows "no changes". - [ ] Wipe Directus DB (`pnpm dev:reset`) → boot fresh → `pnpm run schema:apply` recreates the 12 collections from the committed snapshot. - [ ] Snapshot a second time after no admin UI changes → result is byte-identical to the first. - [ ] Make a trivial admin UI change (add a description to a field) → snapshot → diff against committed → exactly that change shows up. - [ ] `snapshots/schema.yaml` is committed; `snapshots/README.md` warns against hand-editing. ## Risks / open questions - **Snapshot determinism across runs.** Some Directus versions have re-ordered keys in their snapshot output between identical runs, producing noisy diffs. If this happens on the pinned version, document it as a known issue and consider a post-snapshot `yq sort-keys` normalization step. - **Permission policies in the snapshot.** Phase 1 has no policies set; verify the snapshot is empty in those sections. When Phase 4 adds policies, re-evaluate whether snapshot/apply round-trips them faithfully. - **`directus_users` custom-field round-trip.** Already flagged in task 1.4. If those fields don't round-trip, the workaround (separate `user_profiles` collection) needs to be applied before this snapshot lands. ## Done (Fill in commit SHA + one-line note when this lands.)