veza/docs/PLAN_V0_601_IMPLEMENTATION.md

428 lines
12 KiB
Markdown
Raw Normal View History

# Plan d'implémentation v0.601 — Production Readiness & Commerce
**Date** : 2026-02-22
**Base** : v0.503 taguée
**Durée estimée** : 6 sprints (~30 jours ouvrés)
**Référence** : [V0_601_RELEASE_SCOPE.md](V0_601_RELEASE_SCOPE.md)
---
## Vue d'ensemble
```
Sprint 1 (j1-5) → INF1 : Infrastructure Production (blue-green, Grafana, health)
Sprint 2 (j6-10) → COM1 : Commerce (reviews, factures, remboursements, Hyperswitch prod)
Sprint 3 (j11-15) → AUTH1 : OAuth Discord & Spotify
Sprint 4 (j16-22) → CLN1 : Dette technique (découpage handler, interceptors, migrations)
Sprint 5 (j23-27) → QA1 : Tests E2E, smoke test, documentation
Sprint 6 (j28-30) → QA2 : Rétrospective, tag v0.601
```
---
## Diagramme d'architecture cible
```mermaid
flowchart TD
subgraph LB["Load Balancer"]
HAProxy["HAProxy Blue-Green"]
end
subgraph Blue["Blue Stack"]
API1["veza-backend-api"]
Stream1["veza-stream-server"]
end
subgraph Green["Green Stack"]
API2["veza-backend-api"]
Stream2["veza-stream-server"]
end
subgraph Monitor["Monitoring"]
Prometheus["Prometheus"]
Grafana["Grafana Dashboards"]
Alertmanager["Alertmanager"]
end
subgraph Commerce["Commerce"]
Reviews["Reviews API"]
Invoice["Invoice PDF"]
Refund["Refund API"]
end
HAProxy --> Blue
HAProxy --> Green
API1 --> Prometheus
API2 --> Prometheus
Prometheus --> Grafana
Prometheus --> Alertmanager
API1 --> Reviews
API1 --> Invoice
API1 --> Refund
```
---
## Sprint 1 — Infrastructure Production (jours 1-5)
> **Objectif** : Blue-green deployment, dashboards Grafana, health check enrichi, graceful shutdown.
### Tâche INF1-01 : Blue-green deployment
**Fichiers** :
- `config/haproxy/haproxy.cfg` — ajouter backends blue/green, health checks
- `config/caddy/Caddyfile.staging` — alternative si Caddy utilisé
- `docker-compose.prod.yml` — deux stacks (blue, green)
- `scripts/deploy-blue-green.sh` — script bascule manuelle
**Exemple HAProxy** :
```haproxy
backend api_blue
balance roundrobin
option httpchk GET /api/v1/health
http-check expect status 200
server api1 api-blue:8080 check
backend api_green
balance roundrobin
option httpchk GET /api/v1/health
http-check expect status 200
server api1 api-green:8080 check
```
### Tâche INF1-02 : Dashboards Grafana
**Fichiers** :
- `config/grafana/dashboards/api-overview.json` — latence, erreurs, throughput
- `config/grafana/dashboards/chat-overview.json` — connexions WS, messages/s
- `config/grafana/dashboards/commerce-overview.json` — orders, checkout, refunds
**Validation** : Dashboards chargent les métriques Prometheus existantes.
### Tâche INF1-03 : Alertmanager
**Fichier** : `config/alertmanager/alertmanager.yml`
```yaml
route:
receiver: 'slack-default'
group_by: ['alertname']
receivers:
- name: 'slack-default'
slack_configs:
- api_url: '${SLACK_WEBHOOK_URL}'
channel: '#alerts'
```
### Tâche INF1-04 : Graceful shutdown
**Fichier** : `veza-backend-api/cmd/api/main.go`
```go
srv := &http.Server{Addr: ":" + port, Handler: router}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
```
**Fichier** : `veza-stream-server/src/main.rs` — gérer SIGTERM, drain connexions.
### Tâche INF1-05 : Health check enrichi
**Fichier** : `veza-backend-api/internal/handlers/health.go`
```go
type HealthResponse struct {
Status string `json:"status"` // "ok" | "degraded"
DB string `json:"db"`
Redis string `json:"redis"`
RabbitMQ string `json:"rabbitmq,omitempty"`
Checks map[string]string `json:"checks"`
}
```
**Validation Sprint 1** :
```bash
cd veza-backend-api && go build ./...
curl -s http://localhost:8080/api/v1/health | jq
```
**Commit Sprint 1** : `feat(infra): blue-green deployment, Grafana dashboards, enriched health check, graceful shutdown`
---
## Sprint 2 — Commerce Finalisation (jours 6-10)
> **Objectif** : Reviews produits, factures PDF, remboursements, Hyperswitch production.
### Tâche COM1-01 : Reviews produits
**Migration** : `veza-backend-api/migrations/114_product_reviews.sql`
```sql
CREATE TABLE IF NOT EXISTS product_reviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
rating INT NOT NULL CHECK (rating >= 1 AND rating <= 5),
comment TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(product_id, user_id)
);
CREATE INDEX idx_product_reviews_product ON product_reviews(product_id);
```
**Fichiers** :
- `internal/models/product_review.go` — modèle GORM
- `internal/repositories/product_review_repository.go` — CRUD
- `internal/handlers/marketplace_handler.go` — POST/GET reviews, GET moyenne
- Frontend : `ProductDetail` — affichage reviews, formulaire
### Tâche COM1-02 : Factures PDF
**Fichier** : `veza-backend-api/internal/services/invoice_service.go`
- Lib : `github.com/jung-kurt/gofpdf` ou `github.com/signintech/gopdf`
- Template : numéro facture, date, items, total, TVA
- `GET /api/v1/orders/:id/invoice` — génère et retourne PDF
**Frontend** : bouton « Télécharger facture » dans OrdersView.
### Tâche COM1-03 : Remboursements
**Fichiers** :
- `internal/models/order.go` — champ `refund_status`
- `internal/handlers/marketplace_handler.go``POST /orders/:id/refund`
- `internal/services/hyperswitch_service.go` — appel Hyperswitch refund API
- Webhook : traiter `refund.succeeded`, mettre à jour order, révoquer licence
### Tâche COM1-04 : Hyperswitch production
**Fichier** : `veza-backend-api/internal/config/config.go`
```go
HyperswitchLiveMode bool // HYPERSWITCH_LIVE_MODE
HyperswitchSecret string // Webhook secret pour validation
```
### Tâche COM1-05 : MSW + Stories
**Fichiers** :
- `apps/web/src/mocks/handlers.ts` — handlers reviews, invoice, refund
- `apps/web/src/features/` — stories ProductReviews, InvoiceDownload, RefundButton
**Validation Sprint 2** :
```bash
cd veza-backend-api && go test ./internal/... -v -count=1 -run Commerce
cd apps/web && npm run build
```
**Commit Sprint 2** : `feat(commerce): product reviews, PDF invoices, refunds, Hyperswitch production mode`
---
## Sprint 3 — OAuth Discord & Spotify (jours 11-15)
> **Objectif** : Implémenter les providers OAuth manquants.
### Tâche AUTH1-01 : OAuth Discord
**Fichier** : `veza-backend-api/internal/services/oauth_service.go`
- Config : `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET`, `DISCORD_REDIRECT_URI`
- Scopes : `identify`, `email`
- Callback : `GET /auth/discord/callback`
- Mapping : `discord_id` → user, création si nouveau
### Tâche AUTH1-02 : OAuth Spotify
**Fichier** : `veza-backend-api/internal/services/oauth_service.go`
- Config : `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`, `SPOTIFY_REDIRECT_URI`
- Scopes : `user-read-email`
- Callback : `GET /auth/spotify/callback`
### Tâche AUTH1-03 : Tests OAuth
**Fichiers** : `internal/services/oauth_discord_test.go`, `oauth_spotify_test.go`
### Tâche AUTH1-04 : FEATURE_STATUS
**Fichier** : `docs/FEATURE_STATUS.md` — OAuth Discord/Spotify → opérationnel
**Validation Sprint 3** :
```bash
cd veza-backend-api && go test ./internal/services/... -v -run OAuth
```
**Commit Sprint 3** : `feat(auth): OAuth Discord and Spotify providers`
---
## Sprint 4 — Dette Technique (jours 16-22)
> **Objectif** : Découper handler.go, interceptors.ts, consolidation migrations.
### Tâche CLN1-01 : Découper handler.go (track)
**Fichier actuel** : `veza-backend-api/internal/core/track/handler.go` (~1463 LOC)
**Découpage** :
- `track_crud_handler.go` — ListTracks, GetTrack, UpdateTrack, DeleteTrack, BatchDelete, BatchUpdate
- `track_social_handler.go` — LikeTrack, UnlikeTrack, GetTrackLikes, GetUserLikedTracks, CreateShare, GetSharedTrack, RevokeShare
- `track_search_handler.go` — SearchTracks, GetRecommendations, GetSuggestedTags
- `track_analytics_handler.go` — GetTrackStats, GetTrackHistory, RecordPlay
- `handler.go` — facade, getUserID, respondWithError, délégation
**Objectif** : `handler.go` < 500 LOC.
### Tâche CLN1-02 : Découper interceptors.ts
**Fichier actuel** : `apps/web/src/services/api/interceptors.ts` (~1207 LOC)
**Découpage** :
- `interceptors/auth.ts` — auth interceptor, token refresh
- `interceptors/error.ts` — error handling, retry
- `interceptors/logging.ts` — request/response logging
- `interceptors/index.ts` — re-export, composition
**Objectif** : chaque fichier < 400 LOC.
### Tâche CLN1-03 : Consolidation migrations
**Fichier** : `scripts/squash_migrations.sh`
```bash
#!/bin/bash
# Génère une baseline SQL à partir de toutes les migrations
OUT=veza-backend-api/migrations/baseline.sql
cat veza-backend-api/migrations/*.sql | grep -v '^--' > "$OUT"
echo "Baseline: $(wc -l < "$OUT") lines"
```
**Fichier** : `docs/MIGRATIONS.md` — documenter le processus, usage baseline.
### Tâche CLN1-04 : Audit console.log
**Commande** : `rg 'console\.log' apps/web/src --type-add 'ts:*.{ts,tsx}' -t ts -l`
Remplacer par : `import { logger } from '@/utils/logger'` puis `logger.debug(...)`.
**Validation Sprint 4** :
```bash
cd veza-backend-api && go test ./internal/core/track/... -v
cd apps/web && npm run build
```
**Commit Sprint 4** : `refactor: split track handler and interceptors, add migration baseline script`
---
## Sprint 5 — Tests, Documentation (jours 23-27)
### Tâche QA1-01 : Tests E2E commerce
**Fichier** : `veza-backend-api/internal/integration/e2e_commerce_test.go`
Flow : upload → achat → review → facture → remboursement (optionnel).
### Tâche QA1-02 : Smoke test v0.601
**Fichier** : `docs/SMOKE_TEST_V0601.md`
Checklist :
- [ ] Blue-green : bascule manuelle OK
- [ ] Health : DB, Redis, RabbitMQ (degraded si un down)
- [ ] Grafana : 3 dashboards chargent
- [ ] Reviews : création, affichage, moyenne
- [ ] Facture : téléchargement PDF
- [ ] Remboursement : initiation refund
- [ ] OAuth Discord : login
- [ ] OAuth Spotify : login
- [ ] track handler : < 500 LOC
- [ ] interceptors : < 400 LOC par fichier
### Tâche QA1-03 : Mise à jour docs
**Fichiers** :
- `docs/PROJECT_STATE.md` — section v0.601 livrée
- `docs/FEATURE_STATUS.md` — OAuth Discord/Spotify → opérationnel
- `CHANGELOG.md` — section v0.601
### Tâche QA1-04 : Archiver scope, placeholder v0.602
- Déplacer `V0_601_RELEASE_SCOPE.md``docs/archive/`
- Créer placeholder `V0_602_RELEASE_SCOPE.md`
### Tâche QA1-05 : Rétrospective
**Fichier** : `docs/RETROSPECTIVE_V0601.md`
**Commit Sprint 5** : `docs(v0.601): smoke test, changelog, retrospective`
---
## Sprint 6 — Tag v0.601 (jours 28-30)
### Tâche QA2-01 : Tag
```bash
git tag -a v0.601 -m "v0.601 — Production Readiness & Commerce"
```
### Tâche QA2-02 : Mise à jour SCOPE_CONTROL
**Fichier** : `docs/SCOPE_CONTROL.md` — référence active → V0_602_RELEASE_SCOPE.md
**Commit Sprint 6** : `chore(release): tag v0.601`
---
## Commits récapitulatifs
| Sprint | Commit |
|--------|--------|
| 1 | `feat(infra): blue-green deployment, Grafana dashboards, enriched health check, graceful shutdown` |
| 2 | `feat(commerce): product reviews, PDF invoices, refunds, Hyperswitch production mode` |
| 3 | `feat(auth): OAuth Discord and Spotify providers` |
| 4 | `refactor: split track handler and interceptors, add migration baseline script` |
| 5 | `docs(v0.601): smoke test, changelog, retrospective` |
| 6 | `chore(release): tag v0.601` |
---
## Dépendances entre lots
```
INF1 (Infra) → indépendant
COM1 (Commerce) → indépendant
AUTH1 (OAuth) → indépendant
CLN1 (Dette) → indépendant (peut être fait en parallèle avec INF1/COM1/AUTH1)
QA1 (Tests) → dépend de INF1, COM1, AUTH1, CLN1
QA2 (Tag) → dépend de QA1
```
---
## Risques et mitigations
| Risque | Mitigation |
|--------|------------|
| Stripe Connect / Payout complexe | Reporté en v0.602, focus reviews/factures/remboursements |
| Génération PDF lourde | Utiliser gofpdf, génération async si besoin |
| Blue-green 2x ressources | Documenter option rolling si ressources limitées |
| OAuth quotas Discord/Spotify | Documenter limites, rate limiting côté provider |