Aller au contenu

Story OP-015: Backend import UI passthrough (POST/GET /imports)

Module: operator-console Slice: Architecture §11 OP-004d + US-OP-01 Side: [BACKEND] Version target: V0.0.3 Priority: 16 Depends on: OP-000 (RBAC, audit), ING (ImportService.start, ImportService.findById) Can develop concurrently with: OP-012, OP-013, OP-014 Merge order: Before OP-019 (frontend imports page) Estimated complexity: S PRD User Stories: US-OP-01 AC1+AC2+AC3+AC4 Wireframe: N/A — backend only


Objective

Exposer 2 endpoints OP qui délèguent à ING (start import + read status), avec audit IMPORT_TRIGGERED côté OP. Cette story permet au frontend (OP-019) de pilotter l'import sans appeler directement le namespace ING (encapsulation + audit trail OP).


Backend Scope

Service Layer

  • ImportsController :
  • POST /api/operator/imports (RBAC : agency_operator + cabinet_admin) — body multipart : file (CSV ou XLSX), agencyId (requis pour cabinet_admin/supervisor).
    • Délègue à ImportService.start(tenantId, agencyId, fileStream, fileName, operatorId) du module ING.
    • ING calcule le hash SHA-256, détecte doublon, lance le job d'ingestion async.
    • Retour : 200 { importId, status:"EN_COURS", duplicateOfImportId?:"uuid", duplicateDetectedAt?:"timestamp" }.
    • Si duplicateOfImportId présent → le frontend affiche la warning « Ce fichier a déjà été importé le {date}. Continuer quand même ? » (US-OP-01 AC4). Si le user confirme, le frontend rappelle POST /imports?forceDuplicate=true.
    • Audit OP IMPORT_TRIGGERED {importId, fileName, fileSizeBytes, sha256, agencyId, operatorId}.
  • GET /api/operator/imports/{id} (RBAC : tous OP) — délègue à ImportService.findById(tenantId, importId).
    • Retour : { importId, status:"EN_COURS|TERMINÉ|ÉCHEC", startedAt, completedAt?, validCount, errorCount, anomalyCount, fileName, agencyId, agencyName, operatorId }.
  • GET /api/operator/imports?cursor=&pageSize=20 — liste paginée des imports récents.

API Endpoints

Method Path Request Response Auth
POST /api/operator/imports (multipart) file, agencyId? 200 import status agency_operator + cabinet_admin
GET /api/operator/imports/{id} import details Tous OP
GET /api/operator/imports?cursor=&pageSize=20 liste Tous OP

Validation Rules

  • file : MIME text/csv | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet ; taille ≤ 20 Mo (sinon 413).
  • agencyId requis pour cabinet_admin/supervisor.
  • forceDuplicate query param boolean.

Multi-Tenant Considerations

  • Scope tenant_id.
  • agency_id : agency_operator force son agence ; cabinet_admin choisit.

Audit & Logging

  • IMPORT_TRIGGERED à chaque POST réussi.
  • Pas d'audit sur GET.

Acceptance Criteria

AC-001: POST /imports lance ingestion et audit (US-OP-01 AC1)
Given un fichier CSV valide 2.3 Mo
When agency_operator POST /imports (multipart)
Then 200 { importId, status:"EN_COURS" }
And IMPORT_TRIGGERED audit avec fileName + sha256.

AC-002: Doublon détecté → warning dans la réponse (US-OP-01 AC4)
Given un fichier déjà importé (même SHA-256)
When POST /imports
Then 200 { importId, status:"EN_COURS", duplicateOfImportId, duplicateDetectedAt }
And le frontend peut afficher la warning.

AC-003: GET /imports/{id} retourne le résultat (US-OP-01 AC2)
Given un import TERMINÉ
When GET /imports/{id}
Then 200 { status:"TERMINÉ", validCount=412, errorCount=3, anomalyCount=12, ... }.

AC-004: Fichier > 20 Mo → 413
Given un fichier 25 Mo
When POST /imports
Then 413 Payload Too Large message "Le fichier dépasse la taille maximale (20 Mo)."

Compliance Rules

  • US-OP-01 : delegate à ING ; OP audit en sus. VÉRIFIÉ.

Standards & Conventions

  • docs/standards/api-guidelines.md — multipart upload, 413.
  • docs/standards/java-spring-guidelines.mdMultipartFile, streaming.

Testing Requirements

Unit Tests

  • Validation taille + MIME.

Integration Tests

  • ImportPassthroughIT AC-001..AC-004 avec ING fixture (mock ImportService).

What QA Will Validate

  • Upload bout-en-bout avec petit CSV de test.
  • Doublon réel détecté.

Out of Scope

  • Frontend page Imports → OP-019.
  • Édition champ d'import → ING (déjà géré côté ING).

Definition of Done

  • [ ] Les 3 endpoints retournent 200/413 conformes
  • [ ] AC-001..AC-004 passent
  • [ ] IMPORT_TRIGGERED audité
  • [ ] Multipart streaming (pas de chargement complet en mémoire)
  • [ ] Tests verts