add docker compose

This commit is contained in:
Julien Aldon
2026-02-19 17:34:15 +01:00
parent 1bd0583c70
commit 7574626e52
14 changed files with 199 additions and 43 deletions

13
backend/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
FROM python:3.12
WORKDIR /code
RUN apt update && apt install -y weasyprint
COPY ./backend/requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./backend /code/app
CMD ["fastapi", "run", "app/src/main.py", "--port", "8000"]

65
backend/requirements.txt Normal file
View File

@@ -0,0 +1,65 @@
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.12.1
brotli==1.2.0
certifi==2026.1.4
cffi==2.0.0
charset-normalizer==3.4.4
click==8.3.1
cryptography==46.0.5
cssselect2==0.9.0
dnspython==2.8.0
email-validator==2.3.0
fastapi==0.129.0
fastapi-cli==0.0.23
fastapi-cloud-cli==0.13.0
fastar==0.8.0
fonttools==4.61.1
greenlet==3.3.1
h11==0.16.0
httpcore==1.0.9
httptools==0.7.1
httpx==0.28.1
idna==3.11
Jinja2==3.1.6
lxml==6.0.2
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mdurl==0.1.2
odfdo==3.20.2
pillow==12.1.1
psycopg2-binary==2.9.11
pycparser==3.0
pydantic==2.12.5
pydantic-extra-types==2.11.0
pydantic-settings==2.13.1
pydantic_core==2.41.5
pydyf==0.12.1
Pygments==2.19.2
PyJWT==2.11.0
pyphen==0.17.2
python-dotenv==1.2.1
python-multipart==0.0.22
PyYAML==6.0.3
requests==2.32.5
rich==14.3.2
rich-toolkit==0.19.4
rignore==0.7.6
sentry-sdk==2.53.0
shellingham==1.5.4
SQLAlchemy==2.0.46
sqlmodel==0.0.34
starlette==0.52.1
tinycss2==1.5.1
tinyhtml5==2.0.0
typer==0.24.0
typing-inspection==0.4.2
typing_extensions==4.15.0
urllib3==2.6.3
uvicorn==0.41.0
uvloop==0.22.1
watchfiles==1.1.1
weasyprint==68.1
webencodings==0.5.1
websockets==16.0
zopfli==0.4.1

View File

@@ -1,7 +1,7 @@
from sqlmodel import create_engine, SQLModel, Session from sqlmodel import create_engine, SQLModel, Session
from src.settings import settings from src.settings import settings
engine = create_engine(f'postgresql://{settings.db_user}:{settings.db_pass}@{settings.db_host}:54321/{settings.db_name}') engine = create_engine(f'postgresql://{settings.db_user}:{settings.db_pass}@{settings.db_host}:5432/{settings.db_name}')
def get_session(): def get_session():
with Session(engine) as session: with Session(engine) as session:

View File

@@ -28,13 +28,13 @@ app.add_middleware(
) )
app.include_router(template_router) app.include_router(template_router, prefix="/api")
app.include_router(contracts_router) app.include_router(contracts_router, prefix="/api")
app.include_router(forms_router) app.include_router(forms_router, prefix="/api")
app.include_router(productors_router) app.include_router(productors_router, prefix="/api")
app.include_router(products_router) app.include_router(products_router, prefix="/api")
app.include_router(users_router) app.include_router(users_router, prefix="/api")
app.include_router(auth_router) app.include_router(auth_router, prefix="/api")
app.include_router(shipment_router) app.include_router(shipment_router, prefix="/api")
SQLModel.metadata.create_all(engine) SQLModel.metadata.create_all(engine)

View File

@@ -1,32 +1,39 @@
version: "3.9"
services: services:
# nginx: nginx:
# restart: always restart: always
# build: build:
# context: . context: .
# dockerfile: front/Dockerfile dockerfile: frontend/Dockerfile
# args: args:
# VUE_APP_ROOT_FQDN: ${SERVICE_ROOT_FQDN} VITE_API_URL: ${VITE_API_URL}
# ports: ports:
# - 80:80 - 80:80
# depends_on: depends_on:
# - back - back
# back: back:
# build: build:
# context: . context: .
# dockerfile: back/Dockerfile dockerfile: backend/Dockerfile
# restart: always restart: always
# environment: environment:
# SERVICE_ORIGIN: ${SERVICE_ORIGIN} ORIGINS: ${ORIGINS}
# DB_HOST: database DB_HOST: database
# MARIADB_USER: ${MARIADB_USER} DB_USER: ${DB_USER}
# MARIADB_PASSWORD: ${MARIADB_PASSWORD} DB_PASS: ${DB_PASS}
# MARIADB_DATABASE: ${MARIADB_DATABASE} DB_NAME: ${DB_NAME}
# SERVICE_SECRET_KEY: ${SERVICE_SECRET_KEY} SECRET_KEY: ${SECRET_KEY}
# ports: VITE_API_URL: ${VITE_API_URL}
# - 8000:8000 KEYCLOAK_SERVER: ${KEYCLOAK_SERVER}
# depends_on: KEYCLOAK_REALM: ${KEYCLOAK_REALM}
# - database KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID}
KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET}
KEYCLOAK_REDIRECT_URI: ${KEYCLOAK_REDIRECT_URI}
DEBUG: ${DEBUG}
MAX_AGE: ${MAX_AGE}
ports:
- 8000:8000
depends_on:
- database
database: database:
image: postgres image: postgres
restart: always restart: always
@@ -35,8 +42,5 @@ services:
POSTGRES_USER: ${DB_USER} POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASS} POSTGRES_PASSWORD: ${DB_PASS}
POSTGRES_DB: ${DB_NAME} POSTGRES_DB: ${DB_NAME}
ROOT_FQDN: ${ROOT_FQDN}
ports:
- "54321:5432"
volumes: volumes:
db: db:

20
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM node:20.19-alpine AS build
WORKDIR /app
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
COPY frontend/package.json frontend/package-lock.json /app/
RUN npm install
COPY frontend/ .
RUN npm run build
FROM nginx:latest
COPY --from=build /app/dist /srv/www/frontend
RUN rm /etc/nginx/conf.d/default.conf
COPY --from=build /app/nginx/default.conf /etc/nginx/conf.d/default.conf

View File

@@ -199,6 +199,7 @@
"your session has expired please log in again": "your session has expired please log in again", "your session has expired please log in again": "your session has expired please log in again",
"session expired": "session expired", "session expired": "session expired",
"user not allowed": "user not allowed", "user not allowed": "user not allowed",
"roles": "roles",
"your keycloak user has no roles, please contact your administrator": "your keycloak user has no roles, please contact your administrator", "your keycloak user has no roles, please contact your administrator": "your keycloak user has no roles, please contact your administrator",
"choose payment method": "choose your payment method (you do not need to pay now).", "choose payment method": "choose your payment method (you do not need to pay now).",
"the product unit will be assigned to the quantity requested in the form": "the product unit defines the unit used in the contract form.", "the product unit will be assigned to the quantity requested in the form": "the product unit defines the unit used in the contract form.",

View File

@@ -199,6 +199,7 @@
"your session has expired please log in again": "votre session a expiré veuillez vous reconnecter.", "your session has expired please log in again": "votre session a expiré veuillez vous reconnecter.",
"session expired": "session expirée", "session expired": "session expirée",
"user not allowed": "utilisateur non authorisé", "user not allowed": "utilisateur non authorisé",
"roles": "roles",
"your keycloak user has no roles, please contact your administrator": "votre utilisateur keycloak n'a pas de roles configurés, contactez votre administrateur.", "your keycloak user has no roles, please contact your administrator": "votre utilisateur keycloak n'a pas de roles configurés, contactez votre administrateur.",
"choose payment method": "choisissez votre méthode de paiement (vous n'avez pas à payer tout de suite, uniquement renseigner comment vous souhaitez régler votre commande).", "choose payment method": "choisissez votre méthode de paiement (vous n'avez pas à payer tout de suite, uniquement renseigner comment vous souhaitez régler votre commande).",
"the product unit will be assigned to the quantity requested in the form": "l'unité de vente du produit définit l'unité associée à la quantité demandée dans le formulaire des amapiens.", "the product unit will be assigned to the quantity requested in the form": "l'unité de vente du produit définit l'unité associée à la quantité demandée dans le formulaire des amapiens.",

View File

@@ -0,0 +1,26 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
root /srv/www/frontend;
index index.html;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://back;
}
}
upstream backend {
server back:8000;
}

View File

@@ -3,7 +3,6 @@ import {
Group, Group,
Modal, Modal,
MultiSelect, MultiSelect,
Select,
TextInput, TextInput,
Title, Title,
type ModalBaseProps, type ModalBaseProps,

View File

@@ -1,4 +1,4 @@
import { ActionIcon, Table, Tooltip } from "@mantine/core"; import { ActionIcon, Badge, Box, Table, Tooltip } from "@mantine/core";
import { t } from "@/config/i18n"; import { t } from "@/config/i18n";
import { IconEdit, IconX } from "@tabler/icons-react"; import { IconEdit, IconX } from "@tabler/icons-react";
import { type User } from "@/services/resources/users"; import { type User } from "@/services/resources/users";
@@ -18,6 +18,31 @@ export default function UserRow({ user }: UserRowProps) {
<Table.Tr key={user.id}> <Table.Tr key={user.id}>
<Table.Td>{user.name}</Table.Td> <Table.Td>{user.name}</Table.Td>
<Table.Td>{user.email}</Table.Td> <Table.Td>{user.email}</Table.Td>
<Table.Td style={{maxWidth: 200}}>
<Box
style={{
display: 'flex',
gap: 4
}}
>
{user.roles.slice(0, 3).map((value) => (
<Badge key={value.id} size="xs">
{t(value.name, { capfirst: true })}
</Badge>
))}
{
user.roles.length > 3 && (
<Tooltip
label={user.roles.slice(3).map(role=>`${role.name} `)}
>
<Badge size="xs" variant="light">
+{user.roles.length - 3}
</Badge>
</Tooltip>
)
}
</Box>
</Table.Td>
<Table.Td> <Table.Td>
<Tooltip label={t("edit user", { capfirst: true })}> <Tooltip label={t("edit user", { capfirst: true })}>
<ActionIcon <ActionIcon

View File

@@ -89,6 +89,7 @@ export default function Contracts() {
label={t("download recap", { capfirst: true })} label={t("download recap", { capfirst: true })}
> >
<ActionIcon <ActionIcon
disabled={true}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
navigate( navigate(

View File

@@ -127,6 +127,7 @@ export default function Users() {
<Table.Tr> <Table.Tr>
<Table.Th>{t("name", { capfirst: true })}</Table.Th> <Table.Th>{t("name", { capfirst: true })}</Table.Th>
<Table.Th>{t("email", { capfirst: true })}</Table.Th> <Table.Th>{t("email", { capfirst: true })}</Table.Th>
<Table.Th>{t("roles", { capfirst: true })}</Table.Th>
<Table.Th>{t("actions", { capfirst: true })}</Table.Th> <Table.Th>{t("actions", { capfirst: true })}</Table.Th>
</Table.Tr> </Table.Tr>
</Table.Thead> </Table.Thead>

View File

@@ -15,7 +15,7 @@ export type User = {
name: string; name: string;
email: string; email: string;
products: Product[]; products: Product[];
roles: string[]; roles: Role[];
}; };
export type UserInputs = { export type UserInputs = {