diff --git a/.dockerignore b/.dockerignore index 80e15fd..ad01401 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,9 +3,14 @@ venv __pycache__ *.pyc +# node_modules réinstallés dans le stage de build (à tous les niveaux) node_modules +**/node_modules +# frontend/dist est rebuildé dans l'image, jamais copié depuis l'hôte frontend/dist +# données locales : ne jamais les embarquer dans l'image data +data_bck *.egg-info .mypy_cache .ruff_cache diff --git a/README.md b/README.md index 3fd59e8..de7f9b5 100644 --- a/README.md +++ b/README.md @@ -37,12 +37,20 @@ Ouvrir **http://localhost:5173** — le proxy Vite redirige `/api` vers le backe ## Production (Docker) +Un **conteneur unique** : l'image builde le frontend Vue puis le fait servir +par le backend FastAPI (API + interface web sur le meme port). Pas de nginx. + ```bash -make docker +make docker # podman-compose up --build +# ou : docker compose up --build ``` Accessible sur **http://localhost:8080**. +Les donnees (base SQLite + documents) sont declarees via `PLESNA_DATA_DIR` +(voir `docker-compose.yml`) et persistees dans le volume `./data`, donc +conservees entre les redemarrages du conteneur. + ## Application de bureau (Windows, sans ligne de commande) L'application peut etre empaquetee en **executable Windows autonome** : un seul diff --git a/backend.Dockerfile b/backend.Dockerfile index 8088d4a..f8c6aff 100644 --- a/backend.Dockerfile +++ b/backend.Dockerfile @@ -1,3 +1,18 @@ +# syntax=docker/dockerfile:1 + +# --- Étape 1 : build du frontend Vue ----------------------------------------- +# Le backend FastAPI sert lui-même le SPA (frontend/dist) : un seul conteneur +# suffit, pas de nginx séparé. On builde donc le frontend ici puis on copie le +# résultat dans l'image Python finale. +FROM node:22-alpine AS frontend + +WORKDIR /frontend +COPY frontend/package.json frontend/package-lock.json* ./ +RUN npm install +COPY frontend/ ./ +RUN npm run build + +# --- Étape 2 : image applicative Python -------------------------------------- FROM python:3.12-slim # pdfplumber est en Python pur : aucune dépendance système (plus de poppler). @@ -11,6 +26,11 @@ RUN uv sync --frozen --no-dev --no-install-project COPY src/ src/ RUN uv sync --frozen --no-dev +# Frontend buildé : servi par le backend via le fallback SPA (api/app.py). +COPY --from=frontend /frontend/dist/ frontend/dist/ + EXPOSE 8000 -CMD ["uv", "run", "plesna-gerance", "serve", "--host", "0.0.0.0"] +# --no-sync : ne pas re-résoudre/installer au démarrage (l'env est déjà figé +# par les `uv sync --frozen` ci-dessus). Sinon `uv run` réinstalle les deps dev. +CMD ["uv", "run", "--no-sync", "plesna-gerance", "serve", "--host", "0.0.0.0"] diff --git a/docker-compose.yml b/docker-compose.yml index 08d620a..2f332f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,16 @@ services: - backend: + app: build: context: . dockerfile: backend.Dockerfile + ports: + # hôte:conteneur — l'app (API + interface web) écoute sur 8000 + - "8080:8000" volumes: + # Persiste base SQLite + documents hors du conteneur. - ./data:/app/data environment: - - PLESNA_DB_PATH=/app/data/database.sqlite - - PLESNA_STORAGE_PATH=/app/data/documents - restart: unless-stopped - - frontend: - build: - context: ./frontend - dockerfile: Dockerfile - ports: - - "8080:80" - depends_on: - - backend + # Déclare l'emplacement des données ; get_data_dir() en dérive + # database.sqlite et documents/ (cf. src/plesna_gerance/paths.py). + - PLESNA_DATA_DIR=/app/data restart: unless-stopped diff --git a/frontend/.dockerignore b/frontend/.dockerignore deleted file mode 100644 index f06235c..0000000 --- a/frontend/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist diff --git a/frontend/Dockerfile b/frontend/Dockerfile deleted file mode 100644 index 6867b95..0000000 --- a/frontend/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:22-alpine AS build - -WORKDIR /app -COPY package.json package-lock.json* ./ -RUN npm install -COPY . . -RUN npm run build - -FROM nginx:alpine -COPY --from=build /app/dist /usr/share/nginx/html -COPY nginx.conf /etc/nginx/conf.d/default.conf -EXPOSE 80 diff --git a/frontend/nginx.conf b/frontend/nginx.conf deleted file mode 100644 index d634563..0000000 --- a/frontend/nginx.conf +++ /dev/null @@ -1,19 +0,0 @@ -server { - listen 80; - root /usr/share/nginx/html; - index index.html; - - # Proxy API requests to backend - location /api { - proxy_pass http://backend:8000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - client_max_body_size 50M; - } - - # SPA fallback - location / { - try_files $uri $uri/ /index.html; - } -}