From 42f06c1128890c5f0f3d3ba9787ba22490fc9305 Mon Sep 17 00:00:00 2001 From: Monarch055 Date: Thu, 11 Jun 2026 09:43:16 +0700 Subject: [PATCH] fix: COPY init.sql into DB image, remove Next.js basePath for Traefik prefix stripping --- docker-compose.yaml | 5 +++-- docker/db/Dockerfile | 5 +++++ index.html | 7 ++++--- sistem-km-next/next.config.mjs | 6 +++--- sistem-km-next/src/components/Dashboard.js | 10 +++++----- 5 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 docker/db/Dockerfile diff --git a/docker-compose.yaml b/docker-compose.yaml index aaa136f..b208cd1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -37,7 +37,9 @@ services: # 3. MySQL Database Service db: - image: mysql:8.0 + build: + context: . + dockerfile: ./docker/db/Dockerfile container_name: gis_db command: --default-authentication-plugin=mysql_native_password # No host port mapping - DB is only accessible internally via gis-network @@ -46,7 +48,6 @@ services: - MYSQL_DATABASE=spbu_db volumes: - db-data:/var/lib/mysql - - ./docker/db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro networks: - gis-network diff --git a/docker/db/Dockerfile b/docker/db/Dockerfile new file mode 100644 index 0000000..67e2a30 --- /dev/null +++ b/docker/db/Dockerfile @@ -0,0 +1,5 @@ +FROM mysql:8.0 + +# Copy the SQL initialization script into the MySQL entrypoint directory. +# MySQL will automatically run all .sql files here on first startup (when data volume is empty). +COPY docker/db/init.sql /docker-entrypoint-initdb.d/init.sql diff --git a/index.html b/index.html index 33a08d9..e07e2ac 100644 --- a/index.html +++ b/index.html @@ -429,10 +429,11 @@ window.location.hostname === '127.0.0.1' || window.location.hostname.endsWith('.test') ) { - nextjsLink.href = 'http://localhost:3000/sistem-km-next'; + nextjsLink.href = 'http://localhost:3000'; } else { - // In production/campus server deployment, use the relative subfolder path - nextjsLink.href = './sistem-km-next'; + // In production (Coolify): Traefik routes /sistem-km-next -> next-app container. + // next-app now serves at root /, so we use the path-based URL on this same host. + nextjsLink.href = window.location.origin + '/sistem-km-next'; } }); diff --git a/sistem-km-next/next.config.mjs b/sistem-km-next/next.config.mjs index e551f69..6f37036 100644 --- a/sistem-km-next/next.config.mjs +++ b/sistem-km-next/next.config.mjs @@ -1,8 +1,8 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - basePath: '/sistem-km-next', - /* config options here */ + // basePath removed: Coolify's Traefik strips the /sistem-km-next prefix before + // forwarding to this container, so Next.js must respond at root /. + // The Traefik path /sistem-km-next -> container / mapping handles routing. }; export default nextConfig; - diff --git a/sistem-km-next/src/components/Dashboard.js b/sistem-km-next/src/components/Dashboard.js index 9b380d5..9707637 100644 --- a/sistem-km-next/src/components/Dashboard.js +++ b/sistem-km-next/src/components/Dashboard.js @@ -111,7 +111,7 @@ export default function Dashboard() { const fetchUsers = async () => { try { - const res = await fetch('/sistem-km-next/api/users'); + const res = await fetch('/api/users'); if (res.ok) { const data = await res.json(); setUsersList(data.users || []); @@ -123,7 +123,7 @@ export default function Dashboard() { e.preventDefault(); setIsSubmittingUser(true); try { - const res = await fetch('/sistem-km-next/api/users', { + const res = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(userFormData) @@ -149,7 +149,7 @@ export default function Dashboard() { onConfirm: async () => { setConfirmDialog(null); try { - const res = await fetch(`/sistem-km-next/api/users?id=${id}`, { method: 'DELETE' }); + const res = await fetch(`/api/users?id=${id}`, { method: 'DELETE' }); if (res.ok) { showToastNotification('Pengguna berhasil dihapus!'); fetchUsers(); @@ -171,7 +171,7 @@ export default function Dashboard() { onConfirm: async () => { setConfirmDialog(null); try { - const res = await fetch(`/sistem-km-next/api/hubs?id=${id}`, { method: 'DELETE' }); + const res = await fetch(`/api/hubs?id=${id}`, { method: 'DELETE' }); if (res.ok) { showToastNotification('Rumah ibadah dan akun terikat berhasil dihapus!'); fetchData(); @@ -541,7 +541,7 @@ const [isEditMode, setIsEditMode] = useState(false); setHouseholds(formattedHh); } else { setHouseholds([]); - fetch('/sistem-km-next/api/stats') + fetch('/api/stats') .then(res => res.json()) .then(data => { if (!isMountedRef.current) return;