diff --git a/Dockerfile b/Dockerfile index 0647e74..37e9af4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,5 +34,9 @@ USER app EXPOSE 3000 ENV PORT=3000 HOSTNAME=0.0.0.0 +# Must match the volume mount in docker-compose.yml. Without this, uploads +# default to `$cwd/data/uploads` (i.e. /app/data/uploads here) — not the +# persisted volume — so files vanish on every container restart/redeploy. +ENV UPLOAD_DIR=/data/uploads ENTRYPOINT ["sh", "./docker-entrypoint.sh"] diff --git a/src/app/api/materials/[id]/file/route.ts b/src/app/api/materials/[id]/file/route.ts index 81b1bff..bc519a6 100644 --- a/src/app/api/materials/[id]/file/route.ts +++ b/src/app/api/materials/[id]/file/route.ts @@ -19,7 +19,16 @@ export async function GET( return new Response("Not found", { status: 404 }) } - const size = row.sizeBytes ?? (await fileSize(row.storagePath)) + // Confirm the file actually exists on disk before streaming: if it's + // missing (e.g. storage misconfiguration), fail fast with a clean 404 + // instead of erroring mid-stream, which surfaces to clients as a broken + // connection / 502 through the reverse proxy. + let size: number + try { + size = await fileSize(row.storagePath) + } catch { + return new Response("Not found", { status: 404 }) + } // Re-sanitize at serve time so rows created before the upload-side // sanitization can't serve active content either. const mime = safeInlineMime(row.mimeType)