feat(sharing): open the lab and clinical-record reads to a delegate

Ten routes: lab results and their detail, the biomarker catalogue and its
detail, allergies, family history, the mental-health screener history, and
the health-profile facts. All GET arms; every write arm in the same files
keeps `requireAuth()` and refuses under a switch.

The family-history payload is the one admitted read that carries third-party
health information by design — it describes the owner's relatives — and it is
admitted because a caregiver reading a family history is what the feature is
for and the rows are the owner's own.

The mental-health module gate resolves against the record, not the caller.
That is the recorded decision: the module map says which parts of a record
exist, so a delegate who enabled the screener on their own account gains no
screener view inside somebody else's. The integration test asserts both
directions.
This commit is contained in:
Marc-André Bombeck committed 2026-08-02 16:38:39 +02:00
1 parent 255cbf5fe0
commit af0f749740
13 files changed
+416 -21

No files matched your search

+2 -2
View File
@@ -12,7 +12,7 @@
import { NextRequest } from "next/server";
import { prisma } from "@/lib/db";
import { apiHandler, requireAuth } from "@/lib/api-handler";
import { apiHandler, requireAuth, requireRecordAuth } from "@/lib/api-handler";
import { annotate } from "@/lib/logging/context";
import { auditLog } from "@/lib/auth/audit";
import {
@@ -31,7 +31,7 @@ type RouteParams = { params: Promise<{ id: string }> };
export const GET = apiHandler(
async (request: NextRequest, { params }: RouteParams) => {
const { user } = await requireAuth();
const { user } = await requireRecordAuth("read");
const { id } = await params;
const row = await prisma.allergy.findUnique({ where: { id } });
+2 -2
View File
@@ -11,7 +11,7 @@
import { NextRequest } from "next/server";
import { prisma } from "@/lib/db";
import { apiHandler, requireAuth } from "@/lib/api-handler";
import { apiHandler, requireAuth, requireRecordAuth } from "@/lib/api-handler";
import { annotate } from "@/lib/logging/context";
import { auditLog } from "@/lib/auth/audit";
import {
@@ -29,7 +29,7 @@ import {
import { toAllergyDTO } from "@/lib/records/dto";
export const GET = apiHandler(async (request: NextRequest) => {
const { user } = await requireAuth();
const { user } = await requireRecordAuth("read");
const params = new URL(request.url).searchParams;
const parsed = allergyListQuerySchema.safeParse({