350 lines
12 KiB
Markdown
350 lines
12 KiB
Markdown
|
|
# 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 |
|