fix(storage): route every file op through getStorageBackend()
Removes 12 direct minioClient.{put,get,remove}Object call sites that
bypassed the pluggable storage abstraction. Filesystem-mode deploys
(MULTI_NODE_DEPLOYMENT=false, storage_backend=filesystem) silently
broke at every site: GDPR export, invoice PDF, EOI generation, portal
download, file upload, folder create/rename/delete, signed PDF land,
maintenance cleanup, etc. Each site now resolves the active backend
and uses its put/get/delete + the new presignDownloadUrl() helper.
Folder marker objects in /files/folders/* keep the same on-the-wire
shape but route through the backend. A future refactor should move
folder bookkeeping to a DB-backed virtual-folder table (see audit
HIGH §3 follow-up note in the route file).
Sites left untouched: src/lib/services/system-monitoring.service.ts
and src/app/api/ready/route.ts use minioClient.bucketExists as an S3-
specific health probe — those are correctly mode-aware and stay.
Refs: docs/audit-comprehensive-2026-05-05.md HIGH §3 (auditor-D Issue 1)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,8 @@ import { createAuditLog, type AuditMeta } from '@/lib/audit';
|
||||
import { diffEntity } from '@/lib/entity-diff';
|
||||
import { NotFoundError, ValidationError, ConflictError } from '@/lib/errors';
|
||||
import { emitToRoom } from '@/lib/socket/server';
|
||||
import { minioClient, buildStoragePath } from '@/lib/minio';
|
||||
import { buildStoragePath } from '@/lib/minio';
|
||||
import { getStorageBackend } from '@/lib/storage';
|
||||
import { env } from '@/lib/env';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { evaluateRule } from '@/lib/services/berth-rules-engine';
|
||||
@@ -549,7 +550,7 @@ export async function sendForSigning(documentId: string, portId: string, meta: A
|
||||
const fileRecord = await db.query.files.findFirst({ where: eq(files.id, doc.fileId) });
|
||||
if (!fileRecord) throw new NotFoundError('File');
|
||||
|
||||
const fileStream = await minioClient.getObject(env.MINIO_BUCKET, fileRecord.storagePath);
|
||||
const fileStream = await (await getStorageBackend()).get(fileRecord.storagePath);
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of fileStream) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
@@ -659,8 +660,11 @@ export async function uploadSignedManually(
|
||||
const fileId = crypto.randomUUID();
|
||||
const storagePath = buildStoragePath(port.slug, 'eoi-signed', documentId, fileId, 'pdf');
|
||||
|
||||
await minioClient.putObject(env.MINIO_BUCKET, storagePath, fileData.buffer, fileData.size, {
|
||||
'Content-Type': fileData.mimeType,
|
||||
await (
|
||||
await getStorageBackend()
|
||||
).put(storagePath, fileData.buffer, {
|
||||
contentType: fileData.mimeType,
|
||||
sizeBytes: fileData.size,
|
||||
});
|
||||
|
||||
const [fileRecord] = await db
|
||||
@@ -860,13 +864,12 @@ export async function handleDocumentCompleted(eventData: { documentId: string })
|
||||
const fileId = crypto.randomUUID();
|
||||
const storagePath = buildStoragePath(port.slug, 'eoi-signed', doc.id, fileId, 'pdf');
|
||||
|
||||
await minioClient.putObject(
|
||||
env.MINIO_BUCKET,
|
||||
storagePath,
|
||||
signedPdfBuffer,
|
||||
signedPdfBuffer.length,
|
||||
{ 'Content-Type': 'application/pdf' },
|
||||
);
|
||||
await (
|
||||
await getStorageBackend()
|
||||
).put(storagePath, signedPdfBuffer, {
|
||||
contentType: 'application/pdf',
|
||||
sizeBytes: signedPdfBuffer.length,
|
||||
});
|
||||
|
||||
const [fileRecord] = await db
|
||||
.insert(files)
|
||||
|
||||
Reference in New Issue
Block a user