# CARTECADEAU — Spécification de conception

- **Date :** 2026-05-21
- **Auteur :** Équipe CARTECADEAU (assisté par Claude)
- **Statut :** En attente de validation

## 1. Contexte & objectif

CARTECADEAU est un site e-commerce qui **revend des cartes-cadeaux (vouchers) et des recharges de jeux (top-ups)** à des clients finaux. L'approvisionnement se fait via l'**API Wupex** (fournisseur). Le paiement client se fait par **Mobile Money via CinetPay**.

Promesse produit : le client paie en Mobile Money et reçoit son **code/PIN** (voucher) ou la **confirmation de recharge** (top-up) de façon fiable, même si l'API fournisseur est lente ou indisponible au moment T.

## 2. Périmètre

### Dans la v1 (MVP)
- Catalogue produits (vouchers + top-ups) synchronisé depuis Wupex.
- Comptes clients **obligatoires** (inscription / connexion).
- Panier + tunnel de commande.
- Saisie des champs de compte de jeu pour les top-ups selon le `subType`.
- Paiement **CinetPay** (Mobile Money) avec webhook de confirmation.
- Livraison **asynchrone et fiable** des commandes Wupex (file + réessais).
- Espace client : historique des commandes + affichage des codes livrés.
- Email de livraison des codes.
- Back-office admin : produits/marges, suivi commandes/paiements, relance manuelle, solde Wupex.

### Hors v1 (phases ultérieures)
Achat invité ; plusieurs agrégateurs de paiement ; codes promo ; multi-devises ; statistiques avancées ; application mobile.

## 3. Choix techniques

| Sujet | Choix |
|---|---|
| Framework | **Symfony** (Twig, Security, Doctrine, Messenger, Mailer) |
| Base de données | MySQL (via WAMP) |
| Paiement | **CinetPay** (Mobile Money : Wave, Orange, MTN, Moov) |
| Fournisseur | **Wupex** — environnement **Sandbox** (`https://sandbox-service.wupex.com`) |
| File d'attente | Symfony Messenger, **transport Doctrine** (aucun broker externe) |
| Direction artistique | **Neon Nocturne** (sombre, dégradés violet→cyan, glassmorphism) |

## 4. Architecture & services

Application monolithique Symfony (rendu serveur Twig). Deux services « clients » isolés, chacun avec une interface claire et testable indépendamment :

### `WupexClient`
Encapsule **tous** les appels à Wupex. Configuré par `WUPEX_API_URL`, `WUPEX_API_KEY`, `WUPEX_MERCHANT_CODE`, `WUPEX_LANGUAGE`. En-têtes systématiques : `x-api-key`, `Accept-Language`, `Content-Type: application/json`.

Méthodes (mappées sur les endpoints réels) :
- `listProducts(page, pageSize, filters[])` → `POST /api/product/merchant/invited/list`
- `pullCodes(items[], referenceId, allowTakeAll)` → `POST /api/order/pull-codes`
- `topup(item, userAccount|attributes, referenceId)` → `POST /api/order/topup`
- `listTopupServers(sku)` → `POST /api/order/topup-listservers`
- `getTopupAttributes(productId)` → `GET /api/order/topup/product/attribute`
- `getOrderDetail(orderName)` → `GET /api/order/detail` (récupère serials/PIN)
- `listOrders(...)` → `POST /api/order/list`
- `getBalance()` → `GET /api/customer/balance`

### `CinetPayClient`
- `initPayment(order)` → crée une transaction CinetPay, renvoie l'URL de paiement.
- `verifyPayment(transactionId)` → vérifie le statut réel côté CinetPay (ne jamais faire confiance au seul retour navigateur).
- Vérification de l'authenticité du **webhook de notification** (token/signature).

## 5. Modèle de données (entités Doctrine)

- **User** — client (email, mot de passe hashé, rôles, profil).
- **Product** — copie locale d'un produit Wupex : `sku`, `productCode`, `name`, `type` (`voucher`|`topup`), `subType` (1–5, pour les top-ups), `purchasePrice` (USD, prix Wupex), `salePrice` (XOF, calculé), `enabled`, `imageUrl`, `lastSyncedAt`.
- **Order** — commande client : `reference` (unique, = referenceId Wupex), `User`, `status`, `totalXof`, timestamps.
- **OrderItem** — ligne : `Product`, `quantity`, prix figés, et pour les top-ups les champs `gameUserId` / `serverId` / `zoneId` / `attributes` (JSON).
- **Payment** — transaction CinetPay liée à l'`Order` : `transactionId`, `status`, `amount`, `operator`, payloads bruts.
- **Fulfillment** — exécution de la commande côté Wupex : lien `referenceId` ↔ `orderName` Wupex, `status`, compteur de tentatives, dernier message d'erreur.
- **DeliveredCode** — code livré rattaché à un `OrderItem` : `serialNumber`, `serialCode` (chiffré au repos), `productSku`.

### États de l'`Order`
`cart` → `pending_payment` → `paid` → `fulfilling` → `fulfilled`
Branches d'erreur : `payment_failed`, `fulfillment_failed` (→ intervention admin : relance ou remboursement/avoir).

## 6. Tunnel de commande & livraison (cœur du système)

1. Client connecté → catalogue → panier.
2. Pour un top-up, on capture les champs requis **selon `subType`** :
   - `1` : userId ; `2` : userId + serverId (via `topup-listservers`) ; `3` : userId + zoneId ; `4` : userId + serverId + zoneId ; `5` : attributs (via `topup/product/attribute`).
3. Checkout → création `Order` en **`pending_payment`** avec un **`reference` unique** (idempotence).
4. `CinetPayClient.initPayment()` → redirection vers Mobile Money.
5. **Webhook CinetPay** reçu → `verifyPayment()` → si OK, `Order` = **`paid`** et on **dispatch un message** `FulfillOrder`.
6. Le handler Messenger appelle Wupex (`pull-codes` pour les vouchers, `topup` pour les top-ups) en réutilisant `reference` comme `referenceId`. **Réessais automatiques** en cas d'échec transitoire.
7. Récupération des codes via `getOrderDetail(orderName)` → stockés (`DeliveredCode`) → `Order` = **`fulfilled`**.
8. **Livraison** : affichage dans l'espace client + **email**.
9. Échec définitif → `fulfillment_failed`, alerte admin, remboursement/avoir manuel.

**Idempotence :** une commande déjà `fulfilled`/`fulfilling` ne redéclenche jamais un achat Wupex. Le `reference` unique + l'`orderName` mémorisé empêchent tout double achat.

## 7. Tarification & devise

- Wupex facture en **USD** ; CinetPay encaisse en **FCFA (XOF)**.
- Prix de vente = `purchasePrice (USD) × tauxUSD_XOF × (1 + marge%)`, arrondi.
- `MARGIN_PERCENT` et `USD_XOF_RATE` sont **configurables** (paramètres / back-office). Le taux est saisi manuellement en v1 (pas d'API de change).

## 8. Sécurité

- `WUPEX_API_KEY`, identifiants CinetPay et secrets **uniquement dans `.env.local`** (jamais commités ; `.gitignore` configuré).
- ⚠️ La clé API partagée en clair doit être **considérée comme exposée** → à **régénérer** dans le portail Wupex avant la mise en production.
- HTTPS obligatoire en production ; protection CSRF Symfony sur tous les formulaires.
- Webhook CinetPay **vérifié** (token/signature) ; statut de paiement toujours **revalidé côté serveur**.
- `serialCode` des vouchers **chiffré au repos** en base.
- Mots de passe hashés (hasher Symfony).

## 9. Direction artistique — « Neon Nocturne »

- **Fond :** très sombre (`#0B0B14` / `#12121F`).
- **Accents :** dégradé **violet → cyan** (`#7C3AED` → `#22D3EE`) pour CTA et survols.
- **Cartes :** glassmorphism (verre dépoli, bordures lumineuses, halo doux).
- **Typographie :** sans-serif moderne, titres généreux ; bonne hiérarchie.
- **Détails :** boutons lumineux (glow), micro-animations sobres, états de chargement soignés.
- **Accessibilité :** contraste suffisant malgré le thème sombre ; focus visibles.
- La qualité visuelle finale s'appuiera sur la skill `frontend-design` lors de l'implémentation.

## 10. Back-office admin

EasyAdmin (ou équivalent) : gestion produits & marges, **synchronisation du catalogue** Wupex, suivi commandes/paiements, **relance manuelle** des livraisons bloquées, consultation du **solde Wupex** (`customer/balance`), suivi des commandes en échec.

## 11. Fiabilité

- Livraison Wupex **asynchrone** via Messenger (transport Doctrine) avec stratégie de **réessais** + file d'échec (`failed`).
- Worker : `php bin/console messenger:consume async` (documenté pour le déploiement).
- Toute commande `paid` non livrée reste visible et **relançable** par l'admin → garantie « pas d'argent encaissé sans livraison ».

## 12. Inputs requis (de l'utilisateur)

1. **`WUPEX_MERCHANT_CODE`** (vide dans le fichier d'environnement fourni).
2. Confirmation que la clé fournie est bien **Sandbox** (sinon en obtenir une de test).
3. Identifiants **CinetPay** : `apikey` + `site_id` (sandbox d'abord).

## 13. Critères de réussite

- Un client peut s'inscrire, acheter un voucher **et** un top-up, payer en Mobile Money (sandbox), et **recevoir ses codes** dans son espace + par email.
- Aucune commande payée ne reste sans livraison ni sans trace : tout échec est visible et relançable côté admin.
- Aucun secret n'est présent dans le dépôt git.
- L'interface respecte la direction « Neon Nocturne » et est responsive.

## 14. Décomposition d'implémentation (aperçu)

L'implémentation sera détaillée dans un plan séparé (skill `writing-plans`), probablement par lots :
1. Scaffolding Symfony + base + sécurité (comptes clients).
2. `WupexClient` + synchro catalogue + pages catalogue (Neon Nocturne).
3. Panier + saisie top-up (subType) + checkout.
4. `CinetPayClient` + webhook + états de paiement.
5. Livraison asynchrone (Messenger) + récupération codes + email + espace client.
6. Back-office admin.
