Files
siop2/apps/api/src/app.module.ts
pr-daaif 2ffdd13cf4 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>
2026-07-16 21:24:04 +01:00

75 lines
2.9 KiB
TypeScript

import { DynamicModule, Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { AnalyticsModule } from './analytics/analytics.module';
import { AssetsModule } from './assets/assets.module';
import { DocumentsModule } from './documents/documents.module';
import { AuthModule } from './auth/auth.module';
import { DemoAuthModule } from './auth/demo/demo-auth.module';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { CategoriesModule } from './categories/categories.module';
import { demoModeEnabled } from './config/env';
import { FilesModule } from './files/files.module';
import { HealthModule } from './health/health.module';
import { LocationsModule } from './locations/locations.module';
import { MetersModule } from './meters/meters.module';
import { PartnersModule } from './partners/partners.module';
import { PartsModule } from './parts/parts.module';
import { PortalModule } from './portal/portal.module';
import { PurchaseOrdersModule } from './purchase-orders/purchase-orders.module';
import { PreventiveModule } from './preventive/preventive.module';
import { ReferenceValuesModule } from './reference-values/reference-values.module';
import { RequestsModule } from './requests/requests.module';
import { TeamsModule } from './teams/teams.module';
import { WorkOrdersModule } from './work-orders/work-orders.module';
import { PermissionsGuard } from './permissions/permissions.guard';
import { PermissionsModule } from './permissions/permissions.module';
import { PrismaModule } from './prisma/prisma.module';
import { UsersModule } from './users/users.module';
/**
* Composé via forRoot() (et non statiquement) pour que l'enregistrement
* conditionnel de DemoAuthModule (ADR-002) soit décidé au démarrage —
* et testable dans les deux états (module présent / routes 404).
*/
@Module({})
export class AppModule {
static forRoot(): DynamicModule {
return {
module: AppModule,
imports: [
PrismaModule,
PermissionsModule,
FilesModule,
AuthModule,
UsersModule,
HealthModule,
// R1 — référentiel
CategoriesModule,
LocationsModule,
AssetsModule,
TeamsModule,
// R2 — exploitation
WorkOrdersModule,
RequestsModule,
ReferenceValuesModule,
PreventiveModule,
MetersModule,
PortalModule,
// R3 — gestion
PartnersModule,
PartsModule,
PurchaseOrdersModule,
DocumentsModule,
AnalyticsModule,
// ADR-002 : hors DEMO_MODE, le module n'est pas enregistré → 404
...(demoModeEnabled() ? [DemoAuthModule] : []),
],
providers: [
// Ordre significatif : authentification puis permissions
{ provide: APP_GUARD, useClass: JwtAuthGuard },
{ provide: APP_GUARD, useClass: PermissionsGuard },
],
};
}
}