mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r3.2): bibliothèque de documents (FileStorage réel) + analytics
- FileStorage : putObject/getObjectStream/removeObject, bucket créé au démarrage — MinIO confiné à son implémentation (règle ESLint intacte) - documents : upload multipart (PDF/JPG/PNG, 20 Mo max, rattachement appareil OU OT requis, permission d'édition sur la CIBLE), liste filtrable, téléchargement STREAMÉ par l'API (MinIO jamais exposé), suppression ; e2e : octets téléchargés identiques aux octets envoyés - analytics : GET /analytics/summary dérivé du réel — coûts/mois (mouvements + main-d'œuvre figés), pannes par organe (bilans codés), taux de préventif, durée moyenne de résolution, top équipements - générateur OpenAPI : query params, multipart, réponse binaire (71 ops) - CI : service MinIO (bitnami) sur les jobs api et e2e - test de régression du tri « Interventions récentes » rendu déterministe (positions absolues instables sous 12 suites parallèles) ; 58 tests, 6 runs complets consécutifs verts Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
260
apps/web/src/api/schema.d.ts
vendored
260
apps/web/src/api/schema.d.ts
vendored
@@ -372,6 +372,75 @@ export interface paths {
|
||||
patch: operations["updateUser"];
|
||||
trace?: never;
|
||||
};
|
||||
"/documents": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Bibliothèque (filtrable par appareil ou OT) */
|
||||
get: operations["listDocuments"];
|
||||
put?: never;
|
||||
/** Téléverser (PDF/JPG/PNG, 20 Mo max, rattachement appareil OU OT requis) */
|
||||
post: operations["uploadDocument"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/documents/{id}/download": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Télécharger — streamé par l’API (MinIO jamais exposé) */
|
||||
get: operations["downloadDocument"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/documents/{id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Supprimer (permission d’édition sur la cible) */
|
||||
delete: operations["deleteDocument"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/analytics/summary": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Le tableau de la direction : coûts, pannes par organe (bilans), préventif, top équipements */
|
||||
get: operations["getAnalyticsSummary"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/partners": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1297,6 +1366,62 @@ export interface components {
|
||||
isActive?: boolean;
|
||||
hourlyRate?: number | null;
|
||||
};
|
||||
DocumentsResponse: {
|
||||
documents: {
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
/** @enum {string} */
|
||||
kind: "NOTICE" | "CERTIFICATE" | "PHOTO" | "OTHER";
|
||||
fileName: string;
|
||||
size: number;
|
||||
contentType: string;
|
||||
assetReference: string | null;
|
||||
workOrderReference: string | null;
|
||||
uploadedByName: string | null;
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
}[];
|
||||
};
|
||||
Document: {
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
/** @enum {string} */
|
||||
kind: "NOTICE" | "CERTIFICATE" | "PHOTO" | "OTHER";
|
||||
fileName: string;
|
||||
size: number;
|
||||
contentType: string;
|
||||
assetReference: string | null;
|
||||
workOrderReference: string | null;
|
||||
uploadedByName: string | null;
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
};
|
||||
AnalyticsSummary: {
|
||||
monthCost: number;
|
||||
previousMonthCost: number;
|
||||
closed12m: {
|
||||
total: number;
|
||||
preventive: number;
|
||||
};
|
||||
preventiveRate: number | null;
|
||||
avgResolutionDays: number | null;
|
||||
failuresByComponent: {
|
||||
label: string;
|
||||
count: number;
|
||||
}[];
|
||||
costsByMonth: {
|
||||
month: string;
|
||||
total: number;
|
||||
}[];
|
||||
topAssets: {
|
||||
reference: string;
|
||||
siteName: string;
|
||||
correctives: number;
|
||||
partsCost: number;
|
||||
laborCost: number;
|
||||
total: number;
|
||||
}[];
|
||||
};
|
||||
PartnersResponse: {
|
||||
partners: {
|
||||
/** Format: uuid */
|
||||
@@ -2647,6 +2772,141 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
listDocuments: {
|
||||
parameters: {
|
||||
query?: {
|
||||
assetId?: string;
|
||||
workOrderId?: string;
|
||||
kind?: string;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Liste */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["DocumentsResponse"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
uploadDocument: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"multipart/form-data": {
|
||||
/** Format: binary */
|
||||
file: string;
|
||||
kind?: string;
|
||||
assetId?: string;
|
||||
workOrderId?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Document rangé */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Document"];
|
||||
};
|
||||
};
|
||||
/** @description Type/taille refusé ou rattachement manquant */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
downloadDocument: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Fichier */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Inconnu */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
deleteDocument: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Supprimé */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Inconnu */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
getAnalyticsSummary: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Synthèse */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["AnalyticsSummary"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
listPartners: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in New Issue
Block a user