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

@@ -419,7 +419,7 @@ func RenderBrief(child string, b Buckets, decode func(string) string, loc *time.
fmt.Fprintf(&sb, "=== %s ===\n", strings.ToUpper(strings.TrimSpace(child)))
writeBriefPeriods(&sb, b.PeriodsToday, decode, loc)
writeBriefEvents(&sb, b.EventsToday, loc)
writeBriefEvents(&sb, b.EventsToday, decode, loc)
writeBriefWork(&sb, "OVERDUE", b.Overdue, loc)
writeBriefFuture(&sb, b, loc)
return sb.String()
@@ -455,19 +455,25 @@ func writeBriefPeriods(sb *strings.Builder, items []store.Item, decode func(stri
}
}
// writeBriefEvents lists today's major school events (FR-9b).
func writeBriefEvents(sb *strings.Builder, items []store.Item, loc *time.Location) {
// writeBriefEvents lists today's major school events (FR-9b), decoded through
// the same map as periods so an ensemble or a concert reads as plain English
// (FR-17). Unknown codes stay raw.
func writeBriefEvents(sb *strings.Builder, items []store.Item, decode func(string) string, loc *time.Location) {
sb.WriteString("\nEVENTS TODAY\n")
if len(items) == 0 {
sb.WriteString("- none\n")
return
}
for _, it := range items {
title := strings.TrimSpace(it.Title)
if decode != nil {
title = decode(title)
}
when := ""
if it.DueAt != nil {
when = " (" + it.DueAt.In(loc).Format("15:04") + ")"
}
fmt.Fprintf(sb, "- %s%s\n", strings.TrimSpace(it.Title), when)
fmt.Fprintf(sb, "- %s%s\n", title, when)
}
}