mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(doctor-report): wire the doctorReport module toggle to the health-record surface
The doctorReport module toggle was inert: turning it off hid nothing and the server-side export route accepted requests regardless. Gate the live surface on the module — the Health-record settings entry now hides client-side when the module is off, and POST /api/export/health-record refuses with a 403 module.disabled envelope, so the doctor-report surface cannot be reached over a Bearer token either.
This commit is contained in:
1 parent
69fe67e2de
commit
b6db529dee
5 files changed
+46
-2
No files matched your search
@@ -132,6 +132,21 @@ describe("POST /api/export/health-record — validation", () => {
|
||||
expect(res.status).toBe(422);
|
||||
});
|
||||
|
||||
it("returns 403 when the doctorReport module is disabled (B3 gate)", async () => {
|
||||
const { apiError } = await import("@/lib/api-response");
|
||||
vi.mocked(requireModuleEnabled).mockResolvedValue({
|
||||
enabled: false,
|
||||
response: apiError('Module "doctorReport" is not enabled', 403, {
|
||||
errorCode: "module.disabled",
|
||||
module: "doctorReport",
|
||||
}),
|
||||
} as never);
|
||||
const { POST } = await import("../route");
|
||||
const res = await POST(mkReq({ format: "fhir" }));
|
||||
expect(res.status).toBe(403);
|
||||
expect(requireModuleEnabled).toHaveBeenCalledWith("user-1", "doctorReport");
|
||||
});
|
||||
|
||||
it("returns 429 when the export rate limit is exhausted", async () => {
|
||||
vi.mocked(checkRateLimit).mockResolvedValue({
|
||||
allowed: false,
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
safeJson,
|
||||
} from "@/lib/api-response";
|
||||
import { checkRateLimit } from "@/lib/rate-limit";
|
||||
import { requireModuleEnabled } from "@/lib/modules/gate";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { decrypt } from "@/lib/crypto";
|
||||
import {
|
||||
@@ -56,6 +57,13 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
const { user } = await requireAuth();
|
||||
annotate({ action: { name: "export.health-record.build" } });
|
||||
|
||||
// v1.18.0 B3 — the whole doctor-report / health-record surface is the
|
||||
// `doctorReport` module. Refuse with a 403 `module.disabled` envelope when
|
||||
// the account turned it off — even with a valid Bearer token. The settings
|
||||
// entry-point already hides client-side; this is the hard enforcement.
|
||||
const gate = await requireModuleEnabled(user.id, "doctorReport");
|
||||
if (!gate.enabled) return gate.response;
|
||||
|
||||
const rl = await checkRateLimit(`export:${user.id}`, 10, 60 * 60 * 1000);
|
||||
if (!rl.allowed) {
|
||||
return apiError("Maximum 10 exports per hour", 429);
|
||||
|
||||
Reference in new issue
Block a user