diff --git a/Dockerfile b/Dockerfile index d7dbc7e4..0dd882ab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,8 +61,14 @@ COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma COPY --from=builder --chown=nextjs:nodejs /app/next.config.* ./ COPY --chmod=755 docker-entrypoint.sh ./docker-entrypoint.sh +# Create uploads directory with proper permissions +RUN mkdir -p /app/uploads && chown nextjs:nodejs /app/uploads + USER nextjs +# Persistent storage for uploaded files +VOLUME ["/app/uploads"] + EXPOSE 3000 CMD ["/app/docker-entrypoint.sh"] \ No newline at end of file diff --git a/QWEN.md b/QWEN.md index c1070959..ec818dd0 100644 --- a/QWEN.md +++ b/QWEN.md @@ -232,42 +232,4 @@ Common issues and solutions: 6. Verify responsive design on different screen sizes ## Qwen Added Memories -- **GitHub Workflow Execution**: Project ini memiliki 3 workflow GitHub Action: -1. `publish.yml` - Build & push Docker image ke GHCR (manual trigger, butuh input: stack_env + tag) -2. `re-pull.yml` - Re-pull Docker image di Portainer (manual trigger, butuh input: stack_name + stack_env) -3. `docker-publish.yml` - Auto build & push saat ada tag versi v* - -Workflow bisa dijalankan via GitHub CLI: `gh workflow run -f param=value --ref branch` - -Setelah commit ke branch deployment (dev/stg/prod), otomatis trigger workflow publish + re-pull untuk deploy ke server. -- **Deployment Workflow Sistematis**: -1. **Version Bump** - Update `version` di `package.json` sebelum deploy (ikuti semver: major.minor.patch) -2. **Commit** - Commit perubahan + version bump dengan pesan yang jelas -3. **Push ke Branch** - Push ke branch target (biasanya `stg` untuk staging atau `prod` untuk production) -4. **Trigger Publish** - Jalankan `gh workflow run publish.yml --ref -f stack_env= -f tag=` -5. **Trigger Re-Pull** - Jalankan `gh workflow run re-pull.yml -f stack_name=desa-darmasaba -f stack_env=` -6. **Verifikasi** - Cek workflow berhasil dan aplikasi berjalan - -Branch deployment: `stg` (staging) atau `prod` (production) -Version format di package.json: `"version": "major.minor.patch"` -- **Deployment Workflow HARUS Sequential (Berurutan)**: - -Saat deploy ke stg atau prod, workflow TIDAK BOLEH dijalankan bersamaan. Harus menunggu yang pertama SELESAI total baru trigger yang kedua. - -**Urutan yang BENAR:** -1. ✅ **publish.yml** - Tunggu sampai SELESAI (status: ✓ success) -2. ✅ **Setelah publish selesai**, baru trigger **re-pull.yml** - -**JANGAN trigger keduanya bersamaan!** Ini akan menyebabkan race condition karena re-pull akan menarik image yang belum selesai di-build. - -**Cara cek workflow selesai:** -```bash -gh run view --json status --jq '.status' -# Harus return "completed" baru lanjut ke re-pull -``` - -**Atau polling sampai selesai:** -```bash -gh run watch -# Tunggu sampai ada checkmark ✓ -``` +- **GitHub Workflows**: Project ini memiliki workflow GitHub Action untuk deployment. User akan menangani workflow secara manual di GitHub. diff --git a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts index 7c83ed42..16176e31 100644 --- a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts +++ b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/create.ts @@ -79,7 +79,7 @@ const fileStorageCreate = async (context: Context) => { data: { name: finalName, realName: file.name, - path: rootPath, + path: pathName, // Store relative path (e.g., "images", "audio", "documents") mimeType: finalMimeType, category, link: `/api/fileStorage/findUnique/${finalName}`, diff --git a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/del.ts b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/del.ts index 65d1469a..b70e0243 100644 --- a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/del.ts +++ b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/del.ts @@ -36,7 +36,7 @@ const fileStorageDelete = async (context: Context) => { }; } - const filePath = path.join(file.path, file.name); + const filePath = path.join(UPLOAD_DIR, file.path, file.name); try { // Hapus file dari filesystem diff --git a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts index 4969e9de..842c6579 100644 --- a/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts +++ b/src/app/api/[[...slugs]]/_lib/fileStorage/_lib/findUniq.ts @@ -3,6 +3,8 @@ import { Context } from "elysia"; import fs from "fs/promises"; import path from "path"; +const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR; + const fileStorageFindUnique = async (context: Context) => { const { name } = context.params; @@ -20,9 +22,17 @@ const fileStorageFindUnique = async (context: Context) => { }; } + if (!UPLOAD_DIR) { + context.set.status = "Internal Server Error"; + return { + status: 500, + message: "UPLOAD_DIR is not defined", + }; + } + console.log(data); - const file = await fs.readFile(path.join(data.path, data.name)); + const file = await fs.readFile(path.join(UPLOAD_DIR, data.path, data.name)); context.set.headers = { "Content-Type": data.mimeType, "Content-Length": file.length,