mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
These four were the only connected providers with no way to ask for a sync; they ran on their scheduled pass and nothing else. Each gets a POST sync route on the hardened Fitbit and Google Health template: session auth, a 5-per-minute per-user bucket, and a fixed 502 on failure. No body and no full-sync flag, because none of the four entry points has a full-history arm to call. Polar goes through the shared legs entry point so both legs run with the attribution rules built for them. The Nightscout error arm is the one that matters: a base URL carries the API token as a query parameter, so the caught message can hold the user's secret and never reaches the response body. The classified failure is already on the ledger, recorded with the provider's own redaction. Connecting also starts the first sync now. The poll handler has accepted a single-user payload since it was written and never had a producer, so a fresh connection sat empty for up to an hour waiting for the schedule. The Oura and Polar callbacks and the Nightscout connect route enqueue one targeted job each, best effort, with the hourly tick still the safety net. Strava needs none: its callback already enqueues the history backfill, which covers the recent window. The four poll-queue names move into their own module so a request-path caller can name a queue without dragging the whole worker handler graph into the request bundle, following the backfill-queue precedent. Creation, scheduling and handler binding stay in the registrar, and the dead-queue guard follows the declarations.
src/
Application source. HealthLog is a Next.js 16 App Router project (output: "standalone", React 19, TypeScript strict). The path alias @/* resolves to this directory. Everything a request touches lives under here; the layout below follows the request flow rather than alphabetical order.
Request flow
client → src/proxy.ts → src/app/<route>/route.ts → src/lib/api-handler.ts → handler body → src/lib/api-response.ts → client
proxy.ts— the HTTP edge (Next.js 16's renamedmiddleware). Public-path allowlist, demo-mode mutation block, server-side onboarding redirect, worker-only refusal,x-request-id+ CSP nonce generation, every security header.app/— App Router pages (RSC by default) and API routes. Every API route wraps its handler inapiHandler. Seeapp/README.md.lib/— the server/runtime toolkit:apiHandler, auth, crypto, rollups, AI, notifications, pg-boss jobs, integrations, rate limiting. Seelib/README.md.components/— React components (shadcn/ui new-york, kebab-case files). Seecomponents/README.md.
Other directories
hooks/— shared React hooks (use-prefix, kebab-case).types/— shared TypeScript declarations.generated/prisma/— the generated Prisma client (do not edit; regenerated byprisma generate). Imported as@/generated/prisma.instrumentation.ts— Next.js startup hook; boots the pg-boss worker registry and boot-time backfill queues.__tests__/— cross-cutting unit tests; most tests live in__tests__/folders next to the code they cover.
Conventions
See ../CLAUDE.md for the full set. The load-bearing ones: RSC by default ("use client" only when a hook/state/browser API needs it); every API route wraps apiHandler and parses its body with Zod safeParse; userId is always narrowed from session or Bearer, never accepted as a body field; TanStack Query keys come only from src/lib/query-keys/; outbound HTTP goes through src/lib/safe-fetch.ts.