Partner Mapping and Activation

Summary

When a new partner deposits their first XML file, the system runs a file audit (instead of ingesting) to extract all unique field codes (lot types, programme statuses, etc.) and propose automatic mappings. The partner status transitions to audit_ready. An admin then reviews these mappings in the UI, corrects any unknown codes, and calls the validate endpoint. On validation, all mappings are stamped admin_validated, the partner becomes active, and the archived file is immediately re-ingested with the correct mappings. A Slack notification is sent on activation.

State Diagram

stateDiagram-v2
    state "Mappings en attente" as PendingMapping
    state "Audit prêt à valider" as AuditReady
    state "Partenaire actif" as Active
    [*] --> PendingMapping: partner.status = pending_mapping (after onboarding)
    PendingMapping --> AuditReady: first XML file deposited → runFileAudit()
    AuditReady --> AuditReady: admin reviews mappings via GET /mapping
    AuditReady --> AuditReady: admin updates codes via PUT /mapping
    AuditReady --> Active: admin validates mapping (no unknowns remaining)
    Active --> PendingMapping: admin triggers re-audit
    Active --> [*]

Steps

1. Automatic Audit Trigger (Actor: system)

When the file watcher detects a deposit for a partner with status: "pending_mapping" or "audit_ready", runFileAudit() is called from lib/audit.ts instead of the normal ingestion pipeline. The file is first archived to /home/{username}/feeds/archive/. The audit extracts field codes, proposes PartnerMapping rows, and updates the partner to status: "audit_ready" with an auditReport JSON containing the archived file path and fileDepositId.

Triggers: File deposited while partner is in pending_mapping or audit_ready state Outcome: PartnerMapping rows created, partner status → audit_ready

2. Review Mappings (Actor: admin)

GET /admin/partners/:id/mapping — returns partner metadata, all PartnerMapping rows ordered by family and source code, and the TARGET_VALUES whitelist (valid enum values per mapping family).

The admin can see which codes have been auto-proposed and which remain unknown (confidence: "unknown").

Triggers: Admin opens the mapping UI for this partner Outcome: Full mapping table with allowed target values displayed

3. Update Mappings (Actor: admin)

PUT /admin/partners/:id/mapping with { updates: [{ id, targetValue, family }] }.

For each update, targetValue is validated against TARGET_VALUES[family] whitelist. Invalid values return 400 INVALID_TARGET_VALUE. Valid updates are applied in a Prisma $transaction, setting confidence: "admin_validated".

Triggers: Admin corrects or confirms code mappings Outcome: PartnerMapping.confidence set to admin_validated for updated rows

4. Validate and Activate (Actor: admin)

POST /admin/partners/:id/mapping/validate:

Pre-conditions:

  • Partner must be in audit_ready status (400 INVALID_STATE otherwise).
  • No PartnerMapping with targetValue: "unknown" may remain (400 UNKNOWNS_REMAINING).

On success (Prisma $transaction):

  1. All mappings → confidence: "admin_validated".
  2. partner.status"active", auditReport → cleared.

Post-activation:

  • enqueueIngestion() is called with the archived file path stored in the audit report — the file is re-processed immediately with the new mappings.
  • notifyMappingValidated(partnerName, adminName, filename) sends a Slack notification.

Idempotent: if partner is already active, returns 200 with { alreadyActive: true }.

Triggers: Admin confirms all codes are correctly mapped Outcome: Partner activated, archived file re-ingested, Slack notified

5. Manual Re-Audit (Actor: admin)

POST /admin/partners/:id/audit — resets partner to pending_mapping and clears auditReport. Next file deposit will trigger a fresh audit.

Triggers: Admin needs to restart the mapping process Outcome: Partner back to pending_mapping

Error States

  • Partner not found → 404 NOT_FOUND
  • Validate called when status is not audit_ready → 400 INVALID_STATE
  • Unknown mappings remain at validation time → 400 UNKNOWNS_REMAINING
  • Invalid targetValue in PUT → 400 INVALID_TARGET_VALUE