Compare commits
5 Commits
af368eeee0
...
deploy/stg
| Author | SHA1 | Date | |
|---|---|---|---|
| 09c7fd8f3a | |||
| 656ffcc561 | |||
| 76ffa662c5 | |||
| 46423409fd | |||
| 2edf5e9b11 |
@@ -59,9 +59,16 @@ COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
|||||||
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
|
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
|
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/next.config.* ./
|
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
|
USER nextjs
|
||||||
|
|
||||||
|
# Persistent storage for uploaded files
|
||||||
|
VOLUME ["/app/uploads"]
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["bun", "start"]
|
CMD ["/app/docker-entrypoint.sh"]
|
||||||
19
QWEN.md
19
QWEN.md
@@ -232,21 +232,4 @@ Common issues and solutions:
|
|||||||
6. Verify responsive design on different screen sizes
|
6. Verify responsive design on different screen sizes
|
||||||
|
|
||||||
## Qwen Added Memories
|
## Qwen Added Memories
|
||||||
- **GitHub Workflow Execution**: Project ini memiliki 3 workflow GitHub Action:
|
- **GitHub Workflows**: Project ini memiliki workflow GitHub Action untuk deployment. User akan menangani workflow secara manual di GitHub.
|
||||||
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 <nama.yml> -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 <branch> -f stack_env=<env> -f tag=<version>`
|
|
||||||
5. **Trigger Re-Pull** - Jalankan `gh workflow run re-pull.yml -f stack_name=desa-darmasaba -f stack_env=<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"`
|
|
||||||
|
|||||||
13
docker-entrypoint.sh
Normal file
13
docker-entrypoint.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🔄 Running database migrations..."
|
||||||
|
cd /app
|
||||||
|
bunx prisma migrate deploy || {
|
||||||
|
echo "❌ Migration failed!"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "✅ Migrations completed successfully"
|
||||||
|
|
||||||
|
echo "🚀 Starting application..."
|
||||||
|
exec bun start
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "desa-darmasaba",
|
"name": "desa-darmasaba",
|
||||||
"version": "0.1.6",
|
"version": "0.1.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "DataBanjar" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"nama" TEXT NOT NULL,
|
||||||
|
"penduduk" INTEGER NOT NULL,
|
||||||
|
"kk" INTEGER NOT NULL,
|
||||||
|
"miskin" INTEGER NOT NULL,
|
||||||
|
"tahun" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
CONSTRAINT "DataBanjar_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "DistribusiAgama" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"agama" TEXT NOT NULL,
|
||||||
|
"jumlah" INTEGER NOT NULL,
|
||||||
|
"tahun" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
CONSTRAINT "DistribusiAgama_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "DistribusiUmur" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"rentangUmur" TEXT NOT NULL,
|
||||||
|
"jumlah" INTEGER NOT NULL,
|
||||||
|
"tahun" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
CONSTRAINT "DistribusiUmur_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "MigrasiPenduduk" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"nama" TEXT NOT NULL,
|
||||||
|
"jenis" "JenisMigrasi" NOT NULL,
|
||||||
|
"tanggal" TIMESTAMP(3) NOT NULL,
|
||||||
|
"asal" TEXT,
|
||||||
|
"tujuan" TEXT,
|
||||||
|
"alasan" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
CONSTRAINT "MigrasiPenduduk_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "DinamikaPenduduk" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"tahun" INTEGER NOT NULL,
|
||||||
|
"kelahiran" INTEGER NOT NULL,
|
||||||
|
"kematian" INTEGER NOT NULL,
|
||||||
|
"masuk" INTEGER NOT NULL,
|
||||||
|
"keluar" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
CONSTRAINT "DinamikaPenduduk_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DataBanjar_tahun_idx" ON "DataBanjar"("tahun");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DataBanjar_isActive_idx" ON "DataBanjar"("isActive");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DistribusiAgama_tahun_idx" ON "DistribusiAgama"("tahun");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DistribusiAgama_isActive_idx" ON "DistribusiAgama"("isActive");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DistribusiUmur_tahun_idx" ON "DistribusiUmur"("tahun");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DistribusiUmur_isActive_idx" ON "DistribusiUmur"("isActive");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "MigrasiPenduduk_tanggal_idx" ON "MigrasiPenduduk"("tanggal");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "MigrasiPenduduk_isActive_idx" ON "MigrasiPenduduk"("isActive");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DinamikaPenduduk_tahun_idx" ON "DinamikaPenduduk"("tahun");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "DinamikaPenduduk_isActive_idx" ON "DinamikaPenduduk"("isActive");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "DinamikaPenduduk_tahun_key" ON "DinamikaPenduduk"("tahun");
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "JenisMigrasi" AS ENUM ('MASUK', 'KELUAR');
|
||||||
@@ -79,7 +79,7 @@ const fileStorageCreate = async (context: Context) => {
|
|||||||
data: {
|
data: {
|
||||||
name: finalName,
|
name: finalName,
|
||||||
realName: file.name,
|
realName: file.name,
|
||||||
path: rootPath,
|
path: pathName, // Store relative path (e.g., "images", "audio", "documents")
|
||||||
mimeType: finalMimeType,
|
mimeType: finalMimeType,
|
||||||
category,
|
category,
|
||||||
link: `/api/fileStorage/findUnique/${finalName}`,
|
link: `/api/fileStorage/findUnique/${finalName}`,
|
||||||
|
|||||||
@@ -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 {
|
try {
|
||||||
// Hapus file dari filesystem
|
// Hapus file dari filesystem
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Context } from "elysia";
|
|||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
|
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
|
||||||
|
|
||||||
const fileStorageFindUnique = async (context: Context) => {
|
const fileStorageFindUnique = async (context: Context) => {
|
||||||
const { name } = context.params;
|
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);
|
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 = {
|
context.set.headers = {
|
||||||
"Content-Type": data.mimeType,
|
"Content-Type": data.mimeType,
|
||||||
"Content-Length": file.length,
|
"Content-Length": file.length,
|
||||||
|
|||||||
Reference in New Issue
Block a user