app/config.py: centralized Settings (DEMO_MODE, CLOUD_MODE, ports, etc.) app/middleware/demo.py: DemoModeMiddleware — caps sessions (429), blocks export (403), adds X-Linnet-Mode header app/middleware/cloud.py: CloudAuthMiddleware — requires X-CF-Session on /session/* routes, 401 without it app/services/session_store.py: active_session_count() for demo cap app/main.py: wires middleware conditionally, extends CORS for cloud origins compose.test.yml: hermetic pytest runner in Docker (CF_VOICE_MOCK=1) compose.demo.yml: DEMO_MODE=true, ports 8523/8524, demo.circuitforge.tech/linnet compose.cloud.yml: CLOUD_MODE=true, ports 8522/8527, menagerie.circuitforge.tech/linnet docker/web/Dockerfile: two-stage build (node:20 → nginx:alpine), VITE_BASE_URL/VITE_API_BASE ARGs docker/web/nginx.conf: SSE + WS proxy, SPA routing (dev/demo) docker/web/nginx.cloud.conf: adds X-CF-Session forwarding, /linnet/ alias for path-strip Caddy routing manage.sh: profile arg (dev|demo|cloud|test), start/stop/restart/status/test/logs/build/open per profile tests/test_profiles.py: 8 tests — demo export block, session cap, cloud auth gate, mode headers
22 lines
671 B
Docker
22 lines
671 B
Docker
# Stage 1: build Vue 3 frontend
|
|
FROM node:20-alpine AS build
|
|
WORKDIR /app
|
|
COPY frontend/package*.json ./
|
|
RUN npm ci --prefer-offline
|
|
COPY frontend/ ./
|
|
|
|
# Vite bakes these as static strings into the bundle.
|
|
# VITE_BASE_URL: path prefix the app is served under (/ for dev, /linnet for cloud)
|
|
# VITE_API_BASE: prefix for all /session/* fetch calls (empty for direct, /linnet for cloud)
|
|
ARG VITE_BASE_URL=/
|
|
ARG VITE_API_BASE=
|
|
ENV VITE_BASE_URL=$VITE_BASE_URL
|
|
ENV VITE_API_BASE=$VITE_API_BASE
|
|
|
|
RUN npm run build
|
|
|
|
# Stage 2: serve via nginx
|
|
FROM nginx:alpine
|
|
COPY docker/web/nginx.conf /etc/nginx/conf.d/default.conf
|
|
COPY --from=build /app/dist /usr/share/nginx/html
|
|
EXPOSE 80
|