Project Documents¶
Upload S3, checklist onboarding, compléments d'analyse et validation de l'étape Documents. Source : project-document.controller.ts.
Tous les endpoints porteur requièrent ProjectFinancingRequestOwnerGuard (session Better Auth + propriété du :projectId).
Modèle documentType¶
Chaque ligne project_financing_request_document porte un documentType qui pilote les règles métier (suppression, lecture, lien analyse). Schéma : project-financing-request-document.schema.ts.
| Type | Quand | Champs spécifiques | Endpoints porteur actuels |
|---|---|---|---|
onboarding |
Projet draft — étape Documents phase 1 |
— | GET …/documents, upload presigné, DELETE …/documents/:id |
analysis |
Projet blocked — réponse à une demande Projet Analyse |
documentRequestId |
DELETE …/analysis/document-request/:documentRequestId/document/:documentId |
finalization |
Phase 2 — pièces KYB / signature | finalizationCategory (signedCompanyStatutes, rib, kbis, beneficialOwnersDeclaration) |
schéma posé ; HTTP porteur à venir |
GET …/documents ne liste aujourd'hui que les documents onboarding (listOnboardingByProjectId). Les documents analysis sont exposés via GET …/analysis/status ; finalization sera branché avec l'écran collecte.
La suppression onboarding vs analyse partage le même service : documentType choisit le guard (project-not-draft vs project-not-blocked).
GET /project-financing-request/project/:projectId/documents¶
Liste les fichiers du projet avec URL de téléchargement presignée, plus l'état des checklists :
{
"documents": [
{
"id": "uuid",
"name": "business-plan.pdf",
"mimeType": "application/pdf",
"size": 204800,
"downloadUrl": "https://…",
"comment": { "value": "…", "createdAt": "…" },
"createdAt": "…"
}
],
"onboarding": {
"expectedDocuments": { "companyKbis": true, "worksQuote": false }
},
"analysis": {
"missingDocumentsFromAnalysis": { "taxReturn": true }
}
}
onboarding.expectedDocuments: renvoyé uniquement endraft(sinon{}).true= encore attendu,false= coché par le porteur.analysis.missingDocumentsFromAnalysis: renvoyé uniquement enblocked(sinon{}). Même sémantique booléenne pour les noms poussés par Projet Analyse.
Upload S3 (presigned)¶
Même pattern que les images de présentation — le binaire ne transite pas par l'API.
| Méthode | Path | Rôle |
|---|---|---|
POST |
/documents/request-upload |
URLs PUT presignées (files[] : mime, size) |
POST |
/documents/confirm-upload |
Vérifie HeadObject + insère les lignes document |
Préfixe S3 : projects/${projectId}/documents/${uuidv7}.${ext}.
Après confirm-upload, si l'étape Documents était completed en draft, elle repasse en draft (réouverture pour re-validation).
Commentaires sur un fichier¶
| Méthode | Path | Corps |
|---|---|---|
POST |
/documents/:documentId/comment |
{ "value": "…" } |
DELETE |
/documents/:documentId/comment |
— |
Même règle de réouverture de l'étape si elle était completed.
Supprimer un fichier¶
| Méthode | Path | Fenêtre | Réponse |
|---|---|---|---|
DELETE |
/documents/:documentId |
Onboarding, projet draft |
200 (corps vide) |
DELETE |
/analysis/document-request/:documentRequestId/document/:documentId |
Analyse, projet blocked |
{ documentRequestId, documents[] } à jour |
Soft-delete : la ligne reste en base avec deletedAt posé (audit), exposé via la colonne générée deletedAt_view, et tous les reads porteur l'excluent (deletedAt_view IS NULL). L'objet S3 est retiré via deleteObject après commit (best-effort). L'ordre commit-puis-S3 est délibéré : un crash entre les deux laisse un objet S3 orphelin (invisible, aucun read ne le référence), jamais un document vivant pointant vers un fichier absent. L'orphelin est inerte ; une règle de cycle de vie S3 pourra le balayer (non implémentée, dette assumée). L'opération est idempotente : re-supprimer un document déjà supprimé ne réécrit rien et ne rappelle pas S3.
Un document refusé par l'analyse (isRefused) reste supprimable. Côté onboarding, supprimer le dernier fichier peut rouvrir l'étape completed (même règle que le commentaire).
Checklist onboarding (phase 1, draft uniquement)¶
PUT /documents/base-document-list/check — corps { "documentKey": "…", "checked": true | false }.
Persiste expectedDocuments[key] = !checked. Modifier la checklist réouvre l'étape si elle était completed.
Clés : voir README — document keys.
Compléments d'analyse (blocked)¶
Porteur — cocher les pièces manquantes¶
PUT /documents/analysis-documents/check — corps { "documentName": "…", "checked": true | false }.
Uniquement en blocked. Persiste missingDocumentsFromAnalysis[name] = !checked.
Porteur — valider l'étape après upload¶
POST /documents/validate — vide missingDocumentsFromAnalysis et notifie Projet Analyse (notifyProjectUpdated, reason: 'missing-documents-provided'). Projet doit être blocked.
Projet Analyse — pousser la liste des manquants¶
PUT /internal/projet-analyse/project/:projectId/missing-documents (API key projet-analyse).
Corps : { "documentNames": ["taxReturn", "…"] }. Écrase l'ensemble en préservant l'état coché des noms déjà connus. Passe le projet en blocked si besoin.
Compléter l'étape Documents (phase 1)¶
PUT /documents/complete — marque documentsStep.status = 'completed'.
Prérequis :
- Projet en
draft documentsStep.status !== 'unavailable'(la présentation doit avoir été complétée au moins une fois)- Au moins un fichier uploadé (
documents-step-emptysinon)
La checklist expectedDocuments guide l'UX mais n'est pas un prérequis technique à la complétion.
Refus d'un document par Projet Analyse¶
PUT /internal/projet-analyse/project/:projectId/document/:documentId/refuse — voir Project Analysis.
Expose côté porteur via isRefused: true sur chaque document dans GET …/analysis/status et dans les documentRequests[].documents.
Erreurs courantes¶
| Code | HTTP | Cause |
|---|---|---|
project-not-draft |
409 | Action réservée au brouillon |
project-not-blocked |
409 | Action réservée aux compléments d'analyse |
documents-step-unavailable |
409 | Présentation pas encore complétée |
documents-step-empty |
409 | Aucun fichier à la complétion |
s3-key-invalid-prefix |
400 | Clé S3 hors du préfixe projet |
analysis-missing-document-not-found |
404 | Nom inconnu dans la liste Analyse |
Liens¶
- Service :
project-document.service.ts - Interne missing-docs :
project-document-internal.controller.ts - S3 :
project-financing-request-s3.ts