# Plan d'implémentation v0.602 — Payout, Dette Technique & Tests E2E **Date** : 2026-02-22 **Base** : v0.601 taguée **Durée estimée** : 5 sprints (~25 jours ouvrés) **Référence** : [V0_602_RELEASE_SCOPE.md](V0_602_RELEASE_SCOPE.md) --- ## Vue d'ensemble ``` Sprint 1 (j1-5) → CLN2 : Split interceptors (auth, error) Sprint 2 (j6-12) → P3 : Payout vendeurs (Stripe Connect) Sprint 3 (j13-17) → INF2 : Dashboards Grafana métriques réelles Sprint 4 (j18-22) → QA2 : Tests E2E commerce, smoke test Sprint 5 (j23-25) → Docs, rétrospective, tag v0.602 ``` --- ## Diagramme d'architecture cible ```mermaid flowchart TD subgraph Seller["Seller Flow"] Onboard["Stripe Connect Onboard"] Balance["GET /sell/balance"] Transfer["Transfer after sale"] end subgraph Interceptors["API Interceptors"] Auth["auth.ts - token refresh"] Error["error.ts - error handling"] Request["request.ts"] Response["response.ts"] end subgraph Monitor["Monitoring"] Grafana["Grafana - métriques réelles"] end Seller --> Onboard Onboard --> Balance Balance --> Transfer Auth --> Error ``` --- ## Sprint 1 — Split interceptors (jours 1-5) > **Objectif** : Extraire auth.ts et error.ts, réduire interceptors.ts à une facade. ### Tâche CLN2-01 : Extraire auth interceptor **Fichier nouveau** : `apps/web/src/services/api/interceptors/auth.ts` - Déplacer : `isRefreshing`, `refreshAttempts`, `MAX_REFRESH_ATTEMPTS`, `failedQueue`, `processQueue` - Logique token refresh : détection 401, appel `refreshToken`, mise en queue des requêtes en attente - Exporter : `createAuthRequestInterceptor`, `createAuthResponseInterceptor` (ou équivalent) **Fichier** : `apps/web/src/services/api/interceptors.ts` - Importer depuis `auth.ts`, supprimer le code déplacé **Commit** : `refactor(api): extract auth interceptor to interceptors/auth.ts` ### Tâche CLN2-02 : Extraire error interceptor **Fichier nouveau** : `apps/web/src/services/api/interceptors/error.ts` - Déplacer : gestion `AxiosError`, `parseApiError`, `getErrorCategory`, `formatUserFriendlyError` - Logique retry : `isRetryableError`, `getRetryDelay`, `networkFailureTracker` - Toast, offline queue, rate limit store - Exporter : `createErrorResponseHandler(apiClient)` **Fichier** : `apps/web/src/services/api/interceptors.ts` - Importer depuis `error.ts`, supprimer le code déplacé **Commit** : `refactor(api): extract error interceptor to interceptors/error.ts` ### Tâche CLN2-03 : Réduire interceptors.ts à facade **Fichier** : `apps/web/src/services/api/interceptors.ts` - Garder uniquement : imports des 5 modules (utils, request, response, auth, error) - Composition : `apiClient.interceptors.request.use(...)`, `apiClient.interceptors.response.use(...)` - Objectif : < 80 LOC **Fichier** : `apps/web/src/services/api/interceptors/index.ts` (créer si absent) - Re-exporter les modules pour usage externe **Commit** : `refactor(api): reduce interceptors.ts to facade, add interceptors/index.ts` ### Tâche CLN2-04 : Validation ```bash cd apps/web && npm run build cd apps/web && npm test -- --run rg '\.ts$' apps/web/src/services/api/interceptors/ -l | xargs wc -l ``` - Chaque fichier interceptors < 400 LOC - Aucune régression **Commit** : `test(api): validate interceptors split, all tests pass` --- ## Sprint 2 — Payout vendeurs (jours 6-12) > **Objectif** : Stripe Connect onboarding, balance, transfert après vente. ### Tâche P3-01 : Config Stripe Connect **Fichier** : `veza-backend-api/internal/config/config.go` ```go StripeConnectClientID string // STRIPE_CONNECT_CLIENT_ID StripeConnectSecret string // STRIPE_CONNECT_SECRET StripeConnectWebhookSecret string // STRIPE_CONNECT_WEBHOOK_SECRET ``` **Fichier** : `.env.example` — documenter les variables **Commit** : `feat(seller): add Stripe Connect config` ### Tâche P3-02 : Migration seller_stripe_accounts **Fichier** : `veza-backend-api/migrations/114_seller_stripe_accounts.sql` ```sql CREATE TABLE IF NOT EXISTS seller_stripe_accounts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE UNIQUE, stripe_account_id VARCHAR(255) NOT NULL UNIQUE, onboarding_completed BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_seller_stripe_accounts_user ON seller_stripe_accounts(user_id); ``` **Commit** : `feat(seller): add seller_stripe_accounts migration` ### Tâche P3-03 : POST /sell/connect/onboard **Fichier** : `veza-backend-api/internal/handlers/sell_handler.go` (ou créer) - Handler `ConnectOnboard` : vérifier user vendeur, créer lien Stripe Express, redirect URL - Route : `POST /api/v1/sell/connect/onboard` - Callback : `GET /api/v1/sell/connect/callback` — traiter retour Stripe, sauvegarder account_id **Commit** : `feat(seller): add Stripe Connect onboarding endpoint` ### Tâche P3-04 : GET /sell/balance **Fichier** : `veza-backend-api/internal/services/stripe_connect_service.go` (ou sell_service.go) - `GetSellerBalance(userID)` : appeler Stripe API Balance, ou table locale si cache - Handler : `GET /api/v1/sell/balance` — retourne `{ available, pending }` **Commit** : `feat(seller): add balance endpoint` ### Tâche P3-05 : Transfert après vente **Fichier** : `veza-backend-api/internal/services/hyperswitch/` ou `stripe_connect_service.go` - Sur webhook `payment.succeeded` (ou post-order) : récupérer `transfer_data.destination` - Si vendeur a compte Connect : initier transfer vers son compte - Alternative MVP : ne pas implémenter transfert auto, documenter pour v0.603 **Commit** : `feat(seller): add payout transfer on sale` (ou `feat(seller): document payout transfer for v0.603` si MVP) ### Tâche P3-06 : SellerDashboardView — balance, onboarding **Fichier** : `apps/web/src/features/seller/SellerDashboardView.tsx` - Carte balance : afficher available, pending (ou message "Configurez les paiements") - Bouton « Configurer les paiements » : appelle `POST /sell/connect/onboard`, redirect Stripe **Fichier** : `apps/web/src/services/marketplaceService.ts` — `getSellerBalance()`, `connectOnboard()` **Commit** : `feat(seller): add balance and onboarding UI to SellerDashboard` ### Tâche P3-07 : MSW + Stories **Fichier** : `apps/web/src/mocks/handlers.ts` — handlers balance, onboard redirect **Stories** : `SellerBalanceCard`, `SellerOnboardingButton` **Commit** : `test(seller): add MSW handlers and stories for payout` --- ## Sprint 3 — Dashboards Grafana (jours 13-17) > **Objectif** : Connecter les dashboards aux métriques Prometheus réelles. ### Tâche INF2-04 : Vérifier exposition métriques backend **Fichier** : `veza-backend-api/internal/middleware/` — prometheus, metrics - Vérifier : `http_requests_total`, `http_request_duration_seconds`, `http_requests_errors` - Labels : method, path, status - Ajouter si manquant **Commit** : `feat(monitoring): ensure Prometheus metrics exposed for API` ### Tâche INF2-01 : API dashboard **Fichier** : `config/grafana/dashboards/api-overview.json` - Panels : rate(http_requests_total[5m]), histogram_quantile(0.95, http_request_duration_seconds), error rate - Top endpoints par volume **Commit** : `feat(monitoring): connect API dashboard to real Prometheus metrics` ### Tâche INF2-02 : Chat dashboard **Fichier** : `config/grafana/dashboards/chat-overview.json` - Panels : connexions WS actives (si métrique existe), messages/s - Vérifier métriques chat dans backend Go **Commit** : `feat(monitoring): connect Chat dashboard to real metrics` ### Tâche INF2-03 : Commerce dashboard **Fichier** : `config/grafana/dashboards/commerce-overview.json` - Panels : orders créés, checkout success, refunds - Métriques à exposer si manquantes : `commerce_orders_total`, `commerce_checkout_success_total` **Commit** : `feat(monitoring): connect Commerce dashboard to real metrics` --- ## Sprint 4 — Tests E2E (jours 18-22) > **Objectif** : E2E commerce, smoke test v0.602. ### Tâche QA2-01 : E2E commerce **Option A** : `veza-backend-api/internal/integration/e2e_commerce_test.go` - Flow : créer produit (ou utiliser fixture) → checkout (mock Hyperswitch) → review → invoice download - Utiliser testify, appels HTTP réels **Option B** : Playwright `apps/web/e2e/commerce.spec.ts` - Flow : login → marketplace → achat (mock) → review → téléchargement facture **Commit** : `test(commerce): add E2E flow upload-achat-review-facture` ### Tâche QA2-02 : Smoke test v0.602 **Fichier** : `docs/SMOKE_TEST_V0602.md` Checklist : - [ ] Payout : onboarding Stripe Connect, balance affichée - [ ] Interceptors : auth.ts, error.ts extraits, build OK - [ ] Grafana : 3 dashboards chargent métriques - [ ] Commerce : achat, review, facture, remboursement - [ ] OAuth : Discord, Spotify login **Commit** : `docs: add SMOKE_TEST_V0602.md` ### Tâche QA2-03 : Mise à jour docs **Fichiers** : - `docs/PROJECT_STATE.md` — section v0.602 livrée - `docs/FEATURE_STATUS.md` — P3 Payout → opérationnel - `CHANGELOG.md` — section v0.602 **Commit** : `docs: update PROJECT_STATE, FEATURE_STATUS, CHANGELOG for v0.602` --- ## Sprint 5 — Finalisation (jours 23-25) > **Objectif** : Archiver scope, rétrospective, tag. ### Tâche QA2-04 : Archive, placeholder, rétro, tag 1. Déplacer `V0_602_RELEASE_SCOPE.md` → `docs/archive/` 2. Créer placeholder `V0_603_RELEASE_SCOPE.md` 3. Créer `docs/RETROSPECTIVE_V0602.md` 4. Mettre à jour `docs/SCOPE_CONTROL.md` — référence active → V0_603 5. Tag : `git tag -a v0.602 -m "v0.602 — Payout, Dette Technique & Tests E2E"` **Commits** : - `chore(release): archive v0.602 scope, create v0.603 placeholder` - `docs: add RETROSPECTIVE_V0602.md` - `chore(release): tag v0.602` --- ## Commits récapitulatifs (ordre d'exécution) | # | Sprint | Commit | |---|--------|--------| | 1 | 1 | `refactor(api): extract auth interceptor to interceptors/auth.ts` | | 2 | 1 | `refactor(api): extract error interceptor to interceptors/error.ts` | | 3 | 1 | `refactor(api): reduce interceptors.ts to facade, add interceptors/index.ts` | | 4 | 1 | `test(api): validate interceptors split, all tests pass` | | 5 | 2 | `feat(seller): add Stripe Connect config` | | 6 | 2 | `feat(seller): add seller_stripe_accounts migration` | | 7 | 2 | `feat(seller): add Stripe Connect onboarding endpoint` | | 8 | 2 | `feat(seller): add balance endpoint` | | 9 | 2 | `feat(seller): add payout transfer on sale` | | 10 | 2 | `feat(seller): add balance and onboarding UI to SellerDashboard` | | 11 | 2 | `test(seller): add MSW handlers and stories for payout` | | 12 | 3 | `feat(monitoring): ensure Prometheus metrics exposed for API` | | 13 | 3 | `feat(monitoring): connect API dashboard to real Prometheus metrics` | | 14 | 3 | `feat(monitoring): connect Chat dashboard to real metrics` | | 15 | 3 | `feat(monitoring): connect Commerce dashboard to real metrics` | | 16 | 4 | `test(commerce): add E2E flow upload-achat-review-facture` | | 17 | 4 | `docs: add SMOKE_TEST_V0602.md` | | 18 | 4 | `docs: update PROJECT_STATE, FEATURE_STATUS, CHANGELOG for v0.602` | | 19 | 5 | `chore(release): archive v0.602 scope, create v0.603 placeholder` | | 20 | 5 | `docs: add RETROSPECTIVE_V0602.md` | | 21 | 5 | `chore(release): tag v0.602` | --- ## Dépendances entre lots ``` CLN2 (Interceptors) → indépendant (peut démarrer immédiatement) P3 (Payout) → indépendant INF2 (Grafana) → peut nécessiter P3 métriques commerce QA2 (Tests) → dépend de CLN2, P3, INF2 Sprint 5 → dépend de QA2 ``` --- ## Risques et mitigations | Risque | Mitigation | |--------|------------| | Stripe Connect complexité | MVP balance seule, transfert reporté v0.603 | | Hyperswitch vs Stripe | Vérifier doc Hyperswitch Connect ; Stripe si Hyperswitch non supporté | | Métriques backend absentes | Tâche INF2-04 en premier ; ajouter middleware si besoin | | E2E flaky | Utiliser mocks Hyperswitch ; éviter dépendances externes |