Files
directus/.planning/phase-1-slice-1-schema/06-snapshot-tooling.md
T
julian a8e808e71c Scaffold directus service planning structure
Initial commit. Establishes the .planning/ tree mirroring processor's
shape (ROADMAP.md as nav hub + per-phase folders with READMEs and
granular task files).

Six phases:

1. Slice 1 schema + deploy pipeline — what Rally Albania 2026 needs.
   Org catalog (orgs, users, vehicles, devices) + event participation
   (events, classes, entries, entry_crew, entry_devices). db-init/
   for the positions hypertable + faulty column. snapshot/apply
   tooling. Gitea CI dry-run. Dogfood seed of Rally Albania 2026.
   Nine task files with full Goal / Deliverables / Specification /
   Acceptance criteria / Risks / Done sections.

2. Course definition — stages, segments, geofences, waypoints, SLZs.
   PostGIS extension introduced here.

3. Timing & penalty tables — co-developed with processor Phase 2.
   entry_segment_starts, entry_crossings, entry_penalties,
   stage_results, penalty_formulas.

4. Permissions & policies — Directus 11 dynamic-filter Policies per
   logical role. Deployment-time work, deferred to keep early phases
   focused on the data model.

5. Custom extensions — TypeScript hooks/endpoints implementing the
   cross-plane workflows the schema implies (faulty-flag → Redis
   stream emit, stage-open materializer, etc.).

6. Future / optional — retroactivity preview UI, command-routing
   Flows, audit trails, federation rule import. Not committed.

Non-negotiable design rules captured in ROADMAP.md: schema authority
in Directus + snapshot-as-code + db-init for non-Directus DDL +
sequential idempotent migrations + entrypoint apply order + no
application logic in Flows + permissions deferred to Phase 4.

Architectural anchors point at the wiki at ../docs/wiki/ — the schema
draft, the Rally Albania 2025 source page, plus the existing
processor/postgres-timescaledb/live-channel pages. Each task file
calls out the wiki refs an implementing agent should read first.

README.md mirrors the processor service README structure: quick start,
local Docker test, prod/stage deployment notes, env vars, CI behavior.
2026-05-01 20:42:44 +02:00

5.0 KiB

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 (<size> 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.)