a8e808e71c
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.
3.5 KiB
3.5 KiB
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_crossingsrows 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_penaltiessnapshots 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
- Does
entry_crossingsneed 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 inpositionsand the join key gets you back to it. - Where does
position_in_classandposition_overallget computed — DB view, materialized view, or processor-written column? Trade-off: view is simpler but slower; column is faster but needs invalidation. - Penalty review workflow UX — is the operator approving each row individually, or bulk-approving the auto-computed set with manual exceptions? Drives whether
manual_overrideis a single bool or a richer state.