From 99d0c666260ddf2f85b763c9b0e6bb68ba743fb6 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Wed, 4 Mar 2026 07:46:32 +0000 Subject: [PATCH] feat(Dockerfile): add root multi-stage Dockerfile for Dokploy - Stage 1 (node:20): builds Vue.js frontend to /app/dist - Stage 2 (python:3.12): FastAPI serves API + static files - main.py: serve Vue.js dist via StaticFiles if /app/dist exists - Removes GET / route (replaced by frontend index.html) Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 16 ++++++++++++++++ backend/app/main.py | 15 +++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1e3ced4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM node:20-alpine AS frontend-builder +WORKDIR /app/frontend +COPY frontend/package*.json ./ +RUN npm ci +COPY frontend/ ./ +RUN npm run build + +FROM python:3.12-slim +WORKDIR /app +COPY backend/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY backend/ . +COPY --from=frontend-builder /app/frontend/dist /app/dist +RUN mkdir -p uploads +EXPOSE 8000 +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/backend/app/main.py b/backend/app/main.py index c3c5d4e..a03a597 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -1,6 +1,9 @@ """FastAPI application entry point.""" +import os + from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from fastapi.staticfiles import StaticFiles from app.api.attachments import router as attachments_router from app.api.audit_log import router as audit_log_router @@ -64,13 +67,13 @@ app.include_router(organizations_admin_router, prefix="/api") app.include_router(public_router, prefix="/api") -@app.get("/") -def root() -> dict[str, str]: - """Root endpoint.""" - return {"message": "Space Booking API"} - - @app.get("/health") def health() -> dict[str, str]: """Health check endpoint.""" return {"status": "ok"} + + +# Serve Vue.js frontend in production (when /app/dist exists) +_dist_dir = os.path.join(os.path.dirname(__file__), "..", "..", "dist") +if os.path.isdir(_dist_dir): + app.mount("/", StaticFiles(directory=_dist_dir, html=True), name="static")