Appearance
jimmy-vps /events endpoint — deploy spec (SHIPPED)
project: hinata-infrastructuretype: deploy-specstatus: shippedshipped: 2026-05-26 20:30 (server + tunnel) · 20:48 (Studio Worker proxy) End-to-end live as of 2026-05-26. Studio Worker /api/events → CF Tunnel → api.michael-engineer.dev → FastAPI on jimmy-vps. ActivityLog renders the table.
Reality corrections (5 deltas this deploy uncovered)
Database name:
hinata(NOThinata_collector). Football lives in thefootball.schema inside the same DB; events lives inpublic.events.DB access: synchronous psycopg via
from db import get_conn(NOT asyncpg).with get_conn() as conn, conn.cursor() as cur:thencur.execute(...).Auth header:
x-hinata-keyenforced server-side per router viafrom auth import require_key(NOTAuthorization: Bearer). All sibling tenants use the same header.Router shape: bare
router = APIRouter()with no prefix in-file. Prefix applied atapp.include_router(events.router, prefix="/events", tags=["events"])in main.py.Token storage:
hinata_collector_api_key.json(NOT.md). The 43-char token lives in thevaluefield.
Final shipped artifacts
ArtifactPathRole
Install script~/Sandpit/hinata/scripts/jimmy-vps-add-events-tenant.shidempotent: schema + router + main.py wire + restart Tunnel install script~/Sandpit/hinata/scripts/jimmy-vps-cloudflared-tunnel-api.shidempotent: cloudflared install + tunnel create + DNS route + systemd service Public hosthttps://api.michael-engineer.devsingle VPS-facing subdomain; all tenants share it Studio Worker proxyapplications/hinata-studio/api/worker/index.ts route /api/eventsholds HINATA_COLLECTOR_KEY as wrangler secret; key never in browser bundle Producer~/Sandpit/hinata/scripts/emit-event.sh``x-hinata-key auth; reads JSON token's value field Consumerapplications/hinata-studio/src/components/ActivityLog.tsxfetches ${VITE_API_URL}/api/events?limit=50
Producer instrumentation
ProducerKind emittedTrigger
poll-monzo.py``monzo.writtennew transactions appended parse-apple-health.py``health.normalisednon-empty inbox parse result calendar-nudge.py``nudge.{pre|start|mid}Telegram nudge fired (per event tag)
Tunnel design — single backend subdomain
Cloudflare Tunnel hinata-collector-api (UUID 67a84c34-3ba0-43d6-ae39-03025a5b1c97) publishes one hostname → localhost:8080. FastAPI multiplexes by path (/events, /football, /musicmastery, /[next]). One DNS record, one ingress rule, all current + future tenants reachable.
Gotchas captured
Itachi token guard:
deploy-studio.commandnow refuses anyCLOUDFLARE_API_TOKENvalue containing whitespace or non-ASCII (the placeholder template string was being exported, em dash breaking wrangler'sAuthorizationheader).wrangler 4 commit-subject header: wrangler auto-reads
git log -1 --format=%sand ships it as a deploy-metadata HTTP header. Latin-1 only. Sandpit commit subjects routinely contain em dashes. Both deploy scripts now pass explicit--commit-message "<ASCII string>"to bypass auto-detection.
◆ hinata · projects/hinata-infrastructure/events-endpoint-deploy.html · phase-19 conversion