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.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# Phase 3 — Timing & penalty tables
|
||||
|
||||
**Status:** ⬜ Not started — co-developed with [[processor]] Phase 2
|
||||
**Outcome:** The schema half of the paired schema/code work that produces real timing results. Adds `entry_segment_starts`, `entry_crossings`, `entry_penalties`, `stage_results`, and `penalty_formulas` collections. Penalty evaluator registry ships on the [[processor]] side; the rule numeric values ship here. After Phase 3, operators can review computed penalties, override them, and publish official stage results.
|
||||
|
||||
## Why this is co-developed
|
||||
|
||||
- **Schema and writer must land together.** `entry_crossings` rows are written by [[processor]] Phase 2; defining the collection without the writer is dead weight, defining the writer without the collection is broken code. Land both in the same release window.
|
||||
- **Penalty formula seeding is event-specific.** Rally Albania 2026's SLZ brackets come from the Supplementary Regulation (published 60 days before the event per regs §1.8). Phase 3 needs that data, or a reasonable placeholder, before the rally.
|
||||
- **Snapshot pattern requires care.** `entry_penalties` snapshots its inputs (peak speed, count, formula values). The schema must capture this faithfully so the recompute strategy in [[processor]] works.
|
||||
|
||||
## Tasks (sketched, not detailed)
|
||||
|
||||
| # | Task | Notes |
|
||||
|---|------|-------|
|
||||
| 3.1 | `penalty_formulas` collection | Per [[directus-schema-draft]]: `event_id`, `belongs_to_type`, `belongs_to_id`, `type`, `offence_min`, `offence_max`, `operator`, `penalty`, `retroactive`, `enabled`. Both bracket-style and flat-style coexist. |
|
||||
| 3.2 | `entry_segment_starts` collection | `entry_id`, `segment_id`, `start_position`, `target_at`, `manual_override`. Materialized at stage open. |
|
||||
| 3.3 | `entry_crossings` collection | Per-position-derived crossing events. Idempotent on `(entry_id, geofence_id, ts)`. Written by [[processor]]. |
|
||||
| 3.4 | `entry_penalties` collection | `entry_id`, `type`, `formula_id`, `formula_snapshot` (JSONB), `inputs` (JSONB), `seconds`, `evaluated_at`, `recomputed_at`, `manual_override`. Snapshot inputs and rule rows for cheap recompute. |
|
||||
| 3.5 | `stage_results` collection | `entry_id`, `stage_id`, `clean_time`, `penalty_seconds`, `total_time`, `position_in_class`, `position_overall`, `published_at`. The next-stage seeding input is `clean_time`. |
|
||||
| 3.6 | Custom interface for penalty review | Operator-facing panel showing all `entry_penalties` rows for a stage, with diff between auto-computed and manual override. Likely a custom extension (Phase 5 territory). Phase 3 produces the schema; the UI follows. |
|
||||
| 3.7 | Snapshot regeneration + CI verification | All new collections in the snapshot; CI dry-run still passes. |
|
||||
| 3.8 | Rally Albania SLZ bracket seed | Once the Supplementary Regulation is published, seed `penalty_formulas` rows with the actual brackets. Single SQL/Directus-API script. |
|
||||
|
||||
## Open questions blocking task-level detail
|
||||
|
||||
1. Does `entry_crossings` need PostGIS metadata on each row (e.g. the exact geometry-relative position), or just `(entry_id, geofence_id, ts, kind)`? Default: minimal, the position is in `positions` and the join key gets you back to it.
|
||||
2. Where does `position_in_class` and `position_overall` get computed — DB view, materialized view, or [[processor]]-written column? Trade-off: view is simpler but slower; column is faster but needs invalidation.
|
||||
3. Penalty review workflow UX — is the operator approving each row individually, or bulk-approving the auto-computed set with manual exceptions? Drives whether `manual_override` is a single bool or a richer state.
|
||||
Reference in New Issue
Block a user