feat: add per-patient Local folder in Documents page backed by Cloud Storage

- Documents page shows a "Local Folder" card for each selected patient
  with an "Open in Cloud Storage" button that deep-links to their folder
- Cloud Storage page reads ?folderId URL param on mount and auto-opens
  the folder panel for seamless navigation from Documents
- Backend: GET /api/cloud-storage/patient-folder/:patientId endpoint
  that idempotently gets or creates a top-level CloudFolder per patient
- CloudFolder schema gains optional patientId field linked to Patient
- Disk directories for cloud storage folders now use the folder's name
  (e.g. "Xiaohui Wang/") instead of the opaque "folder-{id}/" path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ff
2026-06-05 23:01:56 -04:00
parent 2457e12b5c
commit d5bc96ff39
158 changed files with 1539 additions and 130 deletions

View File

@@ -2,6 +2,7 @@ import express, { Request, Response } from "express";
import storage from "../storage";
import { serializeFile } from "../utils/prismaFileUtils";
import { CloudFolder } from "@repo/db/types";
import { prisma as db } from "@repo/db/client";
const router = express.Router();
@@ -133,6 +134,35 @@ router.get(
}
);
// ---------- Patient-dedicated folder (get or create) ----------
// GET /patient-folder/:patientId?userId=XXX
router.get(
"/patient-folder/:patientId",
async (req: Request, res: Response): Promise<any> => {
const patientId = Number.parseInt(req.params.patientId ?? "", 10);
const userId = Number.parseInt(String(req.query.userId ?? ""), 10);
if (!Number.isInteger(patientId) || patientId <= 0)
return sendError(res, 400, "Invalid patientId");
if (!Number.isInteger(userId) || userId <= 0)
return sendError(res, 400, "Missing or invalid userId");
try {
const patient = await db.patient.findUnique({
where: { id: patientId },
select: { firstName: true, lastName: true },
});
if (!patient) return sendError(res, 404, "Patient not found");
const patientName = `${patient.firstName} ${patient.lastName}`.trim();
const folder = await storage.getOrCreatePatientFolder(userId, patientId, patientName);
return res.json({ error: false, data: folder });
} catch (err) {
return sendError(res, 500, "Failed to get or create patient folder", err);
}
}
);
// ---------- Folder CRUD ----------
router.get(
"/folders/:id",