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>
68 lines
2.5 KiB
SQL
68 lines
2.5 KiB
SQL
-- 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'))
|
|
);
|