diff --git a/Dockerfile b/Dockerfile index 2bb2821..18b2231 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,6 +45,7 @@ COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/prisma.config.ts ./prisma.config.ts +COPY --from=builder /app/scripts ./scripts # Explicitly copy all native/prisma node_modules (required for standalone mode) COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma diff --git a/entrypoint.sh b/entrypoint.sh index 268cf52..66cb7a9 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,16 +1,19 @@ #!/bin/sh set -e -echo "=== Menu Professional Entrypoint ===" -echo "Node version: $(node -v)" +echo "=== Menu Professional — Starting ===" +echo "NODE_ENV: ${NODE_ENV}" +echo "PORT: ${PORT:-3214}" echo "DATABASE_URL: ${DATABASE_URL}" # Ensure the prisma directory exists and is writable mkdir -p /app/prisma chmod -R 777 /app/prisma -echo "Write check on /app/prisma..." -touch /app/prisma/.write_test && echo "OK" && rm /app/prisma/.write_test +echo "" +echo "[1/2] Initializing database schema..." +node /app/scripts/init-db.mjs -echo "Launching server on port ${PORT:-3214}..." +echo "" +echo "[2/2] Starting Next.js server..." exec node server.js diff --git a/lib/db.ts b/lib/db.ts index 16170f2..172279d 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -1,26 +1,17 @@ import { PrismaClient } from '@prisma/client'; import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'; -import { initializeDatabase } from './initDb'; const globalForPrisma = global as unknown as { prisma: PrismaClient }; +/** + * Creates the Prisma client. + * Schema initialization is handled by scripts/init-db.mjs (run at startup). + */ const createPrismaClient = () => { - try { - const dbUrl = process.env.DATABASE_URL || 'file:/app/prisma/dev.db'; - console.log(`[DB] Connecting to: ${dbUrl}`); - - // Ensure schema exists before creating the Prisma client - initializeDatabase(); - - const adapter = new PrismaBetterSqlite3({ url: dbUrl }); - const client = new PrismaClient({ adapter }); - - console.log('[DB] Prisma client ready.'); - return client; - } catch (error) { - console.error('[DB] Critical initialization failure:', error); - throw error; - } + const dbUrl = process.env.DATABASE_URL || 'file:/app/prisma/dev.db'; + console.log(`[DB] Connecting to: ${dbUrl}`); + const adapter = new PrismaBetterSqlite3({ url: dbUrl }); + return new PrismaClient({ adapter }); }; export const prisma = globalForPrisma.prisma || createPrismaClient(); diff --git a/lib/initDb.ts b/lib/initDb.ts deleted file mode 100644 index 3bd4668..0000000 --- a/lib/initDb.ts +++ /dev/null @@ -1,52 +0,0 @@ -import Database from 'better-sqlite3'; -import path from 'path'; - -/** - * Initializes the SQLite database schema using raw SQL. - * Safe to run multiple times — uses IF NOT EXISTS and handles migrations. - */ -export function initializeDatabase(): void { - const dbUrl = process.env.DATABASE_URL || 'file:/app/prisma/dev.db'; - const filePath = dbUrl.replace(/^file:/, ''); - const resolvedPath = path.isAbsolute(filePath) - ? filePath - : path.join(process.cwd(), filePath); - - console.log(`[DB Init] Ensuring schema at: ${resolvedPath}`); - - try { - const db = new Database(resolvedPath); - - // Config table - db.exec(` - CREATE TABLE IF NOT EXISTS "Config" ( - "id" TEXT NOT NULL PRIMARY KEY, - "value" TEXT NOT NULL - ); - `); - - // Button table (base) - db.exec(` - CREATE TABLE IF NOT EXISTS "Button" ( - "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - "name" TEXT NOT NULL, - "url" TEXT NOT NULL, - "order" INTEGER NOT NULL DEFAULT 0 - ); - `); - - // Migration: add icon column if missing (added in v2) - try { - db.exec(`ALTER TABLE "Button" ADD COLUMN "icon" TEXT;`); - console.log('[DB Init] Migration applied: Button.icon column added.'); - } catch { - // Column already exists — no action needed - } - - db.close(); - console.log('[DB Init] Schema ready.'); - } catch (err) { - console.error('[DB Init Error] Failed to initialize schema:', err); - throw err; - } -} diff --git a/scripts/init-db.mjs b/scripts/init-db.mjs new file mode 100644 index 0000000..8fc200d --- /dev/null +++ b/scripts/init-db.mjs @@ -0,0 +1,53 @@ +#!/usr/bin/env node +/** + * Database initialization script. + * Run BEFORE the Next.js server starts (via entrypoint.sh). + * Uses better-sqlite3 directly — no Prisma CLI dependency. + */ + +import Database from 'better-sqlite3'; +import { existsSync, mkdirSync } from 'fs'; +import { dirname } from 'path'; + +const DB_URL = process.env.DATABASE_URL || 'file:/app/prisma/dev.db'; +const DB_PATH = DB_URL.replace(/^file:/, ''); + +// Ensure the directory exists +const dir = dirname(DB_PATH); +if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }); + console.log(`[init-db] Created directory: ${dir}`); +} + +console.log(`[init-db] Initializing database at: ${DB_PATH}`); + +const db = new Database(DB_PATH); + +// Config table +db.exec(` + CREATE TABLE IF NOT EXISTS "Config" ( + "id" TEXT NOT NULL PRIMARY KEY, + "value" TEXT NOT NULL + ); +`); + +// Button table +db.exec(` + CREATE TABLE IF NOT EXISTS "Button" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL, + "url" TEXT NOT NULL, + "order" INTEGER NOT NULL DEFAULT 0 + ); +`); + +// Migration v2: icon column +try { + db.exec(`ALTER TABLE "Button" ADD COLUMN "icon" TEXT;`); + console.log('[init-db] Migration: Button.icon column added.'); +} catch { + // Column already exists — safe to ignore +} + +db.close(); +console.log('[init-db] Database ready.');