Skip to content

Pilates tracker — design

owner: Trunks (researcher) + Squidward (UI)retire_after: 2026-09-23

What

Monitor Pilates classes at Dulwich Leisure Centre via authenticated GladstoneGO scraping. Surface availability + my-bookings in a 30-day interactive calendar in Hinata Studio. Self-decommissions when Michael's membership ends on 2026-09-23.

Architecture

pilates-researcher (Sandpit)
  - reads itachi:pilates_key.json
  - curl_cffi login + cookie cache
  - 30-day timetable scrape
  - my-bookings scrape
  - JSONL append-only lake (local)
  - diff vs previous → Telegram
  - POST → /api/pilates/sync

Hinata Studio API + D1
  - GET  /api/pilates/calendar
  - PUT  /api/pilates/instance/:id
  - POST /api/pilates/sync
  - D1 table: pilates_instances
  - enabled is user-owned (never overwritten on sync)

PilatesCalendar.tsx
  - 30-day grid, rows = class slots, columns = dates
  - 4-state palette. Click cell → toggle red ↔ grey.

4-state colour rule

StateColourPredicate

cancelledred stripedstatus === 'cancelled'bookedgreenbooked === truedisabledred 55% opacityenabled === false OR (date < today AND not booked) availableyellowspaces > 0 AND enabled AND not booked monitoringgreydefault — enabled, polling, no spaces yet

Telegram policy

Per feedback_telegram_only_on_breakage — pings ONLY:

  1. 0 spots → N spots transition on an enabled, unbooked slot (book now)

  2. 3 consecutive non-zero exits from run-scheduled.sh (real breakage)

  3. Retirement boot (one-time goodbye on 2026-09-24+)

Retirement (2026-09-23)

On 2026-09-24+: run.py writes .retired sentinel, fires one Telegram goodbye. run-scheduled.sh short-circuits all subsequent fires. PilatesCalendar.tsx checks isPilatesActive() → renders a retirement card instead of the grid.

◆ hinata · projects/hinata-architecture/pilates-tracker.html · phase-19 conversion