# ── Stage 1: Build the SvelteKit UI ────────────────────────────────────────── FROM node:22-alpine AS ui-builder WORKDIR /app COPY ui/package*.json ./ui/ RUN cd ui && npm ci --legacy-peer-deps # UI source + shared server types (needed for $types alias) COPY ui/ ./ui/ COPY server/ ./server/ WORKDIR /app/ui ENV NODE_ENV=production RUN npm run build # ── Stage 2: Runtime (API + compiled UI) ───────────────────────────────────── FROM node:22-alpine WORKDIR /app # API dependencies (tsx needed at runtime for ESM TypeScript) COPY package*.json ./ RUN npm ci # API source COPY bin/ ./bin/ COPY server/ ./server/ COPY tsconfig*.json ./ # Pre-built UI from stage 1 COPY --from=ui-builder /app/ui/build ./ui/build COPY --from=ui-builder /app/ui/package*.json ./ui/ RUN cd ui && npm ci --omit=dev --legacy-peer-deps # SQLite volume mount point RUN mkdir -p /app/data ENV NODE_ENV=production ENV DB_PATH=/app/data/market-screener.db ENV PORT=3000 ENV UI_PORT=3001 EXPOSE 3000 3001 # Run both processes; if either dies the container exits CMD ["npx", "concurrently", \ "--kill-others", \ "--names", "api,ui", \ "tsx bin/server.ts", \ "node ui/build/index.js"]