Phase 6b/7b: dashboard codes editor, decode events, human-readable briefs (AUD-115)

- New /codes dashboard page (behind the session login, linked in the top bar):
  lists every mapping by kind with Add, inline Edit+Save and Delete. Sam can put
  real teacher surnames in without a rebuild (FR-17).
- Decode timetable EVENTS through the same map as periods, so an ensemble reads
  'JAZZ ENSEMBLE - Ensemble Room - Mr KWO' instead of raw codes.
- teacherName splits comma- or space-separated codes ('HHL, OFG').
- SeedCodes is a one-time bootstrap while the table is empty, so a correction or
  a delete is never overwritten or restored.
- Tests: decode Label/Event, the /codes page (save, refuse, csrf, delete, auth),
  store re-seed behaviour. go test ./internal/... passes.
This commit is contained in:
2026-10-16 12:50:31 +11:00
parent 80b54524ea
commit 3e25011399
11 changed files with 433 additions and 28 deletions

View File

@@ -36,18 +36,24 @@ hour moves with the day's first event (07:00 on one page, 06:00 on another).
## 2. The decode map (FR-17)
`codes` (migration `005_codes.sql`) is the editable map: `subject`, `room`,
`teacher` and `period`. It is seeded on first read and never overwrites a
correction. An unknown code renders as the **raw code**, never blank.
`teacher` and `period`. It is seeded **once**, while the table is empty, and never
overwrites or restores a row after that, so a correction or a delete sticks. An
unknown code renders as the **raw code**, never blank.
The same map decodes the timetable **events**, not only the lesson periods, so
an ensemble reads in plain English too:
```
=== FINN ===
PERIODS TODAY
- Period 1 — Year 7 Science — Room H14LAB — Mr KNI (08:55)
...
- Period 4 — Year 7 Physical Education — Gym 4 — Mr LTA (13:26)
EVENTS TODAY
- JAZZ ENSEMBLE — Ensemble Room — Mr KWO (07:45)
- JUNIOR GUITAR ENSEMBLE — Theatre — Mr HHL / Mr OFG (07:45)
```
Sam edits it without a rebuild:
Sam edits it without a rebuild, **in the dashboard** or by CLI:
- dashboard: `/codes` (linked as **Codes** in the top bar) lists every mapping by
kind with an Add form per kind, an inline Edit + Save per row, and Delete. The
page sits behind the same session login as the dashboard.
```bash
docker exec compass-teams-nhs /app/school codes list
@@ -56,9 +62,9 @@ docker exec compass-teams-nhs /app/school codes delete --kind room --code Z9
```
Teacher rows are placeholders (`KNI` -> `Mr KNI`) because Compass gives only
initials; Sam replaces them with surnames. Real unknown-code fallback from the
live brief: Harry's period 2 teacher field is `GT AGE_13`, and `AGE_13` is not
mapped, so it renders raw (`Mr GT / AGE_13`).
initials; Sam replaces them with surnames in the dashboard. Real unknown-code
fallback from the live brief: Harry's period 2 teacher field is `GT AGE_13`, and
`AGE_13` is not mapped, so it renders raw (`Mr GT / AGE_13`).
Seed size: 65 rows — 23 subjects, 22 teachers, 18 rooms, 2 period labels.
@@ -223,6 +229,8 @@ internal/parse/daywidget.go the per-child "Today" widget
internal/parse/parse.go, calendar.go, importance.go per-child hook, week-calendar filter
internal/dashboard/dashboard.go brief buckets + the required 4-section renderers
internal/brief/brief.go Finn-first order, codes decoder, new renderers
internal/web/server.go /codes page + save/delete handlers
internal/web/templates/codes.html the dashboard decode-map editor
internal/calendar/sync.go periods + due + overdue + events, decoded, once
internal/calendar/ha.go Event JSON exposes start/end for evidence
cmd/school/{main,parse,calendar,codes,items,notify}.go wiring, codes CLI, purge by page
@@ -240,4 +248,5 @@ docker-compose.yml, Makefile image 0.6.2-phase6b7b
- The **week calendar** is still not fetched by the daily scan, so a *new*
major event is only written if a run fetches that page. The two existing
school-wide events remain in the calendar.
- **Teacher names** are placeholders; only Sam can supply the surnames.
- **Teacher names** are placeholders; Sam supplies the surnames in the new
`/codes` dashboard page. Until then they render as initials.