# STCourses: the server and the SPA in one image. AGPL-3.0-only. # Build: docker build -t stc-app . # Run: see docker-compose.yml and docs/operations.md FROM oven/bun:1.3 # Tools the importer and the studio call: ffmpeg/ffprobe (frames, durations), git (studio repos, code imports), # unzip (Packt and code zips), python3 with PyMuPDF (PDF page images and text; STC_PYTHON points at it). RUN apt-get update \ && apt-get install -y --no-install-recommends ffmpeg git unzip ca-certificates python3 python3-pymupdf \ && rm -rf /var/lib/apt/lists/* \ && python3 -c "import pymupdf" WORKDIR /app # Dependencies first (cached unless a manifest or the lockfile changes). COPY package.json bun.lock ./ COPY apps/server/package.json apps/server/ COPY apps/web/package.json apps/web/ COPY packages/contracts/package.json packages/contracts/ COPY packages/core/package.json packages/core/ COPY packages/course-format/package.json packages/course-format/ COPY packages/db/package.json packages/db/ COPY packages/ui/package.json packages/ui/ COPY packages/feature-learner/package.json packages/feature-learner/ COPY packages/feature-import/package.json packages/feature-import/ COPY packages/feature-studio/package.json packages/feature-studio/ COPY packages/feature-ai/package.json packages/feature-ai/ RUN bun install --production --frozen-lockfile # Sources (Bun runs TypeScript directly; tsconfig.json carries the @stc/* path mapping). COPY tsconfig.json ./ COPY apps apps COPY packages packages COPY overlays overlays # /data holds the database (SQLite), imported courses, studio repos and caches. /courses is for course repos you mount. RUN mkdir -p /data /courses && chown bun:bun /data VOLUME /data ENV NODE_ENV=production \ STC_PORT=3000 \ STC_DATA_DIR=/data \ STC_DATABASE_URL=sqlite:///data/stcourses.db \ STC_COURSE_DIRS=/app/overlays:/courses \ STC_IMPORT_ROOTS=/import \ STC_PYTHON=python3 USER bun EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ CMD bun -e "fetch('http://127.0.0.1:' + (process.env.STC_PORT || 3000) + '/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))" CMD ["bun", "apps/server/src/main.ts"]