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:
39
README.md
39
README.md
@@ -4,8 +4,30 @@ A school service for Harry and Finn: **Compass** for the daily schedule and
|
||||
notices, **Teams** for homework and assignments. It stores what is due per child,
|
||||
puts overdue work first, and tells the family before work is late.
|
||||
|
||||
> Build spec: [`AGENTS.md`](AGENTS.md). This repository is at **Phase 5** (the
|
||||
> per-child dashboard). See §11 of the spec for the phase order.
|
||||
> Build spec: [`AGENTS.md`](AGENTS.md). This repository is at **Phase 6** (the
|
||||
> calendar write). See §11 of the spec for the phase order.
|
||||
|
||||
## Status — Phase 6
|
||||
|
||||
Phase 6 writes the **important** school events to **Sam's Home Assistant
|
||||
calendar** through the Home Assistant REST API (FR-8). It is idempotent (a
|
||||
re-run never duplicates an event) and it fails loudly (a failed write is shown
|
||||
on the dashboard and recorded in `calendar_pushes`). See
|
||||
[`docs/phase-6-calendar-notes.md`](docs/phase-6-calendar-notes.md).
|
||||
|
||||
**Open decision:** the brief says *not Google*, and Home Assistant has no
|
||||
non-Google writable calendar yet. The target entity is configurable
|
||||
(`SCHOOL_HA_CALENDAR_ENTITY`) and the question is on
|
||||
[AUD-110](/AUD/issues/AUD-110).
|
||||
|
||||
```bash
|
||||
scripts/calendar-push.sh entities # list the writable calendar entities
|
||||
scripts/calendar-push.sh status # target, reachability, pending, last push
|
||||
scripts/calendar-push.sh push --dry-run
|
||||
scripts/calendar-push.sh push # write the pending important events
|
||||
scripts/calendar-push.sh events # read the calendar back
|
||||
make calendar CALENDAR_ARGS='push --dry-run'
|
||||
```
|
||||
|
||||
## Status — Phase 5
|
||||
|
||||
@@ -55,9 +77,9 @@ Built and deployed on `.13`:
|
||||
- Its own container and port **8792**, behind Caddy at
|
||||
`school.lab.audasmedia.com.au`.
|
||||
|
||||
Not built yet (later phases): the calendar write, notifications and the Hub API.
|
||||
The service itself does **not** scan the school; n8n triggers the scan later.
|
||||
Teams (FR-15) is a separate source.
|
||||
Not built yet (later phases): notifications and the Hub API. The calendar write
|
||||
is Phase 6. The service itself does **not** scan the school; n8n triggers the
|
||||
scan later. Teams (FR-15) is a separate source.
|
||||
|
||||
### Fail loudly (FR-12)
|
||||
|
||||
@@ -76,10 +98,11 @@ internal/config/ environment configuration
|
||||
internal/store/ SQLite: schema, migrations, queries
|
||||
internal/parse/ HTML -> structured items (tasks, messages, events)
|
||||
internal/llm/ OmniRoute client (importance classification only)
|
||||
internal/calendar/ Home Assistant calendar client + the idempotent sync
|
||||
internal/auth/ session login (signed cookies, CSRF)
|
||||
internal/web/ HTTP handlers, templates, static assets
|
||||
deploy/ Caddy snippet, deployment notes, verify script
|
||||
scripts/ Compass fetchers and the parse wrapper
|
||||
scripts/ Compass fetchers, the parse wrapper and the calendar push
|
||||
environment.d/ env example (the real file is gitignored)
|
||||
```
|
||||
|
||||
@@ -94,8 +117,8 @@ docker compose up -d --build
|
||||
Generate secrets with the built image:
|
||||
|
||||
```bash
|
||||
docker run --rm --entrypoint /app/school compass-teams-nhs/school:0.3.0-phase5 gen-secret
|
||||
docker run --rm --entrypoint /app/school compass-teams-nhs/school:0.3.0-phase5 hash-password 'the-password'
|
||||
docker run --rm --entrypoint /app/school compass-teams-nhs/school:0.4.0-phase6 gen-secret
|
||||
docker run --rm --entrypoint /app/school compass-teams-nhs/school:0.4.0-phase6 hash-password 'the-password'
|
||||
```
|
||||
|
||||
Note: Docker Compose interpolates `$VAR` inside `env_file`. A bcrypt hash
|
||||
|
||||
Reference in New Issue
Block a user