Skip to content

Commit 954a7af

Browse files
committed
fix(backend): local prod run - network, replicas, env; Dockerfile/entrypoint
- backend-local override: create docsplus-network (external: false), replicas 1, env_file .env.local - Dockerfile/entrypoint from earlier backend Docker optimizations Made-with: Cursor
1 parent 4cccd3b commit 954a7af

4 files changed

Lines changed: 40 additions & 113 deletions

File tree

docker-compose.backend-local.override.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,26 @@ name: docsplus
66

77
services:
88
rest-api:
9+
env_file: .env.local
10+
deploy:
11+
replicas: 1
912
ports:
1013
- '4000:4000'
1114
hocuspocus-server:
15+
env_file: .env.local
16+
deploy:
17+
replicas: 1
1218
ports:
1319
- '4001:4001'
1420
hocuspocus-worker:
21+
env_file: .env.local
22+
deploy:
23+
replicas: 1
1524
ports:
1625
- '4002:4002'
26+
27+
# Prod compose declares docsplus-network as external (for Traefik). For local backend-only runs, create it.
28+
networks:
29+
docsplus-network:
30+
external: false
31+
name: docsplus-network

docker-compose.prod.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ services:
143143
restart: always
144144
stop_grace_period: 30s
145145
stop_signal: SIGTERM
146-
command: bun /app/src/index.ts
146+
command: bun src/index.ts
147147
environment:
148148
NODE_ENV: production
149149
APP_PORT: 4000
@@ -240,7 +240,7 @@ services:
240240
restart: always
241241
stop_grace_period: 30s
242242
stop_signal: SIGTERM
243-
command: bun /app/src/hocuspocus.server.ts
243+
command: bun src/hocuspocus.server.ts
244244
environment:
245245
NODE_ENV: production
246246
HOCUSPOCUS_PORT: 4001
@@ -338,7 +338,7 @@ services:
338338
# Grace period must exceed lockDuration (2min) to allow jobs to complete
339339
stop_grace_period: 150s
340340
stop_signal: SIGTERM
341-
command: bun /app/src/hocuspocus.worker.ts
341+
command: bun src/hocuspocus.worker.ts
342342
environment:
343343
NODE_ENV: production
344344
WORKER_HEALTH_PORT: 4002
Lines changed: 12 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,23 @@
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
106
FROM oven/bun:1-slim AS base
117
WORKDIR /app
128

13-
# Build argument for Prisma (only needed for client generation, not actual connection)
149
ARG DATABASE_URL
1510
ENV DATABASE_URL=${DATABASE_URL:-postgresql://dummy:dummy@localhost:5432/dummy}
1611

17-
# Install system dependencies (clean apt lists first to avoid stale mirrors)
1812
RUN 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.
2518
COPY package.json bun.lock* bunfig.toml ./
26-
# Copy full packages needed for hocuspocus (email-templates is a workspace dep)
2719
COPY packages/email-templates ./packages/email-templates
2820
COPY packages/hocuspocus.server ./packages/hocuspocus.server
29-
# Stub package.json for other workspaces so lockfile matches (no install from these)
3021
COPY packages/admin-dashboard/package.json ./packages/admin-dashboard/
3122
COPY packages/eslint-config/package.json ./packages/eslint-config/
3223
COPY packages/extension-hyperlink/package.json ./packages/extension-hyperlink/
@@ -36,78 +27,34 @@ COPY packages/extension-inline-code/package.json ./packages/extension-inline-cod
3627
COPY packages/supabase/package.json ./packages/supabase/
3728
COPY 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
4130
RUN 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
# -----------------------------------------------------------------------------
5536
FROM oven/bun:1-slim AS production
5637
WORKDIR /app
5738

58-
# Install runtime dependencies only
5939
RUN 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/*
6742
RUN groupadd -r appuser && useradd -r -g appuser appuser
6843

69-
# Copy workspace layout from base (no node_modules)
7044
COPY --from=base /app/package.json /app/bun.lock* /app/bunfig.toml ./
7145
COPY --from=base /app/packages ./packages
7246

73-
# Fresh install so node_modules is real (Bun symlinks from base would break here)
7447
RUN 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
8050
COPY --from=base /app/packages/hocuspocus.server/scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
8151
RUN 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

10556
USER appuser
106-
10757
EXPOSE 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
11259
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
11360
CMD ["bun", "src/index.ts"]
Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,20 @@
11
#!/usr/bin/env sh
2+
# Run from monorepo root; app and prisma live under packages/hocuspocus.server
23

3-
echo "🔄 Entrypoint script starting..."
4-
cd /app || exit 1
4+
set -e
5+
cd /app/packages/hocuspocus.server || exit 1
56

7+
echo "🔄 Entrypoint starting (monorepo layout)..."
68
echo "🔄 Running database migrations..."
79

8-
# Use Prisma CLI from node_modules (installed during build)
9-
# This avoids slow bunx downloads at runtime
1010
MIGRATION_FAILED=0
11-
if [ -f "/app/node_modules/.bin/prisma" ]; then
12-
echo "📦 Using Prisma CLI from node_modules (fast)..."
13-
timeout 30 /app/node_modules/.bin/prisma migrate deploy || MIGRATION_FAILED=1
14-
elif command -v bunx >/dev/null 2>&1; then
15-
echo "📦 Using bunx prisma@6.19.0 (schema uses url=env(); Prisma 7 requires prisma.config.ts)..."
16-
timeout 30 bunx prisma@6.19.0 migrate deploy || MIGRATION_FAILED=1
17-
else
18-
echo "⚠️ Prisma CLI not found, skipping migrations..."
19-
fi
11+
# Prisma is devDep; image uses --production so CLI comes from bunx only
12+
timeout 30 bunx prisma@6.19.0 migrate deploy || MIGRATION_FAILED=1
2013

2114
if [ "$MIGRATION_FAILED" -eq 1 ]; then
22-
echo "⚠️ Database migration failed, but continuing to start service..."
15+
echo "⚠️ Database migration failed, continuing to start service..."
2316
fi
2417

25-
echo "✅ Migrations completed (or skipped)"
26-
echo "🚀 Starting services..."
27-
echo "📝 Received command: $*"
28-
echo "📝 Number of args: $#"
29-
echo "📝 Args: $@"
30-
31-
# Convert relative paths to absolute if needed
32-
# Handle both "bun src/index.ts" (as string) and ["bun", "--watch", "src/index.ts"] (as array)
33-
if [ "$#" -eq 3 ] && [ "$1" = "bun" ] && [ "$2" = "--watch" ] && echo "$3" | grep -q "^src/"; then
34-
FILE=$(echo "$3" | sed 's/^src\///')
35-
echo "🔄 Converting: bun --watch src/$FILE -> bun --watch /app/src/$FILE"
36-
exec bun --watch "/app/src/$FILE"
37-
elif [ "$#" -eq 2 ] && [ "$1" = "bun" ] && echo "$2" | grep -q "^src/"; then
38-
FILE=$(echo "$2" | sed 's/^src\///')
39-
echo "🔄 Converting: bun src/$FILE -> bun /app/src/$FILE"
40-
exec bun "/app/src/$FILE"
41-
elif echo "$*" | grep -q -e "bun.*src/"; then
42-
# Handle any bun command with src/ path (-e prevents --watch being parsed as grep option on BusyBox)
43-
if echo "$*" | grep -q -e "--watch"; then
44-
FILE=$(echo "$*" | sed 's/.*bun.*--watch.*src\///' | sed 's/ .*//')
45-
echo "🔄 Converting: bun --watch src/$FILE -> bun --watch /app/src/$FILE"
46-
exec bun --watch "/app/src/$FILE"
47-
else
48-
FILE=$(echo "$*" | sed 's/.*bun.*src\///' | sed 's/ .*//')
49-
echo "🔄 Converting: bun src/$FILE -> bun /app/src/$FILE"
50-
exec bun "/app/src/$FILE"
51-
fi
52-
else
53-
echo "▶️ Executing original command: $@"
54-
exec "$@"
55-
fi
18+
echo "✅ Migrations done"
19+
echo "🚀 Starting: $*"
20+
exec "$@"

0 commit comments

Comments
 (0)