Files
compass_teams_nhs/docs/phase-5-dashboard-notes.md
Sam Rolfe 37d82b1a0a Phase 5: per-child dashboard (overdue first), item detail, delete
- internal/dashboard: classify items into overdue / due today / due this week /
  no due date / messages; render the plain-text brief (FR-6, FR-7, FR-9).
- internal/store: ItemsForChild, ItemByID, DeleteItemByID, ScanSummaryForChild
  and the stored-brief CRUD helpers (FR-10).
- internal/web: routes /?child=, /items/{id}, POST /items/{id}/delete,
  POST /summaries/build, POST /summaries/{id}/delete, plus a per-child scan
  banner (FR-12) and a phone-first server-rendered template.
- Calendar events are never "overdue": a past lesson is history, not work.
- cmd/school brief build|list; scripts/screenshot-phase5.mjs for phone evidence.
- Tests: bucket classification, stored-brief round-trip, and HTTP routes
  including the NO SCAN / SCAN FAILED / healthy banner behaviour.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-15 17:50:29 +11:00

4.5 KiB
Raw Blame History

Phase 5 — the per-child dashboard

Status: done. Sam can see, per child and on a phone, what is overdue, what is due today, what is due this week, and the messages. See AUD-109.

What the dashboard shows

One tab per child (Harry, Finn). The selected tab shows, in order (FR-7):

  1. Overdue — overdue first, with a red marker.
  2. Due today.
  3. Due this week — the next seven days.
  4. No due date — only when the child has such tasks.
  5. Messages — the Compass news feed, newest first.

A task is overdue when Compass says so (Status: Overdue from the JSON service, Submitted: Overdue from the grid), or when it is not submitted and its due date is before today. Submitted work (On Time, Received Late) is not "due", so it stays out of the lists; the count is shown in the panel footer.

A calendar event is never overdue: a past lesson is history, not work to do. Events appear under due today and due this week.

The page is server-rendered HTML with HTMX. It is phone-first: one column, 44px touch targets, and the Delete button steps below the title under 520px.

Routes

Method Path Shows
GET /?child=<id> the per-child dashboard (first child when child is absent)
GET /items/{id} item detail: subject, teacher, due date, link, full text (§5 screen 3)
POST /items/{id}/delete the Delete action on an item (FR-10)
POST /summaries/build build a draft brief for one child (FR-10 summary half)
POST /summaries/{id}/delete the Delete action on a stored brief (FR-10)
GET /partials/scan-status the scan banner fragment (polled every 60s)

Every POST checks the session CSRF token. An HTMX request gets 204 No Content, so the row is removed in place; a plain form post gets 303 See Other back to the dashboard, so the page works without JavaScript.

A deleted item returns on the next parse if the school still lists it. A deleted brief is gone.

Fail loudly (FR-12)

The banner reads the scan log. It is never an empty day:

  • NO SCAN HAS RUN YET — amber. A child with no scan shows "Unknown — the last scan did not complete." instead of "Nothing overdue.".
  • SCAN FAILED — red, with the recorded error. The child panel repeats the warning.
  • Last scan completed — green. Only then may an empty section say "Nothing overdue.".

The banner is per child (ScanSummaryForChild), so a failed scan for Finn is never hidden by a successful scan for Harry.

Where the items come from

No new scan code: Phase 3/4 store the items. Phase 5 adds the reads and the classification (internal/dashboard).

  • internal/dashboard/dashboard.go — classify items into buckets; render the plain-text brief.
  • internal/store/dashboard.go — ItemsForChild, ItemByID, DeleteItemByID, ScanSummaryForChild, and the summary create/list/get/delete helpers.
  • internal/web/server.go — the routes and handlers.
  • internal/web/templates/dashboard.html, item.html — the screens.

The stored brief (FR-10, delete half)

A brief is a row in notifications (AGENTS.md §7). sent_at stays NULL for a draft. Building a brief stores the text; sending it is Phase 7.

docker exec compass-teams-nhs /app/school brief build --child Harry
docker exec compass-teams-nhs /app/school brief list

Verification (2026-10-15, live)

make test    # go test ./...

The tests cover the buckets, the brief text, the stored brief round-trip, and the HTTP routes. internal/web/server_test.go logs in and proves:

  • the selected child's items render and the other child's do not,
  • the overdue item renders before the due-today item,
  • the item detail carries subject, teacher and body,
  • delete removes the row and a tokenless delete is refused (403),
  • the banner shows NO SCAN HAS RUN YET, then SCAN FAILED with the error, then Last scan completed, and only a healthy scan allows "Nothing overdue.".

Live counts on .13 (Compass data of 2026-10-15):

Child Overdue Due today This week No due date Messages
Harry 6 8 7 18 1
Finn 2 0 0 8 1

The overdue counts match the home-page reconciliation from Phase 4a (Harry 6, Finn 2).

Phone-width screenshots (390 × 844) are attached to AUD-109: scripts/screenshot-phase5.mjs.

Known gaps

  • Teams (FR-15) is a separate source; the dashboard shows Compass only.
  • Sending a brief is Phase 7. Phase 5 stores and deletes a draft.
  • The calendar write (Phase 6) and the Hub API (Phase 8) are not built yet.