feat: save insurance PDFs (eligibility/claims/preauth) to Cloud Storage instead of Postgres blobs
New saves go into the patient's Cloud Storage folder under category subfolders (Eligibility/Claims/PreAuth/Claim Status/Attachments) via a new storage.savePdfToCloudStorage helper, instead of the legacy PdfGroup/PdfFile Postgres blob tables. Old records and their read paths are left untouched for backward compatibility; PDF list/content/delete endpoints and viewers now transparently handle both legacy numeric ids and new "cloud:<id>" ids. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -143,6 +143,24 @@ export interface IStorage {
|
||||
patientId: number,
|
||||
patientName: string
|
||||
): Promise<CloudFolder>;
|
||||
getOrCreateSubfolder(
|
||||
userId: number,
|
||||
parentId: number,
|
||||
name: string
|
||||
): Promise<CloudFolder>;
|
||||
savePdfToCloudStorage(
|
||||
userId: number,
|
||||
patientId: number,
|
||||
patientName: string,
|
||||
category: "Eligibility" | "Claims" | "PreAuth" | "Claim Status" | "Attachments",
|
||||
filename: string,
|
||||
buffer: Buffer,
|
||||
mimeType?: string
|
||||
): Promise<CloudFile>;
|
||||
listPatientCategoryCloudFiles(
|
||||
patientId: number,
|
||||
category: string
|
||||
): Promise<CloudFile[]>;
|
||||
}
|
||||
|
||||
/* ------------------------------- Implementation ------------------------------- */
|
||||
@@ -546,6 +564,82 @@ export const cloudStorageStorage: IStorage = {
|
||||
return created as unknown as CloudFolder;
|
||||
},
|
||||
|
||||
async getOrCreateSubfolder(userId: number, parentId: number, name: string) {
|
||||
const existing = await db.cloudFolder.findFirst({
|
||||
where: { parentId, name },
|
||||
});
|
||||
if (existing) return existing as unknown as CloudFolder;
|
||||
|
||||
try {
|
||||
return await cloudStorageStorage.createFolder(userId, name, parentId);
|
||||
} catch (err: any) {
|
||||
// unique constraint on [userId, parentId, name] - another request created it first
|
||||
if (err?.code === "P2002") {
|
||||
const race = await db.cloudFolder.findFirst({ where: { parentId, name } });
|
||||
if (race) return race as unknown as CloudFolder;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
async savePdfToCloudStorage(
|
||||
userId: number,
|
||||
patientId: number,
|
||||
patientName: string,
|
||||
category: "Eligibility" | "Claims" | "PreAuth" | "Claim Status" | "Attachments",
|
||||
filename: string,
|
||||
buffer: Buffer,
|
||||
mimeType: string = "application/pdf"
|
||||
) {
|
||||
const patientFolder = await cloudStorageStorage.getOrCreatePatientFolder(
|
||||
userId,
|
||||
patientId,
|
||||
patientName
|
||||
);
|
||||
const subfolder = await cloudStorageStorage.getOrCreateSubfolder(
|
||||
userId,
|
||||
patientFolder.id!,
|
||||
category
|
||||
);
|
||||
const cloudFile = await cloudStorageStorage.initializeFileUpload(
|
||||
userId,
|
||||
filename,
|
||||
mimeType,
|
||||
BigInt(buffer.length),
|
||||
1,
|
||||
subfolder.id!
|
||||
);
|
||||
await cloudStorageStorage.appendFileChunk(cloudFile.id!, 0, buffer);
|
||||
await cloudStorageStorage.finalizeFileUpload(cloudFile.id!);
|
||||
const finalFile = await cloudStorageStorage.getFile(cloudFile.id!);
|
||||
if (!finalFile) throw new Error("Failed to finalize PDF upload to cloud storage");
|
||||
return finalFile;
|
||||
},
|
||||
|
||||
async listPatientCategoryCloudFiles(patientId: number, category: string) {
|
||||
const patientFolder = await db.cloudFolder.findFirst({ where: { patientId } });
|
||||
if (!patientFolder) return [];
|
||||
const subfolder = await db.cloudFolder.findFirst({
|
||||
where: { parentId: patientFolder.id, name: category },
|
||||
});
|
||||
if (!subfolder) return [];
|
||||
const files = await db.cloudFile.findMany({
|
||||
where: { folderId: subfolder.id, isComplete: true },
|
||||
orderBy: { createdAt: "desc" },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
mimeType: true,
|
||||
fileSize: true,
|
||||
folderId: true,
|
||||
isComplete: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
},
|
||||
});
|
||||
return files.map(serializeFile) as unknown as CloudFile[];
|
||||
},
|
||||
|
||||
// --- STREAM ---
|
||||
async streamFileTo(resStream: NodeJS.WritableStream, fileId: number) {
|
||||
const file = await db.cloudFile.findUnique({
|
||||
|
||||
Reference in New Issue
Block a user