notion_weekly_report
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
- A Notion database for blood sugar readings
- A Val Town script that pulls the last 7 days of entries
- Weekly stats with streaks, XP, and Praise Cage-themed badges
- A friendly email report sent on a schedule (free tier friendly)
- Tests for core logic (streaks, badges, XP)
- A SQLite rollup module stub for future storage
- A food log enricher that reads Notion entries, estimates macros with OpenAI, and writes them back
- Food enrichment now normalizes entries with OpenAI, infers serving sizes, and uses FatSecret's detailed nutrition
- Weekly rollups persisted to SQLite for blood sugar and food
- Monthly rollup report page with a month selector (Memphis-styled)
- We only query Notion for a small time window (fast even as Notion grows)
- We compute the rollup once per week and send it as a summary
- We can reuse the same pattern for other life areas (exercise, meals, goals)
We store weekly rollups (badges, streaks, XP) in Val Town’s SQLite so we can:
- build monthly and yearly summaries without re-reading Notion
- compare across categories (e.g., blood sugar vs exercise)
- keep a long-term history even if we rename Notion pages
weekly_rollups: one row per category per weekbadge_events: a history of badges earned
Each rollup stores:
- category (e.g.,
blood_sugar) - period start/end (YYYY-MM-DD)
- streak, completion rate, XP
- badges as JSON
- summary stats as JSON
For each new Notion database:
- Add a small “collector” val that maps entries into a shared event format.
- Reuse the rollup logic and write weekly results to SQLite.
- Generate emails or dashboards from the stored rollups.
This keeps the system simple while still scaling to many life areas.
- Define XP/badge rule config so new trackers can reuse it
- Add yearly rollup report (from SQLite, not Notion)
- Add a sample “collector” val for another Notion database (e.g., exercise)
- Add run_id generation strategy (UUID or deterministic) and document it
- Validate email layout on Gmail mobile and adjust spacing if needed
- Add serving-size overrides and caching for food enrichment
The new val-scoped SQLite databases (see “Every val gets a database!”, Jan 23, 2026) let each val persist its own data with a built-in browser and forkable state. We can lean into this by turning every collector into a self-serve insights workspace that ships with its data. Key ideas:
- Goal: capture raw Notion snapshots + derived rollups inside the val-scoped DB so maintainers can inspect/patch rows via Val Town’s new DB UI and forks inherit the historical data.
- Why now: previously we used a shared
stevekrouse/sqlitedatabase, so tables mixed across vals and forks lost history. Scoped DBs fix isolation, give us point-in-time forks, and expose schema editing + CSV export without extra tooling.
- As a maintainer, I can open the Val Town DB browser for
blood_sugar_reportand see weekly rollups + the raw Notion entries that fed them. - When I fork the val, I can choose to fork the database so I get a sample dataset (perfect for demos/tests).
- I can alter or backfill rows right from the UI if a Notion entry was missing, then re-run the val and it reuses those edits.
- Adopt the new client
- Introduce
storage/sqlite.tsthat re-exportsstd/sqliteso every module uses the scoped DB (no morestevekrouse/sqliteimport). - Update
storage/rollups.ts,collectors/*.ts(x), andservices/monthly_report_page.http.tsxto consume the new helper.
- Introduce
- Expand schema per val
- Add tables:
notion_entries(raw JSON per sync run),collector_runs(metadata + errors), and keep the existingweekly_rollups/badge_events. - Ensure schema setup runs on every execution (idempotent
CREATE TABLE IF NOT EXISTS).
- Add tables:
- Persist richer data
- In collectors, before building reports, upsert
collector_runs+notion_entrieswith the fetched payload, keyed byrun_id. - Store derived stats/badges in
weekly_rollupsreferencing the samerun_id.
- In collectors, before building reports, upsert
- Ship a DB-backed UI
- Add a new HTTP val (e.g.,
services/rollup_workspace.http.tsx) that queries the scoped DB and renders:- latest sync runs with status + row counts
- raw entry drill-down (JSON pretty print) and weekly rollups
- Provide download links that hit lightweight CSV/JSON routes backed by SQL queries (can reuse Val Town DB UI exports too).
- Add a new HTTP val (e.g.,
- Migration + docs
- Write a one-off
scripts/migrate_shared_db.tsto copy data from the legacy shared database into the val-scoped DB (optional but documented). - Update
readme.mdwith “Using the val-scoped database” instructions (link to DB UI, how to fork with data, etc.).
- Write a one-off
- Do we need to keep writing to the old shared database for compatibility with the existing monthly report? (Probably no once UI + service switch to the scoped DB.)
- Should food + blood sugar share one val (single DB) or live in separate vals with their own scoped DBs? (Decide before migrating.)
- How much sample data should we ship when people fork the val—full history or a trimmed seed week?
