11# =============================================================================
2- # Multi-stage Dockerfile for Hocuspocus Server
3- # Build context MUST be monorepo root (.) so workspace dep @docs.plus/email-templates resolves .
2+ # Hocuspocus Backend (REST, WebSocket, Worker) — minimal image
3+ # Build context: monorepo root (.). Copies only what this backend needs .
44# =============================================================================
55
6- # -----------------------------------------------------------------------------
7- # Stage 1: Base - Install dependencies (monorepo layout)
8- # -----------------------------------------------------------------------------
9- # Use latest Bun 1.x (floating tag); same tag across all Dockerfiles for cohesion
106FROM oven/bun:1-slim AS base
117WORKDIR /app
128
13- # Build argument for Prisma (only needed for client generation, not actual connection)
149ARG DATABASE_URL
1510ENV DATABASE_URL=${DATABASE_URL:-postgresql://dummy:dummy@localhost:5432/dummy}
1611
17- # Install system dependencies (clean apt lists first to avoid stale mirrors)
1812RUN rm -rf /var/lib/apt/lists/* && \
1913 apt-get update && apt-get install -y --no-install-recommends \
20- ca-certificates \
21- openssl \
22- && rm -rf /var/lib/apt/lists/*
14+ ca-certificates openssl && rm -rf /var/lib/apt/lists/*
2315
24- # Copy root workspace files
16+ # Backend closure: root + email-templates + hocuspocus.server. Stub package.json for
17+ # other workspaces so lockfile resolution succeeds without copying their source.
2518COPY package.json bun.lock* bunfig.toml ./
26- # Copy full packages needed for hocuspocus (email-templates is a workspace dep)
2719COPY packages/email-templates ./packages/email-templates
2820COPY packages/hocuspocus.server ./packages/hocuspocus.server
29- # Stub package.json for other workspaces so lockfile matches (no install from these)
3021COPY packages/admin-dashboard/package.json ./packages/admin-dashboard/
3122COPY packages/eslint-config/package.json ./packages/eslint-config/
3223COPY packages/extension-hyperlink/package.json ./packages/extension-hyperlink/
@@ -36,78 +27,34 @@ COPY packages/extension-inline-code/package.json ./packages/extension-inline-cod
3627COPY packages/supabase/package.json ./packages/supabase/
3728COPY packages/webapp/package.json ./packages/webapp/
3829
39- # Install dependencies (resolves @docs.plus/email-templates from workspace)
40- # --ignore-scripts: avoid root "prepare" (husky) and other lifecycle scripts in Docker
4130RUN bun install --frozen-lockfile --production --ignore-scripts
4231
43- # Prisma generate (schema lives in packages/hocuspocus.server/prisma)
44- # Pin to Prisma 6.19.0: project schema uses url=env(); Prisma 7 requires prisma.config.ts
45- RUN cd packages/hocuspocus.server && bunx prisma@6.19.0 generate
46-
47- # Pre-install Prisma CLI for runtime migrations (pin 6.19.0)
48- RUN bun add -d prisma@6.19.0 --no-save || true
49-
32+ # Production runs its own install + generate; no need to generate in base.
5033# -----------------------------------------------------------------------------
51- # Stage 2: Production - Minimal runtime image (flat /app = hocuspocus.server layout)
52- # Do NOT copy node_modules from base: Bun symlinks break across stages (hono,
53- # @hocuspocus/server etc. not found). Run bun install in this stage instead.
34+ # Production: same layout, fresh install in stage (no node_modules copy)
5435# -----------------------------------------------------------------------------
5536FROM oven/bun:1-slim AS production
5637WORKDIR /app
5738
58- # Install runtime dependencies only
5939RUN rm -rf /var/lib/apt/lists/* && \
6040 apt-get update && apt-get install -y --no-install-recommends \
61- ca-certificates \
62- openssl \
63- netcat-openbsd \
64- && rm -rf /var/lib/apt/lists/*
65-
66- # Create non-root user for security
41+ ca-certificates openssl && rm -rf /var/lib/apt/lists/*
6742RUN groupadd -r appuser && useradd -r -g appuser appuser
6843
69- # Copy workspace layout from base (no node_modules)
7044COPY --from=base /app/package.json /app/bun.lock* /app/bunfig.toml ./
7145COPY --from=base /app/packages ./packages
7246
73- # Fresh install so node_modules is real (Bun symlinks from base would break here)
7447RUN bun install --frozen-lockfile --production --ignore-scripts
48+ RUN cd packages/hocuspocus.server && bunx prisma@6.19.0 generate
7549
76- # Prisma generate (schema in packages/hocuspocus.server/prisma)
77- RUN cd packages/hocuspocus.server && bunx prisma@6 generate
78-
79- # Copy entrypoint before we remove packages
8050COPY --from=base /app/packages/hocuspocus.server/scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
8151RUN chmod +x /usr/local/bin/docker-entrypoint.sh
8252
83- # Flat layout: keep packages/email-templates (workspace dep), rest at /app
84- RUN mv packages/hocuspocus.server/src . && \
85- mv packages/hocuspocus.server/prisma . && \
86- cp packages/hocuspocus.server/package.json . && \
87- mv packages/email-templates /tmp/email-templates && \
88- rm -rf packages && \
89- mkdir -p packages && \
90- mv /tmp/email-templates packages/email-templates
91-
92- # Add workspaces so "workspace:*" @docs.plus/email-templates resolves; then re-install
93- # so node_modules is for /app only (no symlinks into deleted packages/) and hono is found.
94- # Remove root lockfile so Bun resolves only this workspace (hocuspocus + email-templates).
95- RUN bun -e "const p=require('./package.json'); p.workspaces=['packages']; require('fs').writeFileSync('package.json', JSON.stringify(p,null,2));"
96- RUN rm -f bun.lock bun.lockb && bun install --production --ignore-scripts
97-
98- # Pre-download Prisma CLI for migrations (pin 6.19.0)
99- RUN bunx --bun prisma@6.19.0 --version || true
100-
101- # Create temp directory for file uploads
102- RUN mkdir -p /app/temp/hypermultimedia && \
103- chown -R appuser:appuser /app
53+ # appuser must own /app so runtime can create ./temp/hypermultimedia/... (storage.local.ts uses mkdir recursive)
54+ RUN chown -R appuser:appuser /app
10455
10556USER appuser
106-
10757EXPOSE 4000 4001 4002
108-
109- HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
110- CMD bun --version || exit 1
111-
58+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD bun --version || exit 1
11259ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
11360CMD ["bun", "src/index.ts"]
0 commit comments