# Ladoum Track SN — Backend

API REST de l'application **Ladoum Track SN** (*Suivre · Tracer · Valoriser*), plateforme
officielle de suivi, traçabilité et valorisation des moutons Ladoum du Sénégal.

Le backend expose une API sécurisée permettant aux éleveurs et administrateurs de gérer
leur cheptel, enregistrer la reproduction (saillies, naissances), suivre la lignée,
générer un extrait de naissance officiel, produire des QR codes de traçabilité, et gérer
les transferts d'animaux entre bergeries avec historique complet.

---

## Fonctionnalités

### Gestion du cheptel
- CRUD des moutons avec photo obligatoire, sexe, multi-couleur (Noir, Blanc, Thiourour,
  Marron — max 2), statut, caractéristiques
- **Numéro d'identification fonctionnel** unique au format `JJMMYYYY#id`
  (ex : `02032026#1`) généré automatiquement à la création et backfillé pour les
  moutons existants
- Traçabilité des parents (père / mère) — auto-référence avec validation du sexe
- Flag **reproducteur** sur les mâles pour constituer le pool de géniteurs
- Cloisonnement strict par éleveur pour la lecture/écriture
- Sélection du père ou de la mère parmi **toutes les bergeries** (pool public)
- Sexe et date de naissance immuables après création

### Reproduction
- **Saillies** avec calcul automatique de la date de mise bas (150 jours de gestation)
- Blocage d'une nouvelle saillie tant que la femelle est en gestation
- Période de repos obligatoire de 45 jours après une mise bas
- **Âge minimum 7 mois** pour une première saillie (règle appliquée uniquement aux
  femelles nées dans le système, pas aux adultes importées)
- **Confirmation de gestation** (détection effective de la grossesse)
- Marquage en échec si la femelle revient en chaleur
- **Naissances** multi-agneaux avec auto-création des moutons, photo et date par agneau
- Chaque agneau est rattaché à sa `Naissance` via une **FK forte** (`naissance_id`),
  garantissant une traçabilité non-ambiguë même avec plusieurs naissances d'une même mère
- Backfill automatique au premier démarrage pour rattacher les moutons existants
  (`NaissanceAgneauBackfill`)
- Auto-remplissage du père depuis la saillie active à l'enregistrement d'une naissance
- Clôture automatique de la saillie lors de l'enregistrement d'une naissance
- **`dateEntreeSysteme`** auto-fixée à la date du jour pour chaque mouton créé
  (manuellement via `/moutons` ou automatiquement via `/naissances`) — champ
  non-éditable, affiché sur la fiche détaillée, la fiche publique et l'extrait PDF

### Lignée et documents
- Arbre généalogique récursif jusqu'à 10 générations
- Génération PDF de l'**extrait de naissance** avec :
  - Bandeau Ladoum Track SN (logo + tagline) en en-tête
  - Logo bergerie + nom + coordonnées propriétaire
  - Photo du mouton + caractéristiques
  - N° d'identification fonctionnel en or
  - Section lignée (parents)
  - Cachet / signature
  - Cadre décoratif doré et pied de page « via Ladoum Track SN »

### QR code et fiche publique
- **QR code PNG** généré à la demande pour chaque mouton (ZXing)
- **Fiche publique** read-only accessible à tous les utilisateurs authentifiés :
  caractéristiques, parents, arbre généalogique sur 3 générations,
  descendance directe avec statistiques (total / mâles / femelles),
  historique des transferts

### Authentification et comptes
- **Connexion par téléphone + mot de passe** (le téléphone est l'identifiant unique
  de login ; l'email reste le sujet du JWT en interne)
- **Inscription multipart** `POST /auth/register` : payload JSON + fichier logo
  obligatoire en un seul appel transactionnel
- Inscription publique = toujours rôle `ELEVEUR` + compte bloqué + bergerie unique +
  téléphone unique
- **Page contact admin publique** : coordonnées des administrateurs actifs récupérées
  depuis la base pour la page d'attente d'activation

### Profil utilisateur (self-service)
- `PUT /utilisateurs/me` accessible à **tout utilisateur authentifié** pour modifier
  ses propres informations (nom, téléphone, bergerie, adresse, mot de passe)
- Email verrouillé (sujet du JWT — ne peut pas être modifié en self-service)
- Upload/remplacement du logo via `POST /utilisateurs/me/logo` (multipart)

### Administration et transferts
- Gestion des utilisateurs (création, édition, blocage / déblocage / suppression)
- **Transferts entre bergeries** : validation en deux temps (émetteur puis récepteur),
  refus avec motif, annulation possible tant qu'en attente, historique complet préservé
  même après changement de propriétaire

---

## Stack technique

- **Java 21** + **Spring Boot 3.3**
- **Spring Security** + **JWT** (jjwt 0.12)
- **Spring Data JPA** / **Hibernate**
- **MySQL 8**
- **OpenPDF 1.3** (génération des extraits de naissance)
- **ZXing** (génération des QR codes)
- **Lombok 1.18.38** — épinglé explicitement dans le `pom.xml` + déclaré dans
  `annotationProcessorPaths` du `maven-compiler-plugin` pour compatibilité JDK récents
- **springdoc-openapi** (Swagger UI)
- **Maven**

---

## Prérequis

- JDK 21+
- MySQL 8+ (tournant sur `localhost:3306`)
- Maven 3.8+ (ou utiliser le wrapper `./mvnw`)

---

## Configuration

Les paramètres sont dans [`src/main/resources/application.yml`](src/main/resources/application.yml).

| Clé | Description | Valeur par défaut |
|-----|-------------|-------------------|
| `spring.datasource.url` | URL MySQL | `jdbc:mysql://localhost:3306/bergerie_ladoum?...` |
| `spring.datasource.username` | User MySQL | `root` |
| `spring.datasource.password` | Mot de passe MySQL | (vide) |
| `app.jwt.secret` | Secret JWT — **à changer en prod** | `ChangeMe...` |
| `app.jwt.expiration-ms` | Durée de validité du token | 24 h |
| `app.admin.email` / `.password` / `.nom` / `.telephone` | Compte admin seedé au démarrage | `mausarr05@gmail.com` / `Admin@123` / `Mamadou sarr` / `775897644` |
| `app.storage.location` | Dossier local des images uploadées | `uploads` |
| `app.frontend.base-url` | URL publique du frontend (utilisée pour les QR codes) | `http://localhost:4200` |

La base `bergerie_ladoum` est créée automatiquement au premier démarrage
(`createDatabaseIfNotExist=true`). Hibernate gère les migrations via `ddl-auto: update`.

---

## Démarrage

```bash
# Depuis le dossier backend/
./mvnw spring-boot:run
# ou
mvn spring-boot:run
```

L'API démarre sur `http://localhost:8080/api`.
Le compte admin est créé automatiquement au premier lancement, et tous les moutons
existants sans numéro d'identification sont backfillés par `MoutonNumeroBackfill`.

**Swagger UI** : [http://localhost:8080/api/swagger-ui.html](http://localhost:8080/api/swagger-ui.html)

---

## Structure du code

```
src/main/java/sn/ladoum/bergerie/
├── BergerieApplication.java           # Classe de démarrage
├── auth/                               # Authentification JWT (login / register)
├── config/
│   ├── DataInitializer.java            # Seed du compte admin au démarrage
│   ├── MoutonNumeroBackfill.java       # Backfill du numéro fonctionnel (one-shot)
│   └── NaissanceAgneauBackfill.java    # Rattache les moutons existants à leur
│                                       #   Naissance via (mere_id, date_naissance)
│                                       #   — idempotent, ne touche que les
│                                       #   moutons sans naissance_id
├── controller/                         # Controllers REST
├── dto/                                # DTOs échangés via l'API
├── entity/                             # Entités JPA + enums
│   └── enums/                          # Sexe, StatutMouton, Role, StatutSaillie,
│                                       #   StatutTransfert
├── exception/                          # GlobalExceptionHandler (gère 401, 403,
│                                       #   DisabledException, BadCredentials…)
├── lignee/                             # Arbre généalogique (protégé + public)
├── pdf/                                # Génération PDF extrait de naissance
│                                       #   (Ladoum Track SN + bergerie)
├── publicapi/                          # Endpoints publics sans auth
│                                       #   (coordonnées admin)
├── qr/                                 # QrCodeService (PNG via ZXing)
├── repository/                         # Spring Data JPA
├── security/                           # SecurityConfig, JwtService,
│                                       #   JwtAuthenticationFilter, UserDetails,
│                                       #   OpenApiConfig
├── service/                            # Couche métier
└── storage/                            # FileStorageService (upload/download images)

src/main/resources/
├── application.yml                     # Configuration
├── logos/
│   └── ladoum-track-icon.png           # Logo embarqué pour le PDF
└── ...
```

---

## Rôles et permissions

| Rôle | Droits |
|------|--------|
| `ADMIN` | Accès complet, gestion des utilisateurs, doit désigner explicitement un éleveur propriétaire à chaque création |
| `ELEVEUR` | CRUD de ses propres moutons / naissances / saillies, lecture du pool public de reproducteurs, transferts sortants et réception |
| `LECTEUR` | Lecture seule |

Règles métier :
- Un éleveur ne peut **pas** rattacher un mouton à un autre utilisateur (auto-rattachement forcé).
- Un éleveur n'est propriétaire que des moutons liés à son compte.
- Un éleveur ne peut voir l'historique d'un mouton qu'après une relation source/destination
  ou s'il en est le propriétaire actuel.
- Le transfert entre bergeries est le seul canal officiel pour changer de propriétaire.
- L'inscription publique crée toujours un compte `ELEVEUR` **bloqué** (à activer par admin).

---

## Principaux endpoints

### Authentification
- `POST /api/auth/register` — Inscription **multipart** (`data` = JSON, `logo` =
  fichier image obligatoire). Compte bloqué par défaut.
- `POST /api/auth/login` — Connexion par **téléphone + mot de passe** (retourne JWT).
  Refuse les comptes bloqués avec message dédié.

### Endpoints publics (sans authentification)
- `GET /api/public/admins` — Coordonnées des administrateurs actifs (pour la page
  d'attente d'activation)

### Moutons
- `GET /api/moutons` — Liste (filtrée par éleveur)
- `POST /api/moutons` — Création
- `GET /api/moutons/{id}` — Détail (propriétaire uniquement)
- `PUT /api/moutons/{id}` — Modification
- `DELETE /api/moutons/{id}` — Suppression (admin)
- `POST /api/moutons/{id}/photo` — Upload photo (multipart)
- `GET /api/moutons/{id}/public-info` — Fiche publique (tous utilisateurs authentifiés)
- `GET /api/moutons/{id}/descendance` — Liste des enfants directs
- `GET /api/moutons/{id}/qrcode?size=320` — PNG du QR code pointant sur la fiche publique
- `GET /api/moutons/reproducteurs/males` — Pool public des mâles reproducteurs
- `GET /api/moutons/reproductrices/femelles` — Pool public des femelles

### Naissances
- `POST /api/naissances/complete` — Enregistre la naissance et crée les agneaux en une
  requête (auto-clôture de la saillie active)
- `GET /api/naissances` — Liste

### Saillies
- `POST /api/saillies` — Initier une saillie
- `POST /api/saillies/{id}/confirmer` — Confirmer la gestation
- `POST /api/saillies/{id}/echec` — Marquer en échec (femelle revenue en chaleur)
- `PUT /api/saillies/{id}` — Modifier une saillie
- `GET /api/saillies/etat-reproducteur/{moutonId}` — État reproducteur d'une femelle

### Transferts
- `POST /api/transferts` — Initier un transfert (propriétaire actuel)
- `POST /api/transferts/{id}/accepter` — Accepter (destination)
- `POST /api/transferts/{id}/refuser` — Refuser avec motif (destination)
- `POST /api/transferts/{id}/annuler` — Annuler (source)
- `GET /api/transferts/entrants` — Transferts entrants en attente
- `GET /api/transferts/sortants` — Transferts sortants
- `GET /api/transferts/historique/{moutonId}` — Historique du mouton (protégé)
- `GET /api/transferts/historique/{moutonId}/public` — Historique public (tous
  utilisateurs authentifiés)

### Lignée
- `GET /api/lignee/{moutonId}?profondeur=3` — Arbre généalogique (propriétaire)
- `GET /api/lignee/{moutonId}/public?profondeur=3` — Arbre public

### Utilisateurs (admin)
- `GET /api/utilisateurs` — Liste complète
- `POST /api/utilisateurs` — Créer
- `PUT /api/utilisateurs/{id}` — Modifier
- `DELETE /api/utilisateurs/{id}` — Supprimer
- `POST /api/utilisateurs/{id}/bloquer` / `/debloquer` — Gérer l'activation
- `GET /api/utilisateurs/eleveurs` — Liste allégée des éleveurs (ouvert à tous les
  utilisateurs authentifiés)

### Profil (utilisateur connecté)
- `GET /api/utilisateurs/me` — Profil de l'utilisateur connecté
- `PUT /api/utilisateurs/me` — **Self-service** : modifie nom, téléphone, bergerie,
  adresse, mot de passe (email verrouillé)
- `POST /api/utilisateurs/me/logo` — Upload / remplacement du logo (multipart)

### Extrait de naissance
- `GET /api/extrait-naissance/{moutonId}` — PDF avec bandeau Ladoum Track SN, logo
  bergerie, photo, n° d'identification, lignée, propriétaire et cachet

---

## Sécurité

- Tous les endpoints sont protégés par JWT sauf `/auth/**`, `/public/**`, `/swagger-ui/**`,
  `/v3/api-docs/**` et `/uploads/**` (images statiques).
- Un compte bloqué (`actif = false`) ne peut ni se connecter ni utiliser son token
  (vérification dans `CustomUserDetailsService` + `JwtAuthenticationFilter`).
- La période d'expiration du token est configurable (`app.jwt.expiration-ms`).
- `DisabledException` → 403 explicite côté client.
- `AccessDeniedException` → 403 avec message métier pour les accès hors périmètre éleveur.

---

## Avant production

- Changer `app.jwt.secret` et `app.admin.password`
- Configurer une base MySQL dédiée avec utilisateur restreint
- Activer HTTPS (reverse proxy) — requis pour la caméra du scanner QR côté frontend
- Ajuster `app.frontend.base-url` pour que les QR codes pointent sur le domaine public
- Vérifier les CORS dans `SecurityConfig.corsConfigurationSource()`
