> ## Documentation Index
> Fetch the complete documentation index at: https://docs.colismove.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Preuves, photos & GPS

> Sc 18, 21, 22, 23, 24 — annonce expirée, photos AVANT_DEPOT/DEPOT, GPS désactivé, échec upload S3.

Cinq scénarios couvrent les preuves de bonne exécution : expiration automatique des annonces, photos PackSentry obligatoires, traçabilité GPS, et résilience upload S3.

## Sc 18 — Annonce expirée (sans booking)

Une annonce dont la date de départ est dépassée et qui n'a aucune réservation associée est nettoyée automatiquement par deux schedulers complémentaires.

```mermaid theme={null}
flowchart TD
    A[Annonce créée<br/>dateDepart = J+10] --> B[J+10 passé<br/>aucun booking]
    B --> C[AnnonceExpirationScheduler<br/>cron 02:30 quotidien]
    C --> D[Détecte annonces<br/>dateDepart < now AND status = ACTIVE]
    D --> E[UPDATE annonces<br/>SET status = EXPIRED]

    F[ExpiredAnnouncementHandler<br/>cron 03:00 quotidien] --> G[Retire annonces<br/>EXPIRED de la search]
    G --> H[Notif carrier<br/>'Annonce expirée, republier ?']
```

### Logique

* `AnnonceExpirationScheduler` à 02:30 → flag `EXPIRED` les annonces sans booking et `dateDepart < now`
* `ExpiredAnnouncementHandler` à 03:00 → exclut de la recherche + notifie le carrier
* Si annonce a au moins 1 booking → reste visible jusqu'à fin du cycle booking (ne pas casser une réservation en cours)

### Tests

Tests d'intégration scheduler en CI continue.

## Sc 21 — Photo AVANT\_DEPOT manquante (gate booking)

Le sender ne peut pas générer le QR de dépôt s'il n'a pas uploadé la photo `AVANT_DEPOT` obligatoire (preuve de l'état du colis avant remise).

```mermaid theme={null}
flowchart TD
    A[Sender booke colis] --> B[Booking → ACCEPTEE]
    B --> C[Frontend mobile<br/>caméra native]
    C --> D[POST /v1/api/photos<br/>type=AVANT_DEPOT]
    D --> E[PackSentry<br/>watermark + S3]
    E --> F[Photo persisted]

    G[Sender tente generate QR dépôt] --> H{PhotoAvantDepot existe ?}
    H -->|Non| I[PhotoPreuveManquanteException<br/>HTTP 422 PHOTO_AVANT_DEPOT_MANQUANTE]
    H -->|Oui| J[QR généré]
```

### Module `colismove-packsentry`

Hexagonal pur (74 fichiers, 11 use cases). Adapter `ImageIOWatermarkAdapter` ajoute watermark date/heure/booking-id, puis upload via `S3PhotoStorageAdapter`.

### Endpoint

```http theme={null}
POST /v1/api/photos
Content-Type: multipart/form-data

file: <binary>
bookingId: 1234
type: AVANT_DEPOT
```

## Sc 22 — Photo DEPOT manquante (gate confirmerDepot)

Au moment du scan QR de dépôt par le carrier, le sender doit avoir uploadé une photo `DEPOT` (preuve de remise effective). Sans elle, la transition `ACCEPTEE → EN_COURS_DE_LIVRAISON` est bloquée.

```mermaid theme={null}
sequenceDiagram
    actor S as Sender
    actor C as Carrier
    participant API as Backend
    participant PS as PackSentry

    S->>PS: POST /photos type=AVANT_DEPOT
    Note over S,C: Sender remet colis<br/>Carrier au point de RDV
    S->>PS: POST /photos type=DEPOT (au moment remise)
    C->>API: POST /qrcode/process-depot
    API->>PS: Gate confirmerDepot()
    alt Photos AVANT_DEPOT + DEPOT présentes
        PS-->>API: OK
        API->>API: → EN_COURS_DE_LIVRAISON
    else Photo DEPOT manquante
        PS-->>API: PhotoPreuveManquanteException
        API-->>C: 422 PHOTO_DEPOT_MANQUANTE
    end
```

### Gates PackSentry

| Gate                 | Quand             | Photos requises         |
| -------------------- | ----------------- | ----------------------- |
| `confirmerDepot`     | Scan QR dépôt     | `AVANT_DEPOT` + `DEPOT` |
| `confirmerLivraison` | Scan QR livraison | `LIVRAISON` (recipient) |

### Particularités

* Watermark non-répudiation : date, heure, booking-id, GPS coords
* Stockage S3 avec URL signée 24h pour preuve litige
* Rétention conforme RGPD : suppression auto J+90 si pas de litige ouvert

## Sc 23 — GPS désactivé sur dépôt

Au scan QR dépôt, le statut GPS du téléphone est capturé. Trois états distincts pour gérer la non-répudiation sans bloquer si la précision est dégradée.

```mermaid theme={null}
flowchart TD
    A[Sender scan QR dépôt] --> B{Statut GPS phone}
    B -->|Localisé| C[GpsStatus.OK<br/>lat/lng persistés]
    B -->|Permission refusée| D[GpsStatus.MISSING<br/>lat/lng = null]
    B -->|Précision > 500m| E[GpsStatus.INCOHERENT<br/>lat/lng persistés + flag]

    C --> F[Booking continue<br/>EN_COURS_DE_LIVRAISON]
    D --> G[Booking continue<br/>warning admin]
    E --> H[Booking continue<br/>review post-litige possible]
```

### Migration domain

V19 a ajouté la colonne `gps_status` enum (`OK`, `MISSING`, `INCOHERENT`) sur `booking_qr_scan`.

### Logique non-bloquante

* Le GPS désactivé **ne bloque pas** le scan QR (évite friction utilisateur)
* Mais le statut est persisté → si litige ultérieur, l'admin a la trace
* `INCOHERENT` = précision GPS > 500m OU coords loin du point de RDV de l'annonce

**Référence** : commit `3697fe8`

## Sc 24 — Échec upload S3 (résilience PackSentry)

Le réseau échoue pendant l'upload de la photo vers S3. Le système retry automatiquement, et bascule en dead-letter si tous les retries échouent.

```mermaid theme={null}
flowchart TD
    A[Sender upload photo] --> B[POST /photos]
    B --> C[ImageIOWatermarkAdapter<br/>watermark applied]
    C --> D[S3PhotoStorageAdapter.upload]
    D --> E{Upload OK ?}
    E -->|Oui| F[200 photoId returned]
    E -->|Non| G[Retry 1/3]
    G --> H{Upload OK ?}
    H -->|Non| I[Retry 2/3]
    I --> J{Upload OK ?}
    J -->|Non| K[Retry 3/3]
    K --> L{Upload OK ?}
    L -->|Non| M[Dead-letter table<br/>+ Micrometer counter]
    L -->|Oui| F
    M --> N[502 S3_UPLOAD_FAILED<br/>+ admin alert]
```

### Configuration

* `MAX_ATTEMPTS = 3` avec backoff exponentiel (200ms, 400ms, 800ms)
* Dead-letter persistée en table `photo_upload_failures` pour replay manuel
* Micrometer counter `packsentry.s3.upload.failures` (alerte ops si > 5/min)

### Frontend mobile

* En cas de 502 → re-show bouton "Réessayer"
* Photos en attente stockées localement (queue Flutter) → upload différé quand réseau revient

### Status

* Dead-letter table + counter Micrometer : **Pending** (sprint S2 PackSentry-Lean)

## Récap modules impactés

| Scénario | Module backend                                   | Schedulers / Gates                                                     |
| -------- | ------------------------------------------------ | ---------------------------------------------------------------------- |
| Sc 18    | `colismove-annonces`                             | `AnnonceExpirationScheduler` 02:30, `ExpiredAnnouncementHandler` 03:00 |
| Sc 21    | `colismove-packsentry`                           | Gate génération QR dépôt                                               |
| Sc 22    | `colismove-packsentry`                           | Gate `confirmerDepot`                                                  |
| Sc 23    | `colismove-reservation` + `colismove-packsentry` | Capture GPS au scan QR                                                 |
| Sc 24    | `colismove-packsentry`                           | Adapter résilient S3                                                   |

## Codes d'erreur

| Code                          | HTTP | Scénario |
| ----------------------------- | ---- | -------- |
| `PHOTO_AVANT_DEPOT_MANQUANTE` | 422  | Sc 21    |
| `PHOTO_DEPOT_MANQUANTE`       | 422  | Sc 22    |
| `S3_UPLOAD_FAILED`            | 502  | Sc 24    |
