Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ HEALTH_DEEP_PROBE_SECRET=your-long-random-health-deep-probe-secret
#NEXT_PUBLIC_LOCAL_NO_AUTH=false
#LOCAL_NO_AUTH=false

# Optional local no-auth owner identity. Set one of these in local dev.
#LOCAL_NO_AUTH_OWNER_ID=
# Optional local no-auth owner identity for private document/maintenance workflows.
# The reviewed Forms/Services catalogue is shared application content and does
# not require either value; local and authenticated users receive it automatically.
#LOCAL_NO_AUTH_OWNER_ID=00000000-0000-4000-8000-000000000000
#LOCAL_NO_AUTH_OWNER_EMAIL=

# OpenAI direct API. This app sends extracted guideline text and extracted images
Expand Down
2,898 changes: 2,898 additions & 0 deletions data/forms-catalog.json

Large diffs are not rendered by default.

6,685 changes: 6,685 additions & 0 deletions data/forms-page-snapshot.json

Large diffs are not rendered by default.

414 changes: 414 additions & 0 deletions data/forms-pdf-manifest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,4 +568,5 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD
| 2026-07-17 | codex/pwa-privacy-safe-20260717 | 35fa8c929d44a9bd84b3f7f2b795354d3b6dae02 | privacy-safe PWA shell and merge-readiness review | No remaining high-confidence product defect in the changed scope. The pre-push browser gate found and fixed one P2 test defect: cleanup referenced `PWA_CACHE_PREFIX` without passing it into the browser context, and the cold installability flow now has a focused 120-second budget. The worker caches only the generic offline page and allow-listed public shell assets; navigations, APIs, auth, queries, documents, uploads, signed URLs, range requests, and cross-origin traffic remain network-only. | Current-main integration; focused Vitest 81/81; full uncached ESLint; TypeScript; scoped Prettier and diff checks; production Webpack build generated 1,043 pages and the client-bundle secret scan passed; full Vitest produced 2,506 passes plus six contention timeouts, with all affected files passing 24/24 serially; focused Chromium PWA 2/2. No Supabase/OpenAI/live-provider checks run. |
| 2026-07-17 | codex/historical-branch-cleanup-20260717 | e36ac0c6628264c7ed6c494a597a62d0214b68f6 | branch-cleanup and historical-content recovery | Completed the pending historical cleanup: deleted 55 exact-SHA remote refs and 20 redundant local refs, removed nine clean merged worktrees, preserved every dirty, active, open-PR, or patch-unique worktree, and recovered the still-useful governance incident runbook from `codex/domain-1-governance-remediation`. Historical code changes were either tied to merged PRs or reviewed as superseded by current implementations; open PRs #699, #700, #702, and #704 remain protected. | Fresh `git fetch --prune`; GitHub PR inventory and exact commit-to-merged-PR associations; exact remote SHA rechecks before deletion; cherry-pick-aware logs; two-dot tree and branch-only-file review; Codex task-to-worktree cross-check; focused documentation validation recorded in the cleanup PR. No OpenAI, Supabase, production-data, or live clinical workflow was run. |
| 2026-07-17 | PR #704 / codex/scroll-geometry-stability-20260717 | 35e74ddbd61bacc5b34f06efbd58091f092665fd | nested scroll-source review follow-up | Confirmed the outside-diff CodeRabbit finding: the standalone shell shared one intent history across main and descendant scroll containers, so a switch from a deep main offset to a near-zero nested offset could falsely reveal chrome. Scroll metrics now identify their source, source changes rebase direction and travel while preserving visibility, and unit/UI regressions cover the switch. No unresolved actionable review finding remains. | Focused Vitest 9/9; TypeScript; scoped ESLint; Prettier; `git diff --check`. Exact-head hosted CI and UI remain required after push. No Supabase/OpenAI/live-provider checks run. |
| 2026-07-17 | codex/chat-forms-import-6914 | e5caaa46cad5fb9a937f1dc43312723799b98abb + working-tree diff | shared Forms/Services catalogue access and LOCAL_NO_AUTH_OWNER_ID review | Fixed one P1 availability/design defect: authenticated reads materialized a private copy of the shared catalogue on first access, creating drift, unnecessary writes, and possible registry-corpus side effects. Forms/Services now merge the reviewed shared baseline with private owner overrides for list, detail, and universal search; older partial overrides retain missing shared metadata; no registry GET seeds or embeds. Private rows and linked documents remain owner-scoped. The ignored local owner setting was corrected to the verified sole live-owner UUID and source validation now requires a UUID. No remaining high-confidence defect in scope. | Focused registry/universal Vitest initially exposed four local expectation/count mismatches; corrected registry suite passed 17/17 and registry/logging suite passed 23/23. Full TypeScript passed. `verify:cheap` passed runtime, action pins, sitemap, brand, type/icon/function guards, full lint, and TypeScript; full Vitest reached 2,588 passing with one stale logging-guard failure, which was fixed and focused-verified. The final full-suite rerun was terminated by the 5-minute host timeout without a reported assertion failure. `git diff --check` passed. No Supabase/OpenAI/provider call or schema/RLS mutation was run for this review. |
| 2026-07-17 | codex/scrolling-cleanup-20260717 | ff77cd06c + latest origin/main sync | cross-page scrolling and interaction stability review | Fixed two confirmed P2 defects: desktop action-popup placement performed synchronous geometry work for every captured scroll event, and submitted differential searches with zero document matches fell back to the home state. Placement is now coalesced per animation frame with passive scroll listeners, and submitted empty-evidence results remain visible. Hardened three popup/navigation browser helpers that reproduced hydration timing failures. No other high-confidence defect remains in the scoped diff. | Scroll-focused Chromium 28/28; final affected Chromium 5/5; source regressions 2/2; scoped ESLint; Prettier; TypeScript and production build passed before the final upstream-only sync; `git diff --check`. The aggregate local Vitest/UI runs were affected by concurrent-worktree resource contention, so exact-head hosted CI remains required before merge. No Supabase/OpenAI/live-provider checks run. |
2 changes: 1 addition & 1 deletion docs/codebase-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Structured map for AI agents and onboarding. For live routes, see `docs/site-map

| Module | Role |
| -------------------------------------------------------------------- | ------------------------------------------------------- |
| `differentials.ts`, `forms.ts`, `services.ts`, `registry-records.ts` | Registry-backed content |
| `differentials.ts`, `forms.ts`, `services.ts`, `registry-records.ts` | Shared catalogue content with optional owner overrides |
| `dsm.ts` | Local DSM diagnosis catalogue and comparison helpers |
| `formulation.ts` | Local formulation mechanism library and builder helpers |
| `clinical-safety.ts`, `demo-data.ts`, `ui-copy.ts` | Safety copy and demo mode |
Expand Down
17 changes: 12 additions & 5 deletions docs/multi-user-auth-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ changed automatically by repo commits. Target project: `Clinical KB Database`

## 2. Auth → Sign in / Providers → "Allow new users to sign up"

- Turn **ON** (open public signup, per decision). Each new account starts as an
empty private silo — a new user cannot see anyone else's data.
- Turn **ON** (open public signup, per decision). Each new account starts with
an empty private document/search silo and the complete reviewed shared
Forms/Services catalogue. A user cannot see another user's private data or
registry overrides.

## 3. Auth → URL Configuration

Expand Down Expand Up @@ -76,7 +78,10 @@ project**, so no broad RLS migration is required:
owner-read policy: `owner_id = (select auth.uid())`.
- Registry tables (`clinical_registry_records`, `_sources`) and internal tables
(`api_rate_limits`, `audit_logs`, `rag_response_cache`) are RLS-enabled and
**service-role-only** (fully server-mediated — intentional).
**service-role-only** (fully server-mediated — intentional). The application
merges private owner overrides over the reviewed in-repo Forms/Services
catalogue, so every user receives the shared baseline without per-user seed
writes or cross-tenant reads.
- Both storage buckets (`clinical-documents`, `clinical-images`) are **private**;
file access is via server-minted signed URLs after an owner check. No direct
client storage access is enabled (so no per-user folder policy is needed unless
Expand All @@ -102,5 +107,7 @@ to launch):**
2. **Magic link** → email link → signed in.
3. **Google** and **Microsoft** SSO → signed in.
4. **Hard-refresh** the page → still signed in (persistent cookie session).
5. **Isolation:** sign in as user A, upload a document, sign out; sign in as
user B → B sees none of A's documents, registry, or search results.
5. **Isolation and shared content:** sign in as user A, upload a document and
create a private registry override, then sign out; sign in as user B → B sees
none of A's document or override data, but both users see the complete shared
Forms/Services catalogue.
50 changes: 50 additions & 0 deletions docs/site-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,56 @@ This file is generated by `npm run sitemap:update`. Run `npm run sitemap:check`
- `/forms/[slug]` - Dynamic route family.
- `detention-examination-movement`
- `extension-transport-order`
- `form-10a`
- `form-10b`
- `form-10c`
- `form-10d`
- `form-10e`
- `form-10f`
- `form-10g`
- `form-10h`
- `form-10i`
- `form-11a`
- `form-11b`
- `form-11c`
- `form-11d`
- `form-11e`
- `form-11f`
- `form-11g`
- `form-12a`
- `form-12b`
- `form-12c`
- `form-12c-attachment`
- `form-13`
- `form-1a`
- `form-1a-attachment`
- `form-1b`
- `form-2`
- `form-3b`
- `form-3c`
- `form-3d`
- `form-3e`
- `form-4d`
- `form-4e`
- `form-5a`
- `form-5b`
- `form-5c`
- `form-5d`
- `form-5e`
- `form-5f`
- `form-6a`
- `form-6b`
- `form-6b-attachment`
- `form-6c`
- `form-6d`
- `form-7a`
- `form-7b`
- `form-7c`
- `form-7d`
- `form-8a`
- `form-8b`
- `form-9a`
- `form-9b`
- `transfer-order`
- `transport-crisis-form`

Expand Down
Binary file added public/forms-pdf/form-10a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10e.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10f.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10g.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10h.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-10i.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11e.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11f.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-11g.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-12a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-12b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-12c-attachment.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-12c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-1a-attachment.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-1a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-1b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-2.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-3a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-3b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-3c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-3d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-3e.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-4a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-4b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-4c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5e.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-5f.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-6a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-6b-attachment.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-6b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-6c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-6d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-7a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-7b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-7c.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-7d.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-8a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-8b.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-9a.pdf
Binary file not shown.
Binary file added public/forms-pdf/form-9b.pdf
Binary file not shown.
37 changes: 8 additions & 29 deletions src/app/api/registry/records/[slug]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ import {
} from "@/lib/api-rate-limit";
import { isDemoMode, isLocalNoAuthMode } from "@/lib/env";
import { jsonError } from "@/lib/http";
import { safeErrorLogDetails } from "@/lib/privacy";
import { publicAccessContext } from "@/lib/public-api-access";
import { getFormRecord } from "@/lib/forms";
import {
deriveGovernanceColumns,
normalizeRegistrySlug,
rowGovernance,
rowToServiceRecord,
type RegistryRecordRow,
} from "@/lib/registry-records";
import { ensureRegistrySeeded } from "@/lib/registry-seed";
import { mergeRegistryRecordWithDefault } from "@/lib/registry-seed";
import { getServiceRecord } from "@/lib/services";
import { createAdminClient } from "@/lib/supabase/admin";
import { AuthenticationError, unauthorizedResponse } from "@/lib/supabase/auth";
Expand Down Expand Up @@ -104,33 +102,12 @@ export async function GET(request: Request, context: { params: Promise<{ slug: s
return (data as RegistryRecordRow | null) ?? null;
};

let row = await fetchRecord();
const row = await fetchRecord();
if (!row) {
// A new owner may deep-link a default record (e.g. a saved favourite)
// before ever loading the Services/Forms home list that seeds them. If
// this owner has no records of this kind at all, lazily seed the curated
// defaults and retry once. Non-fatal — fall through to 404 on failure.
const { count, error: countError } = await supabase
.from("clinical_registry_records")
.select("id", { count: "exact", head: true })
.eq("owner_id", access.ownerId)
.eq("kind", kind);
if (countError) throw new Error(countError.message);
if ((count ?? 0) === 0) {
// Only the seed write is best-effort; the re-read stays outside the try
// so a genuine read failure surfaces rather than a misleading 404.
let seedError: unknown = null;
try {
await ensureRegistrySeeded(supabase, access.ownerId, kind);
} catch (error) {
seedError = error;
console.error("[registry] auto-seed failed", { kind, ...safeErrorLogDetails(error) });
}
row = await fetchRecord();
if (!row && seedError) throw seedError;
}
const payload = publicRegistryDetailPayload(kind, normalizedSlug);
if (!payload) return notFoundResponse(normalizedSlug);
return registryResponse({ ...payload, sharedCatalog: true });
}
if (!row) return notFoundResponse(normalizedSlug);

const { data: links, error: linksError } = await supabase
.from("clinical_registry_record_sources")
Expand All @@ -151,8 +128,10 @@ export async function GET(request: Request, context: { params: Promise<{ slug: s
linkedDocuments = (documents ?? []) as typeof linkedDocuments;
}

const record = mergeRegistryRecordWithDefault(kind, row);

return registryResponse({
record: rowToServiceRecord(row),
record,
governance: rowGovernance(row),
linkedDocuments,
});
Expand Down
19 changes: 9 additions & 10 deletions src/app/api/registry/records/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import { isDemoMode, isLocalNoAuthMode } from "@/lib/env";
import { jsonError } from "@/lib/http";
import { publicAccessContext } from "@/lib/public-api-access";
import { rankFormRecords, formRecords } from "@/lib/forms";
import { deriveGovernanceColumns, type RegistryRecordKind } from "@/lib/registry-records";
import {
deriveGovernanceColumns,
rowGovernance,
rowToServiceRecord,
type RegistryRecordKind,
} from "@/lib/registry-records";
import { fetchOwnerRegistryRowsWithSeed } from "@/lib/registry-seed";
fetchOwnerRegistryRows,
mergeRegistryGovernanceWithDefaults,
mergeRegistryRecordsWithDefaults,
} from "@/lib/registry-seed";
import { rankServiceRecords, serviceRecords, type ServiceRecord, type ServiceSearchMatch } from "@/lib/services";
import { createAdminClient } from "@/lib/supabase/admin";
import { AuthenticationError, unauthorizedResponse } from "@/lib/supabase/auth";
Expand Down Expand Up @@ -104,14 +103,14 @@ export async function GET(request: Request) {
});
}

const rows = await fetchOwnerRegistryRowsWithSeed(supabase, access.ownerId, kind, REGISTRY_MAX_RECORDS);
const records = rows.map(rowToServiceRecord);
const governanceBySlug = Object.fromEntries(rows.map((row) => [row.slug, rowGovernance(row)]));
const rows = await fetchOwnerRegistryRows(supabase, access.ownerId, kind, REGISTRY_MAX_RECORDS);
const records = mergeRegistryRecordsWithDefaults(kind, rows);
const governanceBySlug = mergeRegistryGovernanceWithDefaults(kind, rows);

return registryResponse({
records,
matches: q ? matchesPayload(rankRecords(kind, records, q, limit)) : undefined,
total: rows.length,
total: records.length,
governance: governanceBySlug,
});
} catch (error) {
Expand Down
Loading