Phase 1: Compass/NHS skeleton (Go, SQLite, session login, Docker, Caddy)
Phase 1 of AGENTS.md §11: the app runs on .13 in its own container on port 8792, behind Caddy at school.lab.audasmedia.com.au, with its own session login and GET /health. - Go service (Go 1.25, modernc SQLite, no cgo) with its own image. - SQLite schema per AGENTS.md §7: children, items, scans, notifications, session (internal/store/migrations/001_init.sql). - Separate session login (signed cookie, CSRF double-submit), not SSO. - HTMX server-rendered shell using the Family Home Lab tokens.css: canvas #f6f5f4, action blue #0075de, Inter, 8px grid, hairline borders, pill CTAs, dark mode, phone-friendly. - Fail loudly (FR-12): a missing or failed scan shows as an explicit warning or error banner, never as an empty day. - Dockerfile + docker-compose.yml (own container, own port 8792; uses network_mode bridge because .13 has no free default Docker address pool). - Caddy snippet for .35 in deploy/caddy/, deployment notes, and deploy/verify-phase1.sh. No school scan in this phase; the Compass login and fetch are Phase 2. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
67
internal/store/migrations/001_init.sql
Normal file
67
internal/store/migrations/001_init.sql
Normal file
@@ -0,0 +1,67 @@
|
||||
-- Migration 001 — Phase 1 foundation (AGENTS.md §7).
|
||||
--
|
||||
-- Every item is stored with its child, source page, type, subject, due date and
|
||||
-- link (FR-5). Scans are append-only and record success or an explicit error,
|
||||
-- so a failed scan can never be mistaken for "nothing due" (FR-12).
|
||||
|
||||
CREATE TABLE IF NOT EXISTS children (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
year TEXT,
|
||||
compass_id TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
-- One row per message, task or calendar event read from Compass or Teams.
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
child_id INTEGER NOT NULL REFERENCES children(id),
|
||||
source TEXT NOT NULL DEFAULT 'compass' CHECK (source IN ('compass', 'teams')),
|
||||
type TEXT NOT NULL CHECK (type IN ('message', 'task', 'event')),
|
||||
subject TEXT,
|
||||
teacher TEXT,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT,
|
||||
due_at TEXT,
|
||||
url TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_items_child ON items(child_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_due ON items(child_id, due_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_type ON items(child_id, type);
|
||||
|
||||
-- Append-only scan log (FR-13). ok = 0 with a message is a loud failure.
|
||||
CREATE TABLE IF NOT EXISTS scans (
|
||||
id INTEGER PRIMARY KEY,
|
||||
child_id INTEGER REFERENCES children(id),
|
||||
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
finished_at TEXT,
|
||||
pages_fetched INTEGER NOT NULL DEFAULT 0,
|
||||
items_found INTEGER NOT NULL DEFAULT 0,
|
||||
ok INTEGER NOT NULL DEFAULT 0,
|
||||
error TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_scans_started ON scans(started_at);
|
||||
|
||||
-- One row per delivered brief (FR-9, FR-14).
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recipient TEXT NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
sent_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_sent ON notifications(sent_at);
|
||||
|
||||
-- Harness session state per child. SECRET: session cookies and tokens live
|
||||
-- here, in the database volume only. Never exported, never logged (AGENTS.md
|
||||
-- §10 rule 3).
|
||||
CREATE TABLE IF NOT EXISTS session (
|
||||
child_id INTEGER PRIMARY KEY REFERENCES children(id),
|
||||
state TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
Reference in New Issue
Block a user