The boundaries
- Orchestration
- Collection
- Storage
- Presentation
- Voice agent
n8n, self-hosted behind a Caddy reverse proxy.Runs the scrape on a schedule, calls the scraper, commits each class’s snapshot to the data repo through the GitHub Contents API, updates the rolling index, and sends error notifications. Conditional logic lives here, not in application code.See n8n workflow.
What each boundary is trusted with
A scheduled run
Design choices
Why does n8n own the data flow?
Why does n8n own the data flow?
The scraper’s job is to collect. If it also decided where data goes and who gets notified, every new notification channel or storage target would mean a code change and a redeploy. With n8n as the orchestrator, those become workflow branches, and every execution is logged with its full input and output.
Why store snapshots in Git?
Why store snapshots in Git?
Each snapshot is written as timestamped commits, so any later change to it shows up in Git history. That is the property the project exists to provide. JSON files in a repository are also enough for one student over a school year; a database can be added later without changing the snapshot format.
Why pre-compute some diffs and not others?
Why pre-compute some diffs and not others?
The calendar needs a change count for every day in a month. Fetching and diffing dozens of snapshots per page view would be slow, so those counts live in the rolling index. Detail views need only two snapshots, so they are diffed on demand from the raw files. See Change detection.