Files
directus/.planning/phase-1-slice-1-schema/04-org-catalog-collections.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.9 KiB

Task 1.4 — Org-level catalog collections

Phase: 1 — Slice 1 schema + deploy pipeline Status: Not started Depends on: 1.3 (db-init applied so Directus can boot) Wiki refs: docs/wiki/synthesis/directus-schema-draft.md (Org-level catalog section), docs/wiki/sources/rally-albania-regulations-2025.md

Goal

Create the durable, org-level collections in the Directus admin UI: organizations, users (using Directus's built-in users with custom fields), organization_users, vehicles, organization_vehicles, devices, organization_devices. These are the resources that exist independently of any single event.

This task happens against a locally running Directus instance (from pnpm dev). The output is a snapshot YAML that captures the collection definitions; that snapshot lands in git in task 1.6.

Deliverables

Create the following collections via the admin UI (Settings → Data Model). Field shapes per directus-schema-draft. Required-field columns marked *.

organizations

Field Type Notes
id * UUID primary key, auto-generated
name * string display name
slug * string URL-friendly identifier, unique
created_at timestamp Directus standard
updated_at timestamp Directus standard

Singleton: false. Sort: name asc.

users (extending Directus built-in directus_users)

Use the built-in user collection. Add custom fields (Settings → Data Model → directus_users):

Field Type Notes
phone string optional
birth_date date optional, used for age-derived class eligibility (M-5/M-6/M-7)
nationality string ISO 3166-1 alpha-2 country code

Do NOT add an organization_id here — multi-tenancy goes through organization_users.

organization_users (junction)

Field Type Notes
id * UUID
organization_id * M2O → organizations
user_id * M2O → directus_users
role * string (dropdown) enum: org-admin, race-director, marshal, timekeeper, participant, viewer
joined_at timestamp default now()

Unique constraint: (organization_id, user_id) — a user can only have one row per org. Multiple roles per user in same org → not yet (single role per tenant; revisit if needed).

vehicles

Field Type Notes
id * UUID
make * string "Toyota"
model * string "Land Cruiser 70"
year integer
engine_cc integer engine displacement, used for class assignment
vin string optional
plate_number string optional
notes text

No owner_user_id / owner_team_id — vehicles are org-scoped only, ownership is not modeled (per directus-schema-draft decision).

organization_vehicles (junction)

Field Type Notes
id * UUID
organization_id * M2O → organizations
vehicle_id * M2O → vehicles
registered_at timestamp default now()

Unique constraint: (organization_id, vehicle_id).

devices

Field Type Notes
id * UUID
imei * string unique, the canonical device identifier
model * string "FMB920", "FMB003", etc. — drives IO mapping in processor
serial_number string optional
notes text

imei UNIQUE — same IMEI can't be registered twice anywhere in the system.

organization_devices (junction)

Field Type Notes
id * UUID
organization_id * M2O → organizations
device_id * M2O → devices
registered_at timestamp default now()

Unique constraint: (organization_id, device_id).

Specification

  • Use UUIDs for all primary keys (Directus offers UUID v4 generation natively). Avoids leaking row counts and simplifies cross-env data sync.
  • All M2O relations have ON DELETE set to RESTRICT by default — accidentally deleting an org or vehicle should require the operator to clean up dependents first. Override per-relation only with explicit reason.
  • No permission policies — Phase 4 territory. Set every collection to "All Access" → none (admin only) for now.
  • No interface customization beyond defaults — the SPA isn't using these collections directly yet, and admin UI usability for operators happens after Phase 4 (when policies define what they see).
  • Do not commit .env or any secrets. This task only modifies Directus schema, which is captured in the snapshot.

Acceptance criteria

  • All seven collections exist in the admin UI with the fields listed above.
  • Required fields are flagged required.
  • All unique constraints are enforced (test by trying to create a duplicate row — should error).
  • M2O relations are visible and clickable in the admin UI's relational fields.
  • No permission policies attached (admin-only).
  • Manually create one organization, one user, one organization_user row → the relationships work end-to-end.
  • pnpm run schema:snapshot produces a snapshots/schema.yaml with all seven collections present (verified by grep).
  • Booting a brand-new Directus instance (fresh DB, fresh containers) and running directus schema apply --yes snapshots/schema.yaml recreates the seven collections identically.

Risks / open questions

  • directus_users field additions — Directus does allow adding fields to its built-in user collection, but the snapshot/apply behavior for those additions has historically been finicky across versions. Verify on the pinned Directus version that custom user fields round-trip cleanly via schema snapshot + schema apply. If they don't, fall back to a separate user_profiles collection M2O'd to directus_users.
  • Slug uniqueness on organizations — Directus enforces this at the field level. Confirm it generates a unique-index DDL in the snapshot.

Done

(Fill in commit SHA + one-line note when this lands.)