diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..82eeb26 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# Dependencies +node_modules +.pnpm-store + +# Build outputs +.next +out +dist +build + +# Database +*.db +*.db-journal +data/ + +# Git +.git +.gitignore + +# IDE +.idea +.vscode +*.swp +*.swo + +# Misc +*.log +npm-debug.log* +.DS_Store +Thumbs.db + +# Environment +.env +.env.* +!.env.example + +# Docker +Dockerfile* +docker-compose* +.dockerignore + +# Documentation +README.md +devbook.md +TODO.md + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a3f0cc1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +# syntax=docker/dockerfile:1 + +# ---- Base ---- +FROM node:22-alpine AS base +RUN corepack enable && corepack prepare pnpm@latest --activate +WORKDIR /app + +# ---- Dependencies ---- +FROM base AS deps +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# ---- Build ---- +FROM base AS builder +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Generate Prisma client (dummy URL for build, actual URL at runtime) +ENV DATABASE_URL="file:/tmp/build.db" +RUN pnpm prisma generate + +# Build Next.js +ENV NEXT_TELEMETRY_DISABLED=1 +RUN pnpm build + +# ---- Production ---- +FROM base AS runner +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +# Install build tools for native modules (better-sqlite3) +RUN apk add --no-cache python3 make g++ + +# Create non-root user +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +# Copy built assets (standalone includes node_modules needed for runtime) +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +# Copy Prisma schema, migrations, and config +COPY --from=builder /app/prisma ./prisma +COPY --from=builder /app/prisma.config.ts ./prisma.config.ts + +# Install prisma CLI for migrations + better-sqlite3 (compile native module) +ENV DATABASE_URL="file:/app/data/prod.db" +RUN pnpm add prisma @prisma/client @prisma/adapter-better-sqlite3 better-sqlite3 dotenv && \ + pnpm prisma generate + +# Copy entrypoint script +COPY --chown=nextjs:nodejs docker-entrypoint.sh ./ +RUN chmod +x docker-entrypoint.sh + +# Create data directory for SQLite +RUN mkdir -p /app/data && chown -R nextjs:nodejs /app/data + +USER nextjs + +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" +ENV DATABASE_URL="file:/app/data/prod.db" + +ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/data/dev.db b/data/dev.db new file mode 100644 index 0000000..156f36c Binary files /dev/null and b/data/dev.db differ diff --git a/data/prod.db b/data/prod.db new file mode 100644 index 0000000..fdb96f0 Binary files /dev/null and b/data/prod.db differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..37feebf --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "3011:3000" + environment: + - NODE_ENV=production + - DATABASE_URL=file:/app/data/dev.db + - AUTH_SECRET=${AUTH_SECRET:-your-secret-key-change-in-production} + - AUTH_TRUST_HOST=true + - AUTH_URL=${AUTH_URL:-http://localhost:3011} + volumes: + - ./data:/app/data + restart: unless-stopped + diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..781a1fd --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +echo "🔄 Running database migrations..." +pnpm prisma migrate deploy + +echo "🚀 Starting application..." +exec node server.js + diff --git a/next.config.ts b/next.config.ts index e9ffa30..68a6c64 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", }; export default nextConfig;