feat(docker): add multi-stage image and compose with persistent SQLite
Mount ./docker-data for WAL-capable SQLite storage, support DATABASE_PATH alias, and document compose secrets via .env.docker.example. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
node_modules
|
||||
dist
|
||||
data
|
||||
docker-data
|
||||
backups
|
||||
.env
|
||||
.env.docker
|
||||
.git
|
||||
.gitignore
|
||||
*.db
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
*.tsbuildinfo
|
||||
test
|
||||
coverage
|
||||
.cursor-sqlite-audit.cjs
|
||||
@@ -0,0 +1,5 @@
|
||||
# Copy to .env.docker for docker compose (gitignored).
|
||||
# Do not commit real secrets.
|
||||
|
||||
JWT_SECRET=replace-with-a-strong-secret
|
||||
CORS_ORIGIN=http://localhost:5174
|
||||
+3
-2
@@ -6,8 +6,9 @@ NODE_ENV=development
|
||||
# CORS (Vue dev server)
|
||||
CORS_ORIGIN=http://localhost:5173
|
||||
|
||||
# SQLite — production database
|
||||
# DB_PATH=E:/absolute/path/to/backend-nest/data/app.db
|
||||
# SQLite — path inside container or on host (DB_PATH or DATABASE_PATH)
|
||||
# DB_PATH=/app/data/app.db
|
||||
# DATABASE_PATH=/app/data/app.db
|
||||
|
||||
# JWT — must match legacy Fastify when migrating existing tokens
|
||||
JWT_SECRET=gold-land-dev-secret-change-in-production
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:22.12.0-bookworm-slim AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends python3 make g++ \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
RUN npm ci
|
||||
|
||||
COPY nest-cli.json tsconfig.json tsconfig.build.json ./
|
||||
COPY src ./src
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM node:22.12.0-bookworm-slim AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
PORT=3000 \
|
||||
HOST=0.0.0.0 \
|
||||
DB_PATH=/app/data/app.db
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends python3 make g++ \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
RUN npm ci --omit=dev \
|
||||
&& npm rebuild better-sqlite3 \
|
||||
&& apt-get purge -y python3 make g++ \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
RUN mkdir -p /app/data \
|
||||
&& chown -R node:node /app
|
||||
|
||||
USER node
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
||||
CMD node -e "fetch('http://127.0.0.1:3000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
||||
|
||||
CMD ["node", "dist/main.js"]
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: child-gold-land-backend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
env_file:
|
||||
- .env.docker
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 3000
|
||||
HOST: 0.0.0.0
|
||||
DB_PATH: /app/data/app.db
|
||||
volumes:
|
||||
- ./docker-data:/app/data
|
||||
restart: unless-stopped
|
||||
@@ -19,6 +19,11 @@ export class EnvironmentVariables {
|
||||
@IsString()
|
||||
DB_PATH?: string
|
||||
|
||||
/** Alias for DB_PATH (e.g. Docker Compose). DB_PATH takes precedence when both are set. */
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
DATABASE_PATH?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
JWT_SECRET?: string
|
||||
@@ -43,7 +48,7 @@ export function validateEnv(config: Record<string, unknown>): EnvironmentVariabl
|
||||
PORT: Number(config.PORT ?? 3001),
|
||||
HOST: (config.HOST as string | undefined) ?? '0.0.0.0',
|
||||
CORS_ORIGIN: (config.CORS_ORIGIN as string | undefined) ?? 'http://localhost:5173',
|
||||
DB_PATH: config.DB_PATH as string | undefined,
|
||||
DB_PATH: (config.DB_PATH ?? config.DATABASE_PATH) as string | undefined,
|
||||
JWT_SECRET: jwtSecret ?? 'gold-land-dev-secret-change-in-production',
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ export class DatabaseService implements OnModuleInit, OnModuleDestroy {
|
||||
private readonly dbPath: string
|
||||
|
||||
constructor(@Optional() @Inject(ConfigService) private readonly config?: ConfigService) {
|
||||
const configured = this.config?.get<string>('DB_PATH') ?? process.env.DB_PATH
|
||||
const configured =
|
||||
this.config?.get<string>('DB_PATH') ??
|
||||
process.env.DB_PATH ??
|
||||
process.env.DATABASE_PATH
|
||||
this.dbPath = configured ?? join(process.cwd(), 'data', 'app.db')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user