mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
The running status line now carries its seconds right after the text, in the line's own muted tone, instead of at the far edge of the column. The live count and every finished round read "4 s", the same spacing as the settled summary, with a no-break space so a round never wraps between number and unit. Reply pills (follow-ups, clarifying choices, memory and plan decisions) sit directly under the answer, and the action row is the last thing in the column. Beside a pointer the row stays invisible until hover or focus; above the pills it left an empty band between an answer and its replies. Hovering or focusing the message still reveals the row without moving anything. Keyboard focus in the Coach panel is a solid ring in the neutral text-field focus tone, never the purple ring: the pills, Undo and Change merge it over the button primitive, and the hand-built controls carry it directly. A structural test keeps the purple ring out of the panel. A disabled native select now looks disabled, like Input and Select, so a thinking depth locked by the operator no longer reads as a live choice. In Settings, thinking depth takes the shape of Tone and Reply length beside it; a memory entry's Forget is an icon like its edit; the operator's highest-depth label sits on the switches' left edge.
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.