diff --git a/Dockerfile b/Dockerfile index 410c55b..59d30ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,25 @@ FROM node:alpine -# Required build argument for database type -ARG DATABASE_TYPE +WORKDIR /app -# Set production environment -ENV NODE_ENV=production \ - DATABASE_TYPE=${DATABASE_TYPE} +# Set production environment by default +ENV NODE_ENV=production -# Copy all application files COPY . . -# Copy specific database files based on DATABASE_TYPE and clean up -RUN cp -r /prisma/database/${DATABASE_TYPE}/* /prisma/ && \ - rm -rf /prisma/database +# Install dependencies +RUN npm install -# Install dependencies and generate Prisma client -RUN npm install && \ - npx prisma generate +# Copy all application files + + +# Make the management script executable +RUN chmod +x classworks.js EXPOSE 3000 -# Run different commands based on DATABASE_TYPE -CMD ["sh", "-c", "if [ \"$DATABASE_TYPE\" = \"sqlite\" ]; then (if [ ! -f /data/db.db ]; then npx prisma migrate dev --name init; else npx prisma migrate deploy; fi); else npx prisma migrate deploy; fi && npx prisma generate && npm run start"] +# Use the management script as entrypoint +ENTRYPOINT ["node", "classworks.js"] + +# Default command (can be overridden) +CMD [] \ No newline at end of file diff --git a/classworks.js b/classworks.js new file mode 100644 index 0000000..43b5192 --- /dev/null +++ b/classworks.js @@ -0,0 +1,99 @@ +#!/usr/bin/env node +import { execSync } from "child_process"; +import fs from "fs"; +import path from "path"; +import dotenv from "dotenv"; + +dotenv.config(); + +const PRISMA_DIR = path.join(process.cwd(), "prisma"); +const DATABASE_TYPE = process.env.DATABASE_TYPE || "postgres"; +const DATABASE_URL = + DATABASE_TYPE === "sqlite" + ? "file:/data/db.sqlite" + : process.env.DATABASE_URL; + +function setupDatabase() { + try { + // Create data directory for SQLite if needed + if (DATABASE_TYPE === "sqlite") { + if (!fs.existsSync("/data")) { + fs.mkdirSync("/data", { recursive: true }); + } + } else if (!DATABASE_URL) { + console.error("❌ DATABASE_URL is required for non-SQLite databases"); + process.exit(1); + } + + // Copy files from database type directory + const sourceDir = path.join(PRISMA_DIR, "database", DATABASE_TYPE); + if (!fs.existsSync(sourceDir)) { + console.error(`❌ Database configuration not found at ${sourceDir}`); + process.exit(1); + } + + // Read all files from source directory + const files = fs.readdirSync(sourceDir); + for (const file of files) { + const sourcePath = path.join(sourceDir, file); + const targetPath = path.join(PRISMA_DIR, file); + fs.copyFileSync(sourcePath, targetPath); + } + console.log(`✅ Copied ${DATABASE_TYPE} database configuration files`); + + // Set DATABASE_URL for Prisma + process.env.DATABASE_URL = DATABASE_URL; + } catch (error) { + console.error("❌ Database setup failed:", error.message); + process.exit(1); + } +} + +function buildLocal() { + try { + execSync("npm install", { stdio: "inherit" }); + execSync("npx prisma generate", { stdio: "inherit" }); + console.log("✅ Build completed"); + } catch (error) { + console.error("❌ Build failed:", error.message); + process.exit(1); + } +} + +function startServer() { + try { + console.log(`🚀 Starting server with ${DATABASE_TYPE} database...`); + execSync("npm run start", { stdio: "inherit" }); + } catch (error) { + console.error("❌ Server start failed:", error.message); + process.exit(1); + } +} + +function runPrismaCommand(args) { + try { + const command = `npx prisma ${args.join(" ")}`; + execSync(command, { stdio: "inherit" }); + } catch (error) { + console.error("❌ Prisma command failed:", error.message); + process.exit(1); + } +} + +async function main() { + const args = process.argv.slice(2); + if (args[0] === "prisma") { + // Run Prisma command + runPrismaCommand(args.slice(1)); + } else { + // Setup environment and database + setupDatabase(); + buildLocal(); + startServer(); + } +} + +main().catch((error) => { + console.error("❌ Script failed:", error); + process.exit(1); +}); diff --git a/docker-compose.yml b/docker-compose.yml index 7aadc3b..3b92508 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,70 +1,17 @@ version: '3.8' services: - app-mysql: + app: build: context: . - args: - DATABASE_TYPE: mysql - environment: - - NODE_ENV=production - - DATABASE_URL=mysql://user:password@mysql:3306/classworks - depends_on: - mysql: - condition: service_healthy - - app-postgres: - build: - context: . - args: - DATABASE_TYPE: postgres - environment: - - NODE_ENV=production - - DATABASE_URL=postgresql://user:password@postgres:5432/classworks - depends_on: - postgres: - condition: service_healthy - - app-sqlite: - build: - context: . - args: - DATABASE_TYPE: sqlite + dockerfile: Dockerfile + container_name: classworks + ports: + - "3000:3000" environment: - NODE_ENV=production + - DATABASE_TYPE=sqlite + - DATABASE_URL= volumes: - - sqlite_data:/data + - cs-data:/data - mysql: - image: mysql:8 - environment: - - MYSQL_DATABASE=classworks - - MYSQL_USER=user - - MYSQL_PASSWORD=password - - MYSQL_ROOT_PASSWORD=rootpassword - volumes: - - mysql_data:/var/lib/mysql - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] - interval: 10s - timeout: 5s - retries: 5 - - postgres: - image: postgres:15-alpine - environment: - - POSTGRES_DB=classworks - - POSTGRES_USER=user - - POSTGRES_PASSWORD=password - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d classworks"] - interval: 10s - timeout: 5s - retries: 5 - -volumes: - mysql_data: - postgres_data: - sqlite_data: