# Compass NHS — Code Map

## Module

`gitea.lab.audasmedia.com.au/sam/compass_teams_nhs`

Language: Go 1.25. Database: SQLite through `modernc.org/sqlite`. Passwords use
`golang.org/x/crypto/bcrypt`. There is no other direct dependency.

## Entry Point

`cmd/school/main.go` holds the entry point. The first argument selects a
subcommand. With no argument it starts the HTTP service.

| Subcommand | Function |
| :--- | :--- |
| `run` (default) | Starts the HTTP service, migrates the schema and seeds the children. |
| `parse` | Turns stored raw pages into items. |
| `session` | Shows or clears the harness session per child. |
| `scan` | Fetches and parses one child or both. |
| `items` | Reads or deletes items. |
| `brief` | Builds a brief. |
| `notify` | Sends briefs and shows the send status. |
| `calendar` | Pushes events to Home Assistant. |
| `hash-password` | Prints a bcrypt hash. |
| `gen-secret` | Prints a fresh secret. |
| `version` | Prints the version. |

## Folders

| Folder | Function |
| :--- | :--- |
| `cmd/school/` | One file per subcommand plus `main.go`. |
| `internal/web/` | HTTP server, handlers, HTMX templates, static assets. Holds `hub_api.go`. |
| `internal/auth/` | Session login with signed cookies and CSRF. |
| `internal/store/` | SQLite open, migrations and queries. |
| `internal/store/migrations/` | `001_init`, `002_items_parse`, `003_calendar`, `004_notifications_send`. |
| `internal/parse/` | HTML to items. Readings for tasks, news, calendar and importance. |
| `internal/llm/` | OmniRoute client for importance classification only. |
| `internal/dashboard/` | Builds the per-child buckets. Classifies overdue and due-today. |
| `internal/brief/` | Builds and delivers the morning briefs. |
| `internal/apprise/` | Apprise API client. Uses tags and redacts errors. |
| `internal/calendar/` | Home Assistant client and the idempotent sync. |
| `internal/hub/` | The Hub contract: capabilities and read-only answers. |
| `internal/config/` | Reads the environment. |
| `deploy/` | Caddy snippet, n8n workflow, import and key scripts, verify scripts. |
| `scripts/` | Scrapers, parse and morning-brief wrappers, calendar push. |

## The Read-Only Boundary

`internal/hub` depends on a `Reader` interface. The interface has three read
methods and no write method. Test `TestHubAskReadsOnly` proves that `/ask` does
not change the `items`, `scans` or `notifications` row counts.

## The Scraper

`scripts/compass-fetch-patchright.mjs` logs into Compass with patchright. The
login POST meets a Cloudflare managed challenge. patchright, a headless
Playwright build, passes the challenge. The pi-browser-harness does not.

The Compass parent login required no two-factor code during the Phase 2 proof.

## Database Tables

| Table | Holds |
| :--- | :--- |
| `children` | id, name, year, Compass id. |
| `items` | Child, type, subject, teacher, title, body, due date, URL. |
| `scans` | Start time, child, pages fetched, items found, error. |
| `notifications` | Recipient, scope, summary, channel, status, sent time. |
| `session` | Harness session state per child. |
| `calendar_pushes` | Calendar write attempts, result and error. |

The raw Compass pages are not in the database. The fetcher writes them to
`var/raw/<child>/<timestamp>/` on the host. Each folder holds the HTML, a meta
file per page, and a manifest with a SHA-256 and a byte count per page.

## Tests

Run `make test`. The suite uses standard Go tests. The tests cover the store,
the parser, the dashboard buckets, the brief, the Apprise client, the calendar
sync, the Hub API and the read-only rule.
