Table des matières
ChitUI : Une passerelle locale vers les imprimantes résine
ChitUI fournit une interface web pour des imprimantes résine SDCP. Un processus Python sert les ressources web, découvre les imprimantes sur le réseau local et traduit les actions du navigateur en communications avec les machines.
- Langages
- 5Répartition du code
- Composants documentés
- 2Explorer les modules
- Documents source
- 1Lire les instructions
Langages du dépôtJavaScript 48.61%5
Parts calculées à partir des octets GitHub Linguist.
| Langage | % | Octets |
|---|---|---|
| JavaScript | 21 743 | |
| HTML | 10 991 | |
| Python | 10 226 | |
| CSS | 1 572 | |
| Dockerfile | 200 |
1. Aperçu
1.1. Pourquoi il existe
Interface de contrôle web pour imprimantes 3D résine SDCP 3.0 avec découverte UDP sur LAN.
1.2. Cas d’usage
Contrôle à distance d'imprimantes 3D résine sans poste dédié.
2. Cas d’utilisation
Interface web Flask qui trouve les imprimantes résine SDCP 3.0 (Chitubox) du réseau, envoie des fichiers et lance l’impression.
- Découvrir les imprimantes
- Opérateur d’impressionImprimante résine SDCP
Au démarrage, discover_printers (main.py) diffuse M99999 en UDP sur le port 3000, enregistre les réponses et ouvre un WebSocket vers chaque imprimante sur ws://<ip>:3030/websocket.
- Suivre l’état de l’imprimante
- Opérateur d’impressionImprimante résine SDCP
Le navigateur interroge par Socket.IO ; main.py envoie les commandes SDCP 0 (état) et 1 (attributs) et relaie les messages de l’imprimante vers web/js/chitui.js et sdcp.js.
- Téléverser un fichier
- Opérateur d’impressionImprimante résine SDCP
POST /upload accepte les fichiers .ctb, .goo et .prz, calcule un MD5 et envoie des morceaux de 1 Mo à http://<ip>:3030/uploadFile/upload ; /progress diffuse le pourcentage.
- Lister et effacer les fichiers
- Opérateur d’impressionImprimante résine SDCP
printer_files envoie la commande SDCP 258 avec un chemin de stockage ; action_delete envoie la commande 259 avec la liste des fichiers.
- Lancer une impression
- Opérateur d’impressionImprimante résine SDCP
action_print envoie la commande SDCP 128 avec le nom du fichier et StartLayer 0.
2.1. Scénario : Envoyer un modèle tranché à une imprimante résine depuis le navigateur
- Installer requirements.txt dans un virtualenv et lancer python main.py, ou docker run --net=host pour que la diffusion UDP fonctionne.
- Au démarrage, ChitUI diffuse M99999 sur le port UDP 3000 et se connecte au WebSocket de chaque imprimante sur le port 3030.
- Ouvrir http://127.0.0.1:54780/ pour voir les imprimantes trouvées et leur état.
- Téléverser un fichier .ctb ; ChitUI l’enregistre dans /tmp puis l’envoie en morceaux de 1 Mo avec contrôle MD5.
- Choisir le fichier dans la liste de l’imprimante et lancer l’impression.
Fichiers consultésREADME.mdmain.pyrequirements.txtDockerfileTODO.txtweb/js/chitui.jsweb/js/sdcp.js
3. Démarrage
Ces commandes viennent de la documentation du dépôt. Elles n’ont pas été exécutées pendant cette revue.
python -mvenv .venv
source .venv/bin/activate
pip install -r requirements.txtpython main.pydocker build -t chitui:latest .
docker run --rm --name chitui --net=host chitui:latest4. Références du dépôt
Extraits des guides du dépôt, dans leur langue d’origine. Les liens ouvrent la version du code consultée.
Configuration et utilisation
4.1. Usage
README.md
4.2. Configuration
README.md
Configuration is done via environment variables:
- PORT to set the HTTP port of the web interface (default: 54780)
- DEBUG to enable debug logging, log colorization and code reloading (default: False)
5. Fonctions et composants 2
- Navigateur et serveur local
- main.py crée une application Flask dont les fichiers statiques se trouvent dans web et y ajoute Flask-SocketIO. Les registres d’imprimantes et de WebSocket restent en mémoire. La découverte locale explique l’exigence de réseau hôte Docker du README.
- Transfert de fichier
- La route d’envoi valide l’extension et conserve temporairement le fichier. La fonction de transfert calcule une empreinte MD5 et transmet des blocs d’un mégaoctet avec leurs décalages. Une route de flux d’événements expose la progression.
6. Architecture
Ouvrez un composant pour suivre ses connexions, ou explorez le diagramme complet.
Interface web
- Vers Flask et SocketIO
Flask et SocketIO
- Depuis Interface web
- Vers Découverte et session imprimante
Découverte et session imprimante
- Depuis Flask et SocketIO
- Vers Imprimante SDCP
- Depuis Imprimante SDCP
Imprimante SDCP
Mermaid Diagramme interactif
Vue générale des composants et des échanges vérifiés dans le dépôt.

flowchart LR
subgraph group_server["Server and discovery"]
node_app["HTTP and Socket.IO server<br/>[main.py]"]
node_discovery["Printer discovery<br/>[main.py]"]
node_upload["File upload handling<br/>[main.py]"]
node_transfer["Printer file transfer<br/>[main.py]"]
end
subgraph group_printer["Printer communication"]
node_commands["SDCP commands<br/>[main.py]"]
node_connection["Printer WebSocket connection<br/>[main.py]"]
end
subgraph group_webui["Browser interface"]
node_index["Web page entry<br/>[index.html]"]
node_ui["Printer dashboard and actions<br/>[chitui.js]"]
node_protocol["SDCP constants<br/>[sdcp.js]"]
node_theme["Theme preferences<br/>[color-modes.js]"]
end
node_user(("Operator"))
node_browser(("Web browser"))
node_printer["SDCP printer"]
node_user -->|"uses"| node_browser
node_browser -->|"opens interface"| node_app
node_app -->|"serves"| node_index
node_user -->|"operates"| node_ui
node_ui -->|"sends events"| node_app
node_app -->|"emits updates"| node_ui
node_app -->|"runs discovery"| node_discovery
node_discovery -->|"broadcasts discovery"| node_printer
node_app -->|"connects printers"| node_connection
node_connection -->|"opens WebSocket"| node_printer
node_app -->|"dispatches requests"| node_commands
node_commands -->|"sends SDCP"| node_printer
node_printer -->|"sends messages"| node_connection
node_connection -->|"routes printer events"| node_app
node_browser -->|"posts print file"| node_upload
node_app -->|"handles upload"| node_upload
node_upload -->|"starts transfer"| node_transfer
node_transfer -->|"uploads file"| node_printer
node_ui -->|"uses constants"| node_protocol
node_index -.->|"loads interface code"| node_ui
node_index -.->|"loads theme control"| node_theme
class node_app,node_discovery,node_upload,node_transfer,node_browser toneBlue
class node_commands,node_connection toneAmber
class node_index,node_ui,node_protocol,node_theme toneMint
class node_user,node_printer toneIndigoUn panneau de contrôle web pour les imprimantes résine utilisant Chitubox SDCP 3.0. Le serveur découvre les imprimantes, ouvre les connexions WebSocket, dirige les commandes et les états, puis transfère les fichiers téléversés pendant que le navigateur présente les contrôles.
- Composants
- 13
- Connexions
- 21
- Liens appuyés par le code
- 16/21
Version texte du diagramme
- Interface web → Flask et SocketIO
- Flask et SocketIO → Découverte et session imprimante
- Découverte et session imprimante → Imprimante SDCP
- Imprimante SDCP → Découverte et session imprimante
Suivre un parcours dans le code
Suivez /upload jusqu’au fichier temporaire et à la fonction de transfert. La progression est globale dans cette implémentation; des envois simultanés nécessiteraient un état par tâche pour éviter de mélanger leurs pourcentages.
7. Dossier technique
Établi à partir du code au commit a423617 (7 fichiers). Chaque élément vient d’une correspondance de motif dans le code: ouvrez le fichier lié avant de vous y fier.
7.1. Couches et modules
Les dossiers sont classés par couche selon leur nom, de l’interface utilisateur jusqu’à l’accès aux données. Comme le classement repose sur les noms seulement, le diagramme ne dit rien des appels entre couches.
Mermaid Vue en couches
flowchart TB
subgraph L_presentation["Présentation"]
direction TB
presentation_0["web/js<br/>3 fichiers"]
presentation_1["web<br/>1 fichier"]
presentation_2["web/css<br/>1 fichier"]
end
subgraph L_interface["Points d’entrée et API"]
direction TB
interface_0["(root)<br/>1 fichier"]
end
subgraph L_hosting["Build, CI et hébergement"]
direction TB
hosting_0["(root)<br/>1 fichier"]
end
L_presentation ~~~ L_interface
L_interface ~~~ L_hosting
7.2. Modèle C4
Du contexte du système aux déclarations du code. Chaque niveau conserve les limites des sources disponibles.
UML 1 · Contexte du système
La vue C4 la plus large : qui utilise le projet et sur quels systèmes et stockages externes il s’appuie. Rendu avec uml-mcp.
Source PlantUML
@startuml
!include <C4/C4_Context>
LAYOUT_LEFT_RIGHT()
Person(P_http, "Client HTTP")
System(SYS, "ChitUI", "ChitUI fournit une interface web pour des imprimantes résine SDCP")
Rel(P_http, SYS, "Utilise")
@enduml
UML 2 · Conteneurs
Un niveau plus près : les parties qui s’exécutent séparément dans le projet, leur langage principal et le chemin des appels entre elles. Rendu avec uml-mcp.
Source PlantUML
@startuml
!include <C4/C4_Container>
LAYOUT_LEFT_RIGHT()
Person(P_http, "Client HTTP")
System_Boundary(SYS, "ChitUI") {
Container(APP, "ChitUI", "JavaScript")
}
Rel(P_http, APP, "Utilise")
@enduml
UML 3 · Composants et couches
Modules regroupés par couche du code. Les limites indiquent l’organisation, sans affirmer une isolation à l’exécution ni des appels. Rendu avec uml-mcp.
Source PlantUML
@startuml
!include <C4/C4_Component>
LAYOUT_TOP_DOWN()
System_Boundary(SYS, "ChitUI") {
Boundary(L0, "Présentation", "layer") {
Component(M0_0, "web/js", "JavaScript", "6 fichiers")
Component(M0_1, "web/css", ".css", "3 fichiers")
Component(M0_2, "web", "HTML", "1 fichiers")
}
Boundary(L1, "Points d’entrée et API", "layer") {
Component(M1_0, "(root)", "Python", "1 fichiers")
}
Boundary(L2, "Build, CI et hébergement", "layer") {
Component(M2_0, "(root)", "Dockerfile", "1 fichiers")
}
}
@enduml
UML 4 · Code
Déclarations, champs et méthodes sélectionnés, regroupés par fichier source. Aucun héritage ni appel n’est déduit. Rendu avec uml-mcp.
Source PlantUML
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
top to bottom direction
hide empty members
package "ChitUI" {
object "main.py" as FN0 {
web_index()
progress()
publish_progress()
get_upload_progress()
upload_file()
allowed_file()
}
}
@enduml
7.3. Flux de données
Les appels du diagramme GitDiagram, dans l’ordre où on les rencontre depuis les points d’entrée. GitDiagram produit ce graphe par IA; les chemins de fichiers cités ont été comparés à l’arbre du dépôt.
Mermaid Diagramme de séquence
sequenceDiagram
autonumber
participant P0 as Operator
participant P1 as Web browser
participant P2 as Printer dashboard and actions
participant P3 as HTTP and Socket.IO server
participant P4 as File upload handling
participant P5 as SDCP constants
participant P6 as Web page entry
participant P7 as Printer discovery
participant P8 as Printer WebSocket connection
participant P9 as SDCP commands
participant P10 as Printer file transfer
participant P11 as Theme preferences
participant P12 as SDCP printer
P0->>P1: uses
P0->>P2: operates
P1->>P3: opens interface
P1->>P4: posts print file
P2->>P3: sends events
P2->>P5: uses constants
P3->>P6: serves
P3->>P2: emits updates
P3->>P7: runs discovery
P3->>P8: connects printers
P3->>P9: dispatches requests
P3->>P4: handles upload
P4->>P10: starts transfer
P6--)P2: loads interface code
P6--)P11: loads theme control
P7->>P12: broadcasts discovery
Étapes en texte
- Operator vers Web browser uses
- Operator vers Printer dashboard and actions operates
- Web browser vers HTTP and Socket.IO server opens interface
- Web browser vers File upload handling posts print file
- Printer dashboard and actions vers HTTP and Socket.IO server sends events
- Printer dashboard and actions vers SDCP constants uses constants
- HTTP and Socket.IO server vers Web page entry serves
- HTTP and Socket.IO server vers Printer dashboard and actions emits updates
- HTTP and Socket.IO server vers Printer discovery runs discovery
- HTTP and Socket.IO server vers Printer WebSocket connection connects printers
- HTTP and Socket.IO server vers SDCP commands dispatches requests
- HTTP and Socket.IO server vers File upload handling handles upload
- File upload handling vers Printer file transfer starts transfer
- Web page entry vers Printer dashboard and actions loads interface code
- Web page entry vers Theme preferences loads theme control
- Printer discovery vers SDCP printer broadcasts discovery
- Printer WebSocket connection vers SDCP printer opens WebSocket
- Printer WebSocket connection vers HTTP and Socket.IO server routes printer events
- SDCP commands vers SDCP printer sends SDCP
- Printer file transfer vers SDCP printer uploads file
- SDCP printer vers Printer WebSocket connection sends messages
7.4. Interface publique
Du code extérieur peut utiliser tout ce qui est listé ici. Le projet déclare aussi 0 types publics.
UML Cas d’utilisation
Chaque acteur est un type d’appelant, relié à ce qu’il peut demander au projet. Rendu avec uml-mcp.
Source PlantUML
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
left to right direction
actor "Client HTTP" as A_http
rectangle "ChitUI" {
usecase "ANY /" as U0
usecase "ANY /progress" as U1
usecase "ANY /upload" as U2
}
A_http --> U0
A_http --> U1
A_http --> U2
@enduml
Routes HTTP 3
Mermaid Carte des routes par préfixe
flowchart LR
api(["HTTP API"])
g0["/"]
api --> g0
g0r0["ANY /"]
g0 --> g0r0
g1["/progress"]
api --> g1
g1r0["ANY /progress"]
g1 --> g1r0
g2["/upload"]
api --> g2
g2r0["ANY /upload"]
g2 --> g2r0
| Méthode | Chemin | Source |
|---|---|---|
| ANY | / | main.py:43 |
| ANY | /progress | main.py:48 |
| ANY | /upload | main.py:61 |
Points d’entrée
main.pyfichier d’entrée
7.5. Logique métier
Aucune classe n’a été extraite. Voici les plus gros fichiers source et leurs fonctions.
main.pyweb_index, progress, publish_progress, get_upload_progress, upload_file, allowed_file
7.6. Base de données et persistance
7.7. Intégrations externes
Clients HTTP
7.8. Stack et dépendances
Python requirements.txt 5 à l’exécution
Dépendances externes
5 paquets déclarés (5 à l’exécution, 0 pour le développement) dans requirements.txt.
Tableau des paquets 5
| Paquet | Version | Usage | Rôle | Registre |
|---|---|---|---|---|
flask | ==3.0.3 | exécution | Cadriciel web | pypi.org |
flask-socketio | ==5.4.1 | exécution | Cadriciel web | pypi.org |
websocket-client | ==1.8.0 | exécution | Messagerie temps réel | pypi.org |
requests | ==2.32.3 | exécution | Client HTTP | pypi.org |
loguru | ==0.7.2 | exécution | Journalisation et observabilité | pypi.org |
7.9. Pipeline CI/CD
Aucun pipeline CI/CD dans le dépôt, en dehors de GitLab CI. Le code se construit et se lance à la main, comme décrit plus haut.
7.10. Déploiement
Mermaid Schéma de déploiement
flowchart LR
repo[("Dépôt GitHub")]
ci_GitLab_CI[["GitLab CI"]]
image["Image Docker<br/>FROM python:3.12-alpine"]
repo --> ci_GitLab_CI
repo -->|"docker build"| image
UML Déploiement
Le nœud extérieur est l’endroit où le code s’exécute. Chaque image de base pointe vers ce qu’elle construit, les flèches pleines mènent aux bases de données et les pointillées aux services externes. Rendu avec uml-mcp.
Source PlantUML
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
node "Image Docker" as H {
artifact "ChitUI" as APP
}
artifact "FROM python:3.12-alpine" as IMG0
IMG0 ..> APP : construit
cloud "WebSocket" as E0
APP ..> E0
@enduml
Où il s’exécute
Images Docker de base
7.11. Supervision
Ce que le code consigne, mesure et expose pour savoir s’il fonctionne.
7.12. Sécurité
Variables d’environnement 2
La page reprend les noms sans leurs valeurs et souligne ceux qui ressemblent à des secrets.
Rien trouvé pour: Interface privée, Services, Entités, Tests automatisés.
8. Parcours
Vue pas à pas du chemin inspecté dans le dépôt. Ce n’est pas une exécution en direct.
9. API de transfert vers l’imprimante
POST /upload accepte les champs multipart file et printer. L’identifiant sélectionne une entrée du dictionnaire des imprimantes découvertes. Les extensions acceptées sont ctb, goo et prz. Le serveur crée un fichier temporaire et transfère des blocs au point d’accès de l’imprimante sur le port 3030.
| Méthode | Chemin | Contrôle vérifié | Fichier |
|---|---|---|---|
POST | /upload | Aucun contrôle d’authentification dans le gestionnaire inspecté. Les champs multipart file et printer sont requis. | main.py |
GET | /upload | Aucun contrôle d’authentification. Le gestionnaire inspecté retourne 405. | main.py |
GET | /progress | Aucun contrôle d’authentification dans le gestionnaire inspecté. La réponse est un text/event-stream partagé entre les transferts. | main.py |
POST /upload
Content-Type: multipart/form-data
file: [supported print file]
printer: [identifier returned by discovery]9.1. Réponse et erreurs
Authentification, limites et pagination
Les gestionnaires inspectés n’ont ni authentification ni limiteur de débit. Gardez cette interface sur un réseau de confiance. La progression est globale et ne distingue pas les transferts simultanés. La pagination ne s’applique pas à cette opération.
10. Déploiement et exploitation
Les ports, le stockage et les relations de démarrage ci-dessous viennent de la configuration du dépôt. depends_on indique l’ordre de démarrage, pas la disponibilité du service.
Réseau. Host network (--net=host), requested in the README so UDP broadcast can reach the LAN.
11. Référence
6 / 6 fichiers admissibles lus (31 dans l’arbre); 0 trop volumineux, 0 échec de lecture et 0 diagnostic de syntaxe.
Ce que couvre l’analyse
Les dossiers connus de dépendances et de compilation, les fichiers d’identifiants et les binaires sont exclus. La collecte couvre les README, les manifestes reconnus et les fichiers source pris en charge.
Les statistiques Linguist couvrent l’ensemble du dépôt et peuvent inclure d’autres langages.
13. Fichiers à lire 3
14. Glossaire
Dépôt
Les fichiers source, la configuration et l’historique versionné d’un projet.
README
Le document d’entrée du dépôt, qui présente généralement son rôle et son installation.
Dépendance
Une bibliothèque, un outil ou un service nécessaire à la compilation ou à l’exécution d’un composant.
HTTP
Un protocole de requête et réponse utilisé par les navigateurs et services web. Une requête comprend une méthode, un chemin, des en-têtes et parfois un corps.
Session
Un état conservé entre plusieurs requêtes, souvent pour suivre un utilisateur connecté. L’authentification et les permissions restent des vérifications distinctes.
Conteneur
Un environnement de processus isolé créé à partir d’une image. Les données persistantes nécessitent un stockage hors de son système de fichiers temporaire.
Port publié
Un port de l’hôte associé au port d’un service dans un conteneur. Sa publication peut rendre le service accessible hors du réseau des conteneurs.
Interface en ligne de commande
Une interface textuelle où les commandes et arguments choisissent les opérations. Les codes de retour permettent aux scripts de détecter un succès ou un échec.
Compilation
Les étapes qui transforment les sources et dépendances en programme exécutable ou en livrable distribuable.
15. Références
- antoinebou12. (2026, 5 novembre). ChitUI. [Software repository] github.com.
- antoinebou12. (2026, 5 novembre). ChitUI: README. [Repository documentation] github.com.
- antoinebou12. (2026, 5 novembre). main.py. [Source file] github.com.
- antoinebou12. (2026, 5 novembre). Dockerfile. [Source file] github.com.
- antoinebou12. (2026, 5 novembre). requirements.txt. [Source file] github.com.
- Boucher, A. (2026, 23 octobre). ChitUI : Une passerelle locale vers les imprimantes résine. [Project article] antoineboucher.info.
Les sources sans date de publication indiquent la date de leur dernière vérification, le 5 novembre 2026. Les liens des fichiers conservent la révision inspectée lorsqu’elle est disponible.
Fiche projet