Personal teaching reporting tool
TypeScript · Node.js · SQLite · external integrations
I designed, developed, and maintain this personal tool. I'm its only developer and its only user, and I've evolved it over six months alongside my software specialization at EAFIT. It connects my calendar, teaching notes, AI-assisted session summaries, and the dashboard where teaching hours are reported, so that reporting takes less of my time and leaves more for teaching.
Where it fits
I run it from the command line. It reads scheduled sessions and notes, compares them with what the dashboard has recorded, shows me the differences, and applies only the changes I approve.
Inside the application
It is a modular monolith: one Node.js codebase and one SQLite database, divided into capability modules that each own their state. The command line adapters call operations (discover, reconcile, update), which use the modules through their public interfaces. A separate scheduled job, run by GitHub Actions, checks remaining hours.
Decisions worth explaining
- Reconcile, then review
- Calendar-backed sessions, notes, and dashboard records are compared, and discrepancies are shown for review instead of being silently corrected. I decide what changes.
- Writes preview unless applied
-
Each command that can change the dashboard shows a preview unless I
pass
--apply. The combined pipeline goes the other way and refuses to start without it. The dashboard's HTTP client also checks every non-GET request against a mutation policy before it reaches the server. - Generated summaries don't overwrite my edits
- AI-assisted summaries are drafts that are stored for later reporting. When I regenerate, summaries I've edited or imported are preserved.
- Alerts that don't repeat themselves
- The hours-alert job stores its warning state, so a low balance produces one notification rather than one per run. A balance that goes up is treated as an observed change, not as proof of payment.
Keeping it maintainable as it grew
- Module boundaries are enforced. Lint rules restrict cross-module imports to each module's public API and keep the dependency map acyclic, so the structure can't quietly erode.
- Contracts are validated at the edges. Command-line flags are parsed strictly against declared options, and database rows are validated against schemas before they become domain objects.
- Audit logs redact sensitive fields, recursively, before anything is written.
- Backups are verified. A backup stages snapshots and checks their integrity before replacing the previous ones, and keeps the earlier backups if that fails.
- Tests and CI. Vitest tests cover command parsing, preview-versus-apply behavior, module boundaries, and audit redaction. GitHub Actions runs the scheduled alert job.
Result
I use it for my own reporting. It takes less of my time, the reporting is better because the tool makes it easier, and I've been able to spend the time saved on teaching. I haven't measured the time saved and it has no other users, so I don't claim numbers or wider adoption.
The source is in a private repository. I'm happy to walk through the code and the architecture decision records on a call.