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:
@@ -4,8 +4,7 @@ import { z } from 'zod';
|
||||
import { withAuth, withPermission } from '@/lib/api/helpers';
|
||||
import { parseBody } from '@/lib/api/route-helpers';
|
||||
import { errorResponse, ValidationError } from '@/lib/errors';
|
||||
import { minioClient } from '@/lib/minio';
|
||||
import { env } from '@/lib/env';
|
||||
import { getStorageBackend } from '@/lib/storage';
|
||||
|
||||
const renameFolderSchema = z.object({
|
||||
newPath: z.string().min(1).max(500),
|
||||
@@ -38,11 +37,14 @@ export const PATCH = withAuth(
|
||||
const oldKey = `${ctx.portSlug}/${safeCurrent}${safeCurrent.endsWith('/') ? '' : '/'}`;
|
||||
const newKey = `${ctx.portSlug}/${safeNew}${safeNew.endsWith('/') ? '' : '/'}`;
|
||||
|
||||
// Create new marker, remove old
|
||||
await minioClient.putObject(env.MINIO_BUCKET, newKey, Buffer.alloc(0), 0, {
|
||||
'Content-Type': 'application/x-directory',
|
||||
// Create new marker, remove old. Routed through the active backend
|
||||
// so filesystem mode doesn't crash.
|
||||
const backend = await getStorageBackend();
|
||||
await backend.put(newKey, Buffer.alloc(0), {
|
||||
contentType: 'application/x-directory',
|
||||
sizeBytes: 0,
|
||||
});
|
||||
await minioClient.removeObject(env.MINIO_BUCKET, oldKey);
|
||||
await backend.delete(oldKey);
|
||||
|
||||
return NextResponse.json({ data: { path: newKey } });
|
||||
} catch (error) {
|
||||
@@ -65,7 +67,7 @@ export const DELETE = withAuth(
|
||||
}
|
||||
|
||||
const folderKey = `${ctx.portSlug}/${safePath}${safePath.endsWith('/') ? '' : '/'}`;
|
||||
await minioClient.removeObject(env.MINIO_BUCKET, folderKey);
|
||||
await (await getStorageBackend()).delete(folderKey);
|
||||
|
||||
return new NextResponse(null, { status: 204 });
|
||||
} catch (error) {
|
||||
|
||||
@@ -4,8 +4,7 @@ import { z } from 'zod';
|
||||
import { withAuth, withPermission } from '@/lib/api/helpers';
|
||||
import { parseBody } from '@/lib/api/route-helpers';
|
||||
import { errorResponse, ValidationError } from '@/lib/errors';
|
||||
import { minioClient } from '@/lib/minio';
|
||||
import { env } from '@/lib/env';
|
||||
import { getStorageBackend } from '@/lib/storage';
|
||||
|
||||
const createFolderSchema = z.object({
|
||||
path: z.string().min(1).max(500),
|
||||
@@ -29,9 +28,16 @@ export const POST = withAuth(
|
||||
|
||||
const folderKey = `${ctx.portSlug}/${safePath}${safePath.endsWith('/') ? '' : '/'}`;
|
||||
|
||||
// Create zero-byte marker object in MinIO
|
||||
await minioClient.putObject(env.MINIO_BUCKET, folderKey, Buffer.alloc(0), 0, {
|
||||
'Content-Type': 'application/x-directory',
|
||||
// Zero-byte marker through the active storage backend. S3 stores it
|
||||
// as an empty object; the filesystem backend currently materializes
|
||||
// it as an empty file (a future refactor should move folder
|
||||
// bookkeeping to a DB-backed virtual-folder table — see
|
||||
// docs/audit-comprehensive-2026-05-05.md HIGH §3 follow-up).
|
||||
await (
|
||||
await getStorageBackend()
|
||||
).put(folderKey, Buffer.alloc(0), {
|
||||
contentType: 'application/x-directory',
|
||||
sizeBytes: 0,
|
||||
});
|
||||
|
||||
return NextResponse.json({ data: { path: folderKey } }, { status: 201 });
|
||||
|
||||
Reference in New Issue
Block a user