Phase 6: write important school events to the Home Assistant calendar
Add the Home Assistant REST calendar client and the idempotent sync that writes important school events to Sam's Home Assistant calendar (FR-8). The school stays read-only; the only write is to the calendar (rule 7). - internal/calendar: HA REST client (states, create_event, get_events, delete_event) and the sync that selects important future events, adopts an existing event by its description marker, records the HA event id on the item, and records every attempt. - internal/store: migration 003 (items.ha_event_uid, items.ha_pushed_at and the append-only calendar_pushes table), candidates, mark-synced and the push log. - internal/parse: a school event is important; a routine class period is not. - cmd/school: `school calendar entities|status|push|events`. - web: an "Add to calendar" item action and a fail-loud calendar banner, so a failed write is never swallowed (FR-12). - scripts/calendar-push.sh, Makefile target, env example, docs and tests. The target is configurable (SCHOOL_HA_CALENDAR_ENTITY). Home Assistant has no non-Google writable calendar today, so the entity is asked on AUD-110. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
24
internal/store/migrations/003_calendar.sql
Normal file
24
internal/store/migrations/003_calendar.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Migration 003 — Phase 6 calendar write (AGENTS.md §4 FR-8, §11 Phase 6).
|
||||
--
|
||||
-- Important school events are written to Sam's Home Assistant calendar. The
|
||||
-- write must be idempotent: the Home Assistant event id is stored on the item,
|
||||
-- so a re-run updates nothing and never duplicates an event. The push log is
|
||||
-- append-only, so a failed calendar write is visible and loud instead of being
|
||||
-- swallowed (FR-12).
|
||||
|
||||
ALTER TABLE items ADD COLUMN ha_event_uid TEXT NOT NULL DEFAULT '';
|
||||
ALTER TABLE items ADD COLUMN ha_pushed_at TEXT;
|
||||
|
||||
-- One row per calendar write attempt. ok = 0 with an error is a loud failure.
|
||||
CREATE TABLE IF NOT EXISTS calendar_pushes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
item_id INTEGER NOT NULL REFERENCES items(id),
|
||||
entity_id TEXT NOT NULL,
|
||||
uid TEXT,
|
||||
ok INTEGER NOT NULL DEFAULT 0,
|
||||
error TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_calendar_pushes_item ON calendar_pushes(item_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_calendar_pushes_created ON calendar_pushes(created_at);
|
||||
Reference in New Issue
Block a user