Appearance
Depot et consultation de fichiers
Vue d'ensemble
Le depot de fichiers permet a un client externe d'envoyer tout type de fichier via l'interface web. Le fichier transite par le backend NestJS qui le valide, le transfere vers Scaleway Object Storage (S3), puis enregistre les metadonnees en base.
La page AdminFolderDetailPage expose la liste des fichiers deja deposes par l'utilisateur connecte et trié dans des dossiers. Cette liste est chargee via GET /documents, triee par date de depot decroissante, et affiche le nom, la date et la taille de chaque fichier.
Chaque fichier de la liste peut etre telecharge via GET /documents/:uuid/download. Le backend verifie l'appartenance du document a l'utilisateur connecte, puis genere une URL S3 pre-signee temporaire en attachment.
Le menu d'actions permet aussi de copier un lien applicatif securise (/files/:documentUuid). A l'ouverture de ce lien, le front appelle GET /documents/:uuid/access-url; le backend revalide les droits puis genere une URL S3 pre-signee temporaire en inline.
Ce choix est documente dans l'ADR-03.
Flux complet
mermaid
flowchart TD
U["👤 Client externe"]
F["🖥️ AdminFolderDetailPage"]
API["🧠 DocumentController"]
AUTH["🔐 AuthGuard"]
SERVICE["⚙️ DocumentService"]
S3["☁️ Scaleway Object Storage"]
DB[("🗄️ prisma.tool<br/>documents / users_documents")]
U --> F
F -->|"POST /documents<br/>multipart/form-data"| API
F -->|"GET /documents<br/>liste des depots"| API
API --> AUTH --> SERVICE
SERVICE -->|"upload binaire"| S3
SERVICE -->|"metadonnees + liaison user"| DB
DB -->|"liste triee created_at desc"| SERVICE
SERVICE -->|"URL pre-signee attachment"| S3
SERVICE --> API --> FEtape par etape
1. Frontend — envoi du fichier
Fichiers : front/src/pages/admin/folders/AdminFolderDetailPage.vue, front/src/stores/files-store.js
- L'utilisateur depose un fichier (drag & drop ou selecteur)
- Validation client : taille uniquement (max 50 Mo par defaut)
- Le store envoie le fichier en
multipart/form-datavia axios :jsapi.post('/documents', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (e) => { /* progression */ } }) - Le jeton applicatif est injecte automatiquement par l'intercepteur axios (
X-App-Access-Token: ...)
1 bis. Frontend — consultation des fichiers deposes
Fichiers : front/src/pages/admin/folders/AdminFolderDetailPage.vue, front/src/components/documents/DocumentListItem.vue, front/src/stores/files-store.js
- Au montage de
/dossiers, la page appellefileStore.fetchDocuments() - Le store effectue un
GET /documents - La section
Mes fichiers deposesaffiche :- le nom du fichier
- l'extension
- la date de depot formatee
- la taille formatee (
o,Ko,Mo)
- La vue admin d'un dossier affiche aussi le deposant du fichier quand l'information est disponible
- La section est repliable/depliable et affiche un etat vide si aucun document n'est disponible
- Apres un upload reussi,
fetchDocuments()est relance pour rafraichir la liste - Chaque ligne expose une action
Telecharger, qui appelleGET /documents/:uuid/download - Chaque ligne expose une action
Copier le lien, qui copie une URL applicative/files/:documentUuid
2. Backend — authentification
Fichier : back/src/guards/authGuard.ts
L'AuthGuard verifie :
X-App-Access-Tokenest present et valide- Le jeton cible bien
bddsur l'environnement courant - L'utilisateur est provisionne dans la base tool (
prisma.tool.users) - L'utilisateur a un role assigne
Si une de ces conditions echoue → 401 Unauthorized.
3. Backend — validation du fichier
Fichier : back/src/api/documents/document.service.ts
| Validation | Regle | Erreur |
|---|---|---|
| Fichier present | Le champ files doit contenir un fichier | 400 Missing file |
| Type de fichier | Tout type accepte, y compris sans extension | - |
| Taille | Max FILE_SIZE_LIMIT Mo (defaut 50) | 413 File is too large |
4. Backend — upload vers Scaleway S3
Fichier : back/src/domains/s3Helper/uploadFile.ts
Le fichier est envoye vers Scaleway Object Storage via le SDK AWS S3 (protocole compatible) :
- Client S3 : configure avec les credentials Scaleway (
UPLOAD_S3_ACCESS_KEY,UPLOAD_S3_SECRET_ACCESS_KEY) - Endpoint : Scaleway (
UPLOAD_S3_ENDPOINT), pas AWS — doit etre le base endpoint (https://s3.fr-par.scw.cloud) sans nom de bucket - Bucket : defini par
UPLOAD_S3_BUCKET - Chemin :
enterprises/{enterpriseUuid}/{documentUuid} - ACL :
private(pas d'acces public)
Exemple de chemin : enterprises/550e8400-e29b-41d4-a716-446655440000/f47ac10b-58cc-4372-a567-0e02b2c3d479
5. Backend — enregistrement en base
Fichier : back/src/api/documents/document.service.ts
Apres l'upload S3, les metadonnees sont enregistrees dans prisma.tool :
documents
├── id ← ID technique interne, jamais expose au front
├── uuid ← UUID v4 genere par le service
├── bucket ← nom du bucket S3
├── path ← chemin complet dans le bucket
├── name ← nom original du fichier
├── size ← taille du fichier en octets
├── created_at
└── updated_at
users_documents (table de liaison interne)
├── user_id ← ID de l'utilisateur qui a depose
└── document_id ← ID du document creeLe contenu binaire du fichier n'est jamais stocke en base — uniquement sur S3. Le front et les liens publics manipulent uniquement documents.uuid, obligatoire et unique ; l'ID numerique reste reserve aux relations internes. Le deposant expose par les API admin est derive de la liaison users_documents -> users et contient uniquement des informations simples (firstname, lastname, email).
5 bis. Backend — consultation des fichiers
Fichier : back/src/api/documents/document.service.ts
GET /documents retourne les documents lisibles par l'utilisateur connecte. Pour un utilisateur standard, la reponse ne contient pas le deposant afin de limiter l'exposition de donnees personnelles au strict necessaire.
ts
this.prisma.tool.documents.findMany({
where: {
users_documents: { some: { user_id: userId } },
},
select: {
uuid: true,
name: true,
size: true,
created_at: true,
folder: {
select: { uuid: true, name: true },
},
},
orderBy: { created_at: 'desc' },
})Le champ size est stocke en BigInt cote Prisma et converti en number avant la reponse HTTP. Pour les roles administrateur et super-admin, le backend peut enrichir la liste avec depositor. Pour les endpoints admin de dossiers, GET /folders/:uuid/documents retourne le deposant de chaque fichier.
5 ter. Backend — telechargement d'un fichier depose
Fichiers : back/src/api/documents/document.controller.ts, back/src/api/documents/document.service.ts, back/src/domains/s3Helper/getFileUrl.ts
GET /documents/:uuid/download retourne une URL pre-signee temporaire :
json
{
"url": "https://signed-url-temporaire",
"filename": "rapport-client.csv"
}La verification d'appartenance est centralisee dans DocumentAccessPolicy :
ts
this.prisma.tool.documents.findFirst({
where: {
uuid: documentUuid,
users_documents: { some: { user_id: userId } },
},
})Si le document n'existe pas ou n'appartient pas a l'utilisateur, le service renvoie une erreur File not found. pour ne pas exposer l'existence d'un fichier tiers. L'URL S3 est generee avec Content-Disposition: attachment afin de declencher le telechargement dans le format d'origine.
5 quater. Backend — acces via lien applicatif
Fichiers : front/src/pages/documents/DocumentAccessPage.vue, back/src/api/documents/document.service.ts
Le lien partageable pointe vers le front :
text
/files/:documentUuidCette route front est protegee par le guard de navigation existant. Une fois l'utilisateur authentifie, la page appelle :
http
GET /documents/:uuid/access-urlLe backend applique la meme verification d'appartenance que pour le telechargement. La difference est le mode de signature :
| Endpoint | Usage | Content-Disposition |
|---|---|---|
GET /documents/:uuid/download | Telechargement immediat | attachment |
GET /documents/:uuid/access-url | Ouverture depuis un lien applicatif | inline |
Le lien copie ne contient jamais de token, de bucket S3, de chemin interne, ni d'ID numerique auto-incremental.
6. Lecture — URL pre-signee
Fichier : back/src/domains/s3Helper/getFileUrl.ts
Pour telecharger ou afficher un fichier, le backend genere une URL pre-signee (valable 1 heure) :
ts
const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 })L'URL permet un acces temporaire sans exposer les credentials S3.
Variables d'environnement
| Variable | Description | Exemple |
|---|---|---|
UPLOAD_S3_REGION | Region Scaleway | fr-par |
UPLOAD_S3_ENDPOINT | Endpoint S3 Scaleway (base, sans bucket) | https://s3.fr-par.scw.cloud |
UPLOAD_S3_ACCESS_KEY | Access key Scaleway | (secret) |
UPLOAD_S3_SECRET_ACCESS_KEY | Secret key Scaleway | (secret) |
UPLOAD_S3_BUCKET | Nom du bucket | heriade-strapi |
FILE_SIZE_LIMIT | Taille max en Mo (defaut 50) | 50 |
Fichiers concernes
| Fichier | Role |
|---|---|
front/src/pages/admin/folders/AdminFoldersPage.vue | Liste des dossiers admin, point d'entree du parcours de depot |
front/src/pages/admin/folders/AdminFolderDetailPage.vue | Interface de depot + liste des fichiers deposes pour un dossier |
front/src/stores/files-store.js | Store Pinia — POST /documents, GET /documents, progression et chargement |
front/src/components/upload/FileUploadListItem.vue | Composant de liste avec statut/progression |
front/src/components/documents/DocumentListItem.vue | Composant d'affichage d'un document depose + menu d'actions |
front/src/pages/documents/DocumentAccessPage.vue | Page d'ouverture d'un lien securise /files/:documentUuid |
back/src/api/documents/document.controller.ts | Endpoints GET /documents, GET /documents/:uuid/download, GET /documents/:uuid/access-url et POST /documents |
back/src/api/documents/document.service.ts | Validation + upload S3 + insert BDD + lecture/telechargement/acces des documents utilisateur |
back/src/api/documents/document-access-policy.service.ts | Regles d'autorisation document centralisees |
back/src/domains/s3Helper/uploadFile.ts | Client S3 — envoi du fichier |
back/src/domains/s3Helper/getFileUrl.ts | Client S3 — generation d'URL pre-signee |
back/src/exceptions/document.exceptions.ts | Exceptions metier (fichier manquant, extension, taille) |
sql/tool_01_add_size_to_documents.sql | Migration SQL ajoutant documents.size |
sql/tool_02_documents_uuid_not_null.sql | Migration SQL rendant documents.uuid obligatoire |
