mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Closing a card-opened document asks the browser to go back, so the entry the selection pushed is consumed and the reader's next Back reaches the page before it. A traversal is a request, not a guarantee: one asked for while another is still settling can be dropped, and nothing raises when it is. The sheet closes, React stays consistent, and the address bar goes on naming a document nobody has open, so a reload or a shared link re-opens the sheet that was just closed. Pressing Escape straight after the browser's Forward button is exactly that shape, and it reproduces: ten repeats across both viewports failed two of twenty with the URL still carrying the id, and none of twenty once the close verifies itself. The check is guarded by the document id, so a traversal that landed on a different selection is left alone, and it is cancelled the moment the sheet re-opens. The browser test that found it could not say so. It asserted the sheet was closed through a locator matched on the document TITLE, and the sheet falls back to an untitled label while its detail read is pending, so the assertion also passed on an open sheet showing a skeleton, resolved immediately instead of waiting, and pushed the failure into a URL poll ten seconds later. It now asserts the dialog role, which is what the neighbouring deep-link test already does.
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.