687 lines
44 KiB
Markdown
687 lines
44 KiB
Markdown
|
|
# ROADMAP — Veza v1.0 Public Launch (4-6 semaines)
|
|||
|
|
|
|||
|
|
> **Cible** : ouverture publique grand-public en 4-6 semaines, positionnée
|
|||
|
|
> comme alternative sérieuse à SoundCloud, sur infra self-hosted Incus
|
|||
|
|
> (R720 + débordement Hetzner si nécessaire).
|
|||
|
|
>
|
|||
|
|
> **Auteur** : architecte principal Veza + Claude Code Opus 4.7
|
|||
|
|
> **Dernière mise à jour** : 2026-04-26
|
|||
|
|
> **État de départ** : v1.0.8 + sprint 1 v1.0.9 partiellement livré
|
|||
|
|
> (Item G subscription en cours, items 1.2/1.3/1.4/1.5/1.6 commit-prêts)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 0. Cadrage honnête
|
|||
|
|
|
|||
|
|
**Compression** : le plan original (`/home/senke/.claude/plans/quelles-sont-les-prochaines-playful-beaver.md`)
|
|||
|
|
visait 24 semaines pour atteindre une vraie maturité opérationnelle. On
|
|||
|
|
compresse 4× ici. Ça implique de **trancher** sur ce qui rentre et ce
|
|||
|
|
qui n'y rentre pas — la liste explicite est en §2. Si tu doutes pendant
|
|||
|
|
les 6 semaines, reviens à §2 : tout ce qui n'y est pas listé comme IN
|
|||
|
|
attend post-launch.
|
|||
|
|
|
|||
|
|
**Réalité** :
|
|||
|
|
- Solo dev, ~50h/semaine, pas de marges pour rattraper du retard
|
|||
|
|
- 30 jours ouvrés disponibles, dont ~20% absorbés par l'imprévu (CI
|
|||
|
|
rouge, dette qui remonte, decisions externes)
|
|||
|
|
- Effort réel = 24 jours productifs sur 30
|
|||
|
|
- Budget temps perdu sur la légal/pentest/ops externes : 0 (ces tâches
|
|||
|
|
doivent tourner en parallèle, JAMAIS sur le critical path code)
|
|||
|
|
|
|||
|
|
**Verdict honnête** :
|
|||
|
|
- 4 semaines = irréaliste sauf à accepter risques élevés (pas de pentest
|
|||
|
|
externe, ToS template non-revu, infra single-instance)
|
|||
|
|
- **6 semaines = atteignable si discipline scope-control + démarrage
|
|||
|
|
immédiat des tâches externes**
|
|||
|
|
- 8 semaines = confortable
|
|||
|
|
|
|||
|
|
Je rédige pour 6 semaines avec marge à droite.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. À démarrer AUJOURD'HUI en parallèle (externe au code)
|
|||
|
|
|
|||
|
|
Ces actions ont des cycles longs incompressibles. Elles doivent partir
|
|||
|
|
**maintenant** sinon le lancement glisse de 2-4 semaines.
|
|||
|
|
|
|||
|
|
| # | Action | Cycle | Owner | Statut |
|
|||
|
|
|---|--------|-------|-------|--------|
|
|||
|
|
| EX-1 | Contacter avocat pour ToS / Privacy / DMCA / DSA | 2-4 sem | toi | ⏳ |
|
|||
|
|
| EX-2 | Demander devis pentest externe (ouvert sur surface v1.0.9) | 1 sem devis + 2 sem exec | toi | ⏳ |
|
|||
|
|
| EX-3 | Enregistrer agent DMCA US Copyright Office (~120 USD, 2-3 sem traitement) | 2-3 sem | toi | ⏳ |
|
|||
|
|
| EX-4 | Désigner point de contact DSA (UE) — soit toi soit représentant local | 1 sem | toi | ⏳ |
|
|||
|
|
| EX-5 | DNS production : `veza.fr`, `api.veza.fr`, `cdn.veza.fr`, `turn.veza.fr`, `embed.veza.fr` | 1 j | toi | ⏳ |
|
|||
|
|
| EX-6 | TLS certs (Let's Encrypt) pour tous les sous-domaines | 1 j | toi | ⏳ |
|
|||
|
|
| EX-7 | Compte CDN edge (Cloudflare R2 + Workers ou Bunny.net) | 1 j | toi | ⏳ |
|
|||
|
|
| EX-8 | Rotation OAuth secrets prod (Google, GitHub, Discord, Spotify) | 0.5 j | toi | ⏳ |
|
|||
|
|
| EX-9 | Stripe / Hyperswitch live mode setup + KYC marketplace | 2-3 sem | toi | ⏳ |
|
|||
|
|
| EX-10 | Email transactionnel : domaine custom + SPF/DKIM/DMARC (Mailjet/Postmark/Brevo) | 1 sem | toi | ⏳ |
|
|||
|
|
| EX-11 | Status page (statuspage.io free OU Cachet self-hosted) | 1 j | toi | ⏳ |
|
|||
|
|
| EX-12 | Coturn déploiement Incus (cf. `infra/coturn/README.md`) | 1 j | toi | ⏳ |
|
|||
|
|
|
|||
|
|
**Critical path externe** : EX-1 (légal) et EX-2 (pentest) sont les deux
|
|||
|
|
contraintes majeures. Si tu démarres EX-1 le lundi semaine 1, tu auras
|
|||
|
|
les drafts ToS/Privacy semaine 3 et la version finale signée semaine 5.
|
|||
|
|
EX-2 même calendrier : devis semaine 1, exécution semaines 4-5, rapport
|
|||
|
|
semaine 6. Sans ces deux-là on ne tag pas v2.0.0-public.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Scope contract — ce qui rentre vs sort
|
|||
|
|
|
|||
|
|
### IN (livré avant le tag v2.0.0-public)
|
|||
|
|
|
|||
|
|
**Code applicatif**
|
|||
|
|
- Sprint 1 v1.0.9 (subscription Item G + items 1.2/1.3/1.4/1.5/1.6 + 1.7 flake stab)
|
|||
|
|
- DMCA notice workflow (formulaire + admin queue + take-down handler)
|
|||
|
|
- Embed widget `/embed/track/:id` + oEmbed
|
|||
|
|
- Track sharing tokens privés (parité avec playlist share)
|
|||
|
|
- Service worker offline track cache (Workbox CacheFirst)
|
|||
|
|
- HLS streaming activé par défaut + ABR validé
|
|||
|
|
- Faceted search UI sur `/search` et `/discover`
|
|||
|
|
- Open Graph tags dynamiques sur les pages tracks/playlists
|
|||
|
|
- Status page côté ops + endpoint `/api/v1/status` public
|
|||
|
|
|
|||
|
|
**Infrastructure**
|
|||
|
|
- IaC Ansible playbooks (Postgres, Redis, MinIO, RabbitMQ, coturn, HAProxy, backend-api, stream-server)
|
|||
|
|
- Postgres streaming replica + pg_auto_failover (RTO < 60s)
|
|||
|
|
- pgBackRest WAL archive + restore drill cron hebdo
|
|||
|
|
- PgBouncer transaction-mode pool
|
|||
|
|
- Redis Sentinel 3-node
|
|||
|
|
- MinIO erasure-coded 4-node EC4+2
|
|||
|
|
- HAProxy frontal + 2 backend-api containers actif/actif (sticky WS)
|
|||
|
|
- CDN edge externe (Cloudflare R2 + Workers OU Bunny.net) câblé
|
|||
|
|
- OpenTelemetry collector → Tempo (traces visibles)
|
|||
|
|
- Loki HA 3 réplicas + S3 backend (sur ton MinIO)
|
|||
|
|
- SLO burn-rate alerts (remplacement seuils statiques)
|
|||
|
|
- Backup restore drill automatisé hebdo
|
|||
|
|
- Synthetic monitoring (blackbox exporter rejouant les 6 parcours)
|
|||
|
|
- Game day #1 réalisé + runbooks testés
|
|||
|
|
- Canary release script
|
|||
|
|
|
|||
|
|
**Légal**
|
|||
|
|
- Terms of Service (avocat-revu)
|
|||
|
|
- Privacy Policy RGPD + CCPA + DPA template processeurs
|
|||
|
|
- DMCA notice + agent enregistré
|
|||
|
|
- DSA point de contact + transparency report template
|
|||
|
|
- CGV vendeur marketplace
|
|||
|
|
- Mentions légales + politique cookies + bannière consentement
|
|||
|
|
|
|||
|
|
**Sécurité**
|
|||
|
|
- Pentest externe rapport reçu, 0 critique/haut ouvert
|
|||
|
|
- Secrets hors git (Vault sur conteneur Incus OU sops/age versionné)
|
|||
|
|
- Rotation OAuth secrets effectuée
|
|||
|
|
- JWT RS256 prod (déjà en place — vérifier rotation key)
|
|||
|
|
|
|||
|
|
**Business**
|
|||
|
|
- Stripe live mode actif + KYC créateurs testé E2E avec vrais fonds
|
|||
|
|
- Hyperswitch live mode actif + flux paiement E2E réel
|
|||
|
|
- Email transactionnel sur domaine custom (SPF/DKIM/DMARC OK)
|
|||
|
|
- 5-10 testeurs beta privée semaines 5-6 avec retours documentés
|
|||
|
|
|
|||
|
|
### OUT (deferred post-launch v1.1+)
|
|||
|
|
|
|||
|
|
- **Native mobile (iOS/Android)** — Capacitor wrap après launch (~3 semaines)
|
|||
|
|
- **Audio fingerprinting (Chromaprint)** — DMCA workflow MANUEL au launch ; fingerprinting v1.1
|
|||
|
|
- **Public API SDK** (`@veza/sdk-js`, `@veza/sdk-py`) + dev portal v2 — v1.1
|
|||
|
|
- **OAuth2 client credentials** + rate limit tiers per-app — v1.1
|
|||
|
|
- **Multi-region failover** — single region (R720 + Hetzner debordement) au launch
|
|||
|
|
- **Tipping / fan support** — décision business post-launch
|
|||
|
|
- **Distribution intégrale DSP** (TuneCore, CD Baby, etc.) — v1.1
|
|||
|
|
- **Subscription per-creator (Patreon-style)** — v1.1+
|
|||
|
|
- **CarPlay / Android Auto** — nécessite app native d'abord
|
|||
|
|
- **Lossless tier FLAC subscriber** — codec déjà supporté, exposer post-launch
|
|||
|
|
- **"Fresh from your follows" tab discovery** — déferred (chronologique du feed suffit au launch)
|
|||
|
|
- **Editorial collections admin UI** — défferred (curation manuelle DB au launch)
|
|||
|
|
- **Faceted search saved searches** — UI faceted suffit, "saved" v1.1
|
|||
|
|
|
|||
|
|
### COMPRESSED (livré mais minimum viable, à durcir post-launch)
|
|||
|
|
|
|||
|
|
- **MinIO erasure-coded** : 4 nœuds EC4+2 mais sur la même machine R720 (pas vraiment HA matériel — ajoute Hetzner storage post-launch)
|
|||
|
|
- **HAProxy sticky WS** : 2 backend-api sur la même machine R720 (pas N+1 hardware HA)
|
|||
|
|
- **Loki HA** : 3 réplicas en conteneurs Incus mais sur le même hôte (single-host failure mode, accepté pour launch)
|
|||
|
|
- **DMCA workflow** : workflow complet + agent enregistré, MAIS audit fingerprinting reporté → take-down purement humain
|
|||
|
|
- **Pentest** : externe mais light scope (auth + paiement + DMCA + uploads), pas full deep dive
|
|||
|
|
- **Game day** : 1 game day cycle complet, pas 3 cycles répétés
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Critical path & dépendances
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
EX-1 légal ──────────────────────────────▶ EX week 5 signature ──▶
|
|||
|
|
EX-2 pentest ────────────────────▶ EX week 4 exec ──▶ rapport week 6
|
|||
|
|
EX-9 stripe live ────────▶ KYC ──▶ test E2E vrais fonds week 5
|
|||
|
|
EX-10 email custom ──────▶ DKIM/SPF prop ────▶ délivrabilité week 4
|
|||
|
|
|
|||
|
|
Code:
|
|||
|
|
W1 finir v1.0.9 + IaC ──▶ W2 Postgres HA + obs ──▶ W3 stockage + features ──▶
|
|||
|
|
W4 PWA + search + load test ──▶ W5 game day + canary ──▶ W6 go-live
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Top-3 risques de glissement** :
|
|||
|
|
1. **Légal** : si EX-1 traîne, on tag mais on ne lance pas. Démarre lundi.
|
|||
|
|
2. **Pentest findings critiques** : si le pentest revèle un finding HIGH semaine 6, on rétrograde de tag et on patch — peut décaler 1-2 semaines. Mitigation : faire un pentest interne semaine 4 (ZAP + nuclei + manual audit) pour pré-filtrer.
|
|||
|
|
3. **Postgres HA failover en game day rouge** : si le failover n'atteint pas RTO < 60s on doit ré-architecturer. Mitigation : tester pg_auto_failover en lab Incus dès semaine 1.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Sprint breakdown — jour par jour
|
|||
|
|
|
|||
|
|
> **Convention** : chaque jour = ~6-8h productives. Acceptance criteria
|
|||
|
|
> mesurables. Si un jour déborde, le suivant glisse — pas de "je
|
|||
|
|
> rattraperai le week-end" autorisé sinon le burn-out garantit le slip
|
|||
|
|
> de 2 semaines fin de roadmap.
|
|||
|
|
|
|||
|
|
### Semaine 1 — Closer v1.0.9 + amorçage IaC
|
|||
|
|
|
|||
|
|
**Objectif** : tag v1.0.9, scaffolding Ansible posé, Postgres HA en lab.
|
|||
|
|
|
|||
|
|
#### Jour 1 — Lundi : Démarrer les externes + commit sprint 1
|
|||
|
|
- **AM** : Envoyer EX-1 (avocat), EX-2 (devis pentest), EX-3 (DMCA agent), EX-9 (Stripe KYC), EX-10 (email transactionnel). Ces 5 emails partent avant midi.
|
|||
|
|
- **PM** : Commit + push les 4 commits préparés (`/tmp/v1.0.9-commit-messages.md`). Vérifier CI Forgejo verte. Si rouge → debug avant de continuer.
|
|||
|
|
- **Acceptance** : 5 emails envoyés, 4 commits pushés, CI verte sur main.
|
|||
|
|
- **Files** : `/tmp/v1.0.9-commit-messages.md`
|
|||
|
|
|
|||
|
|
#### Jour 2 — Mardi : Item G subscription Phase 2
|
|||
|
|
- Webhook handler `subscription.payment_succeeded` / `payment_failed` dans `internal/services/hyperswitch/webhook_subscription.go`
|
|||
|
|
- Dispatcher dans `ProcessPaymentWebhook` qui détecte le type subscription et route
|
|||
|
|
- Reuse `webhook_raw_payloads` table (item E v1.0.7) pour persistence
|
|||
|
|
- Tests : webhook arrive → row pending_payment → active. Webhook payment_failed → expired.
|
|||
|
|
- **Acceptance** : 4 tests unitaires verts (success, failed, replay idempotent, unknown event)
|
|||
|
|
- **Files** : `internal/services/hyperswitch/webhook_subscription.go` (nouveau), `internal/services/hyperswitch/webhook_subscription_test.go` (nouveau)
|
|||
|
|
|
|||
|
|
#### Jour 3 — Mercredi : Item G subscription Phase 3 + E2E
|
|||
|
|
- Endpoint recovery `POST /api/v1/subscriptions/complete/:id` qui retourne le `client_secret` Hyperswitch pour reprendre un paiement stalled
|
|||
|
|
- Distribution gate : `distribution.checkEligibility` traite `pending_payment` comme ineligible
|
|||
|
|
- E2E `@critical` `tests/e2e/subscription-pending-payment.spec.ts` : subscribe paid plan → distribution submit retourne 403 → simuler webhook → distribution OK
|
|||
|
|
- Remove `TODO(v1.0.7-item-G)` annotation dans `subscription/service.go`
|
|||
|
|
- **Acceptance** : E2E vert + grep TODO Item G = 0 hit
|
|||
|
|
- **Files** : `internal/handlers/subscription_handler.go`, `internal/api/routes_subscription.go`, `internal/core/distribution/service.go`, `tests/e2e/28-subscription-pending-payment.spec.ts`
|
|||
|
|
|
|||
|
|
#### Jour 4 — Jeudi : Item 1.7 flake stab + tag v1.0.9
|
|||
|
|
- Lire les rapports CI Forgejo des 5 derniers runs E2E sur main
|
|||
|
|
- Identifier flakes : tests qui ont failé puis passé sans changement code
|
|||
|
|
- Stabiliser : remplacer `waitForTimeout` par `waitFor` ciblés, ajouter retry-on-flake helpers, augmenter `expect.timeout` ciblé
|
|||
|
|
- 3 cycles E2E nightly verts consécutifs avant tag
|
|||
|
|
- **Acceptance** : 3 nightly E2E verts, `git tag v1.0.9` poussé
|
|||
|
|
- **Files** : `tests/e2e/*.spec.ts` (stabilisations ciblées), `tests/e2e/playwright.config.ts` (timeout ciblé si nécessaire)
|
|||
|
|
|
|||
|
|
#### Jour 5 — Vendredi : IaC scaffolding Ansible
|
|||
|
|
- Créer `infra/ansible/` avec layout standard : `inventory/`, `group_vars/`, `host_vars/`, `roles/`, `playbooks/`
|
|||
|
|
- Inventaire : 1 host R720 prod + 1 host Hetzner staging + 1 host R720 lab
|
|||
|
|
- Rôle `common` : SSH hardening, fail2ban, unattended-upgrades, monitoring agent
|
|||
|
|
- Rôle `incus_host` : install Incus + configuration networking
|
|||
|
|
- Test : déployer le rôle common sur le host lab
|
|||
|
|
- **Acceptance** : `ansible-playbook -i inventory/lab playbooks/site.yml --check` passe sans erreur
|
|||
|
|
- **Files** : `infra/ansible/inventory/{lab,staging,prod}.yml`, `infra/ansible/playbooks/site.yml`, `infra/ansible/roles/common/tasks/main.yml`, `infra/ansible/roles/incus_host/tasks/main.yml`, `infra/ansible/README.md`
|
|||
|
|
|
|||
|
|
**Verification gate W1** : tag v1.0.9 poussé, Ansible scaffolding fonctionne en lab, externes EX-1 à EX-10 démarrés.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Semaine 2 — Postgres HA + observabilité
|
|||
|
|
|
|||
|
|
**Objectif** : Postgres failover automatique testé, OpenTelemetry collector wired, SLO alerts définies.
|
|||
|
|
|
|||
|
|
#### Jour 6 — Lundi : Postgres HA — pg_auto_failover lab
|
|||
|
|
- Rôle Ansible `postgres_ha` : 2 conteneurs Incus (primary + replica), pg_auto_failover monitor
|
|||
|
|
- Configuration : sync replication, HOT_STANDBY, max_wal_senders, etc.
|
|||
|
|
- Test : kill primary, vérifier failover automatique en < 60s, vérifier replica devient primary
|
|||
|
|
- **Acceptance** : failover test scripté `infra/ansible/tests/test_pg_failover.sh` rouge avant fix, vert après. RTO mesuré < 60s.
|
|||
|
|
- **Files** : `infra/ansible/roles/postgres_ha/{tasks,templates,defaults}/`, `infra/ansible/tests/test_pg_failover.sh`
|
|||
|
|
|
|||
|
|
#### Jour 7 — Mardi : PgBouncer + connection pool
|
|||
|
|
- Rôle Ansible `pgbouncer` : conteneur Incus avec PgBouncer en transaction mode
|
|||
|
|
- Pool size : 50 server connections × 1000 client connections capacity
|
|||
|
|
- Backend-api config : `DATABASE_URL` pointe vers PgBouncer, pas direct Postgres
|
|||
|
|
- Load test : 500 connexions concurrentes simulées via `pgbench`, vérifier pas d'épuisement
|
|||
|
|
- **Acceptance** : pgbench 500 clients × 30s sans erreur de connexion
|
|||
|
|
- **Files** : `infra/ansible/roles/pgbouncer/{tasks,templates}/`, `veza-backend-api/internal/config/config.go` (URL pointe PgBouncer en prod)
|
|||
|
|
|
|||
|
|
#### Jour 8 — Mercredi : pgBackRest + restore drill
|
|||
|
|
- Rôle Ansible `pgbackrest` : install + configuration WAL archive vers MinIO bucket dédié
|
|||
|
|
- Backup full hebdo + différentiels quotidiens + WAL continu
|
|||
|
|
- Script `scripts/dr-drill.sh` : restore le dernier full+WAL dans un conteneur éphémère, lance `cmd/tools/seed --ci` partial check, assertion `SELECT count(*) FROM users > 0`
|
|||
|
|
- Cron hebdo qui execute le script + alerte Prometheus si fail
|
|||
|
|
- **Acceptance** : `bash scripts/dr-drill.sh` passe vert localement
|
|||
|
|
- **Files** : `infra/ansible/roles/pgbackrest/{tasks,templates}/`, `scripts/dr-drill.sh`, `config/prometheus/alert_rules.yml` (ajout `BackupRestoreDrillFailed`)
|
|||
|
|
|
|||
|
|
#### Jour 9 — Jeudi : OpenTelemetry collector + Tempo
|
|||
|
|
- Rôle Ansible `otel_collector` : conteneur OpenTelemetry collector (config receivers + processors + exporters)
|
|||
|
|
- Conteneur Tempo (Grafana stack) pour stocker les traces
|
|||
|
|
- Backend-api : exporter OTLP vers le collector (déjà câblé en émetteur, juste activer le wire)
|
|||
|
|
- Instrumenter 4 hot paths : auth login, track upload (chunked init/chunk/complete), payment webhook, search
|
|||
|
|
- Dashboard Grafana basique avec service map + p99 par endpoint
|
|||
|
|
- **Acceptance** : tracer une requête login → voir le span dans Tempo UI
|
|||
|
|
- **Files** : `infra/ansible/roles/otel_collector/`, `config/otel/collector-config.yaml`, `veza-backend-api/internal/tracing/otlp_exporter.go` (nouveau ou extension), `config/grafana/dashboards/service-map.json`
|
|||
|
|
|
|||
|
|
#### Jour 10 — Vendredi : SLO burn-rate alerts + runbooks
|
|||
|
|
- Définir 3 SLO dans `config/prometheus/slo.yml` :
|
|||
|
|
- `SLO_API_AVAILABILITY` : 99.5% sur `/api/v1/health` + endpoints lecture
|
|||
|
|
- `SLO_API_LATENCY` : 99% p95 < 500ms sur endpoints écriture
|
|||
|
|
- `SLO_PAYMENT_SUCCESS` : 99.5% des `/api/v1/orders` POST → 201
|
|||
|
|
- Multi-window burn-rate alerts (fast 1h burn 14.4× → page, slow 6h burn 6× → ticket)
|
|||
|
|
- Annotations `runbook_url` sur chaque alert pointant `docs/runbooks/<alert-name>.md`
|
|||
|
|
- Squelette runbooks pour les 6 alerts les plus probables
|
|||
|
|
- **Acceptance** : `promtool check rules config/prometheus/slo.yml` vert, dashboard Grafana SLO visible avec error budget tracking
|
|||
|
|
- **Files** : `config/prometheus/slo.yml`, `config/alertmanager/routes.yml` (acheminement page vs ticket), `docs/runbooks/{api-availability-slo-burn,payment-success-slo-burn,db-failover,redis-down,disk-full,cert-expiring-soon}.md`
|
|||
|
|
|
|||
|
|
**Verification gate W2** : `pg_auto_failover` test rouge → vert, `pgbench` 500 connections OK, traces visibles dans Tempo, SLO burn-rate alerts définies + runbooks indexés.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Semaine 3 — Stockage HA + features signature
|
|||
|
|
|
|||
|
|
**Objectif** : MinIO erasure-coded, CDN edge wired, embed widget + DMCA workflow + track sharing.
|
|||
|
|
|
|||
|
|
#### Jour 11 — Lundi : Redis Sentinel HA + cache metrics
|
|||
|
|
- Rôle Ansible `redis_sentinel` : 3 conteneurs Incus (1 master + 2 replicas + 3 sentinels colocated)
|
|||
|
|
- Backend-api : `RedisClient` switch vers `NewFailoverClient` avec MasterName + SentinelAddrs
|
|||
|
|
- Cache hit rate metrics : ajouter compteurs Prometheus dans rate limiter, chat pubsub, presence
|
|||
|
|
- Test : kill Redis master, vérifier promotion automatique d'un replica en < 30s
|
|||
|
|
- **Acceptance** : failover Redis test rouge → vert, dashboard Grafana avec hit rate par service
|
|||
|
|
- **Files** : `infra/ansible/roles/redis_sentinel/`, `veza-backend-api/internal/config/config.go` (Sentinel config), `veza-backend-api/internal/metrics/cache_hit_rate.go` (nouveau)
|
|||
|
|
|
|||
|
|
#### Jour 12 — Mardi : MinIO distribué + migration
|
|||
|
|
- Rôle Ansible `minio_distributed` : 4 conteneurs Incus en pool EC4+2 (résiste perte 2 conteneurs sans data loss)
|
|||
|
|
- Configuration : bucket `veza-prod-tracks`, lifecycle policy (versioning 30j, Glacier après 90j)
|
|||
|
|
- Migration depuis le single-node actuel via `mc mirror veza-current/ veza-distributed/`
|
|||
|
|
- Backend-api : pas de changement code (interface S3 reste identique)
|
|||
|
|
- Smoke test : upload 100MB via `mc cp`, kill 2 nœuds, vérifier read OK, restart nœuds, vérifier rebuild
|
|||
|
|
- **Acceptance** : EC4+2 résiste à 2 nœud kills, dashboard MinIO healthcheck vert
|
|||
|
|
- **Files** : `infra/ansible/roles/minio_distributed/{tasks,templates}/`
|
|||
|
|
|
|||
|
|
#### Jour 13 — Mercredi : CDN edge externe (Cloudflare R2 ou Bunny.net)
|
|||
|
|
- Choisir : Cloudflare R2 (gratuit 10GB, $0.015/GB stockage, $0/GB egress) OU Bunny.net Stream ($0.005/GB egress audio)
|
|||
|
|
- Configurer compte + bucket + cache rules + signed URL
|
|||
|
|
- Câbler `internal/services/cdn_service.go` (déjà existant) pour générer URLs CDN au lieu de MinIO direct
|
|||
|
|
- Trackservice `GetStorageURL` : retourner CDN signed URL pour les routes publiques (stream, download)
|
|||
|
|
- Cache headers backend-api : Cache-Control: public, max-age=86400, immutable pour les segments HLS
|
|||
|
|
- Test : upload track, lire via /tracks/:id/stream → assert URL = `cdn.veza.fr/...`
|
|||
|
|
- **Acceptance** : 1 track lue via CDN edge, latence first byte < 200ms depuis 3 PoPs
|
|||
|
|
- **Files** : `veza-backend-api/internal/services/cdn_service.go` (extend), `veza-backend-api/internal/core/track/service.go` (GetStorageURL hook CDN), `infra/ansible/roles/backend_api/templates/.env.j2` (env vars CDN)
|
|||
|
|
|
|||
|
|
#### Jour 14 — Jeudi : DMCA notice handler + workflow
|
|||
|
|
- Migration `987_dmca_notices.sql` : table `dmca_notices` (id, status, claimant_email, claimant_name, claimant_address, work_description, infringing_track_id, sworn_statement_at, status, takedown_at, counter_notice_at, restored_at, audit_log)
|
|||
|
|
- Handler `internal/handlers/dmca_handler.go` :
|
|||
|
|
- `POST /api/v1/dmca/notice` : public, rate-limited (5/IP/h), validate fields, enregistre `pending`
|
|||
|
|
- `GET /api/v1/admin/dmca/notices` : admin-only, queue + pagination
|
|||
|
|
- `POST /api/v1/admin/dmca/notices/:id/takedown` : admin action → set `status=takedown`, set `takedown_at=NOW()`, mark track `is_public=false` + `dmca_blocked=true`
|
|||
|
|
- `POST /api/v1/admin/dmca/notices/:id/dismiss` : admin action → set `status=rejected`
|
|||
|
|
- Page publique frontend `/legal/dmca` avec formulaire + agent désigné info
|
|||
|
|
- Audit log dans `audit_logs` (existing v0.803 SEC2)
|
|||
|
|
- **Acceptance** : E2E `tests/e2e/29-dmca-notice.spec.ts` vert (notice → admin queue → takedown → track plus accessible)
|
|||
|
|
- **Files** : `veza-backend-api/migrations/987_dmca_notices.sql` + rollback, `veza-backend-api/internal/handlers/dmca_handler.go` (nouveau), `veza-backend-api/internal/api/routes_legal.go` (nouveau), `apps/web/src/features/legal/pages/DmcaNoticePage.tsx` (nouveau), `tests/e2e/29-dmca-notice.spec.ts`
|
|||
|
|
|
|||
|
|
#### Jour 15 — Vendredi : Embed widget + oEmbed + track share tokens
|
|||
|
|
- Route backend `GET /embed/track/:id` : retourne page HTML standalone (pas le SPA, page minimaliste avec player + waveform SVG)
|
|||
|
|
- Route backend `GET /oembed?url=<track_url>&format=json` : réponse oEmbed standard (type=rich, html=`<iframe src="...">`)
|
|||
|
|
- Open Graph tags dynamiques sur `/tracks/:id` (SSR mini ou meta runtime)
|
|||
|
|
- Migration `988_track_share_tokens.sql` : table `track_share_tokens` (id, track_id, token UUID, expires_at NULLABLE, created_by_user_id)
|
|||
|
|
- Handler `POST /api/v1/tracks/:id/share-tokens` (création) + `GET /api/v1/tracks/share/:token` (lecture)
|
|||
|
|
- Test : créer share token → fetch via token → assert track lisible même si is_public=false
|
|||
|
|
- **Acceptance** : embed iframe Twitter card preview OK, oEmbed JSON valide, share token E2E vert
|
|||
|
|
- **Files** : `veza-backend-api/internal/handlers/embed_handler.go` (nouveau), `veza-backend-api/internal/handlers/oembed_handler.go` (nouveau), `veza-backend-api/migrations/988_track_share_tokens.sql` + rollback, `apps/web/embed/track.html` (template standalone), `tests/e2e/30-embed-and-share.spec.ts`
|
|||
|
|
|
|||
|
|
**Verification gate W3** : Redis HA failover OK, MinIO EC4+2 résiste 2 kills, 1 track lue via CDN, DMCA notice E2E vert, embed widget Twitter card preview verte, share token fonctionne.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Semaine 4 — PWA mobile + HLS default + faceted search + load test
|
|||
|
|
|
|||
|
|
**Objectif** : expérience mobile aboutie, HLS ABR par défaut, recherche faceted, capacité validée 1k VU.
|
|||
|
|
|
|||
|
|
#### Jour 16 — Lundi : Service worker offline track cache (Workbox)
|
|||
|
|
- Activer service worker en prod (déjà câblé `pwa.ts:48-56`)
|
|||
|
|
- Workbox stratégies :
|
|||
|
|
- Static assets : `StaleWhileRevalidate`
|
|||
|
|
- HLS segments : `CacheFirst` avec max-age 7j, max 50 entries
|
|||
|
|
- API calls : `NetworkFirst` avec timeout 5s
|
|||
|
|
- Cache offline track : intercepter les fetch `/api/v1/tracks/:id/stream` redirigés vers CDN, cacher les segments HLS du track en cours + les 50 derniers favoris
|
|||
|
|
- Background sync API pour les actions hors-ligne (like, comment) qui rejouent au retour réseau
|
|||
|
|
- Test : devtools network offline mode, jouer un track déjà écouté, doit fonctionner
|
|||
|
|
- **Acceptance** : test manuel offline OK, Lighthouse PWA score ≥ 90
|
|||
|
|
- **Files** : `apps/web/src/sw.ts` (extend Workbox config), `apps/web/src/services/offlineQueue.ts` (extend pour background sync)
|
|||
|
|
|
|||
|
|
#### Jour 17 — Mardi : HLS par défaut + lossless tier preview
|
|||
|
|
- Flip `HLS_STREAMING=true` dans `.env.production`
|
|||
|
|
- Smoke test : upload track, vérifier que le transcode HLS s'execute, vérifier ABR sur le frontend (`useHLSPlayer` hook)
|
|||
|
|
- Pre-listen 30s public sur les produits marketplace : extend `marketplace.go:258-298` pour les tracks publics si créateur opt-in
|
|||
|
|
- FLAC tier preview : ajouter une checkbox "FLAC available" sur la page upload pour les Premium subscribers (visible mais reporté post-launch pour la consommation effective)
|
|||
|
|
- **Acceptance** : nouveau track uploadé sert HLS ABR (3 niveaux 128/256/320), Network panel devtools confirme switch ABR sur réseau dégradé
|
|||
|
|
- **Files** : `infra/ansible/roles/backend_api/templates/.env.j2` (HLS_STREAMING=true), `apps/web/src/features/upload/components/UploadForm.tsx` (FLAC checkbox)
|
|||
|
|
|
|||
|
|
#### Jour 18 — Mercredi : Faceted search UI
|
|||
|
|
- Composant `apps/web/src/features/search/components/FacetSidebar.tsx` : sidebar avec filtres genre / BPM range / musical_key / year / type (track/playlist/user)
|
|||
|
|
- Wire avec orval-generated `useGetSearch` hook : passer `params.type[]`, query params custom pour bpm_min/max
|
|||
|
|
- Backend : étendre `search_handlers.go:Search` pour accepter `bpm_min`, `bpm_max`, `musical_key`, `year_from`, `year_to` (déjà partiellement supportés via SearchService)
|
|||
|
|
- Test : recherche "rock" + filtre BPM 120-130 → résultats restreints
|
|||
|
|
- **Acceptance** : E2E `tests/e2e/31-faceted-search.spec.ts` vert
|
|||
|
|
- **Files** : `apps/web/src/features/search/components/FacetSidebar.tsx` (nouveau), `apps/web/src/features/search/pages/search-page/SearchPage.tsx` (intégration), `veza-backend-api/internal/handlers/search_handlers.go` (extend params), `veza-backend-api/internal/services/search_service.go` (extend filter SQL), `tests/e2e/31-faceted-search.spec.ts`
|
|||
|
|
|
|||
|
|
#### Jour 19 — Jeudi : HAProxy sticky WS + 2 backend-api actif/actif
|
|||
|
|
- Rôle Ansible `haproxy` : conteneur HAProxy avec config `frontend tls / backend api_pool` + sticky cookie sur les routes WS
|
|||
|
|
- Backend-api : déployer 2 conteneurs Incus actif/actif derrière HAProxy. Stateless OK (sessions Redis-backed déjà câblé).
|
|||
|
|
- Health check `/api/v1/health` toutes les 5s, drain 30s avant remove
|
|||
|
|
- Test : kill backend-api 1, vérifier HAProxy bascule, vérifier sessions WS reconnectent au backend-api 2 sans perte de message
|
|||
|
|
- Stream-server : 2 conteneurs avec affinité sticky par `track_id` hash (HLS cache local optimisé)
|
|||
|
|
- **Acceptance** : test scripté `infra/ansible/tests/test_backend_failover.sh` vert
|
|||
|
|
- **Files** : `infra/ansible/roles/haproxy/{tasks,templates}/`, `infra/ansible/roles/backend_api/tasks/main.yml` (multi-instance), `infra/ansible/tests/test_backend_failover.sh`
|
|||
|
|
|
|||
|
|
#### Jour 20 — Vendredi : Load test k6 nightly + capacity validation
|
|||
|
|
- Compléter `scripts/loadtest/k6_load_test.js` avec scénarios mix réalistes :
|
|||
|
|
- 100 VU upload concurrent (10MB tracks)
|
|||
|
|
- 500 VU streaming HLS (segments fetch)
|
|||
|
|
- 1000 VU search + browse mixte
|
|||
|
|
- 50 VU checkout marketplace
|
|||
|
|
- Threshold p95 < 500ms global, error rate < 0.5%
|
|||
|
|
- Workflow CI nightly `.github/workflows/loadtest.yml` qui lance k6 sur staging
|
|||
|
|
- Profiling pprof endpoints lents identifiés
|
|||
|
|
- Capacité validée : 1k users concurrents tenus sur 1 R720 sans saturation
|
|||
|
|
- **Acceptance** : nightly load test passe vert pendant 3 nuits consécutives, dashboard Grafana avec p95/p99 par endpoint
|
|||
|
|
- **Files** : `scripts/loadtest/k6_*.js`, `.github/workflows/loadtest.yml` (nouveau), `docs/PERFORMANCE_BASELINE.md` (update avec chiffres réels)
|
|||
|
|
|
|||
|
|
**Verification gate W4** : Lighthouse PWA ≥ 90, HLS ABR par défaut OK, faceted search E2E vert, HAProxy failover OK, k6 nightly 1k VU green 3 nuits.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Semaine 5 — Pentest + game day + canary + status page
|
|||
|
|
|
|||
|
|
**Objectif** : pentest exécuté, game day rejoué et runbooks validés, canary release process automatisé, status page publique.
|
|||
|
|
|
|||
|
|
#### Jour 21 — Lundi : Pré-flight pentest interne (avant le pentest externe)
|
|||
|
|
- Lancer ZAP automated scan sur staging : `docker run -v $(pwd):/zap/wrk owasp/zap2docker-stable zap-baseline.py -t https://staging.veza.fr`
|
|||
|
|
- Lancer nuclei : `nuclei -u https://staging.veza.fr -t cves/ -t vulnerabilities/ -t exposures/`
|
|||
|
|
- Manual audit OWASP Top 10 sur les nouveaux endpoints v1.0.9 :
|
|||
|
|
- `/api/v1/dmca/notice` : XSS via work_description, SSRF via URLs, CSRF
|
|||
|
|
- `/embed/track/:id` : XSS via track metadata
|
|||
|
|
- `/api/v1/config/webrtc` : disclosure (rappel : volontairement public)
|
|||
|
|
- `/api/v1/tracks/share/:token` : enumeration timing
|
|||
|
|
- Fix les findings HIGH internes avant l'externe
|
|||
|
|
- **Acceptance** : 0 finding HIGH dans le rapport ZAP/nuclei, manual audit issues fixées ou justifiées
|
|||
|
|
- **Files** : `docs/SECURITY_PRELAUNCH_AUDIT.md` (nouveau, avec findings + résolutions)
|
|||
|
|
|
|||
|
|
#### Jour 22 — Mardi : Game day #1 — failures simulées
|
|||
|
|
- Scénario A : kill primary Postgres pendant 5min, vérifier failover < 60s + apps reconnectent
|
|||
|
|
- Scénario B : kill HAProxy backend-api 1, vérifier autres backends servent + WS clients reconnect
|
|||
|
|
- Scénario C : kill Redis sentinel master, vérifier promotion replica + chat continue
|
|||
|
|
- Scénario D : saturate disque MinIO 95%, vérifier alertes + degraded write mode
|
|||
|
|
- Scénario E : RabbitMQ down 30min, vérifier event bus log error loud + queue mémoire fallback
|
|||
|
|
- Documenter chaque incident dans `docs/runbooks/game-days/2026-W5-game-day-1.md` : timestamp, action, observation, runbook utilisé, gap découvert
|
|||
|
|
- **Acceptance** : aucun silent fail, aucune 5xx > 30s post-incident, chaque alert Prometheus déclenchée < 1min
|
|||
|
|
- **Files** : `docs/runbooks/game-days/2026-W5-game-day-1.md` (nouveau), `docs/runbooks/<alert-name>.md` (mises à jour selon gaps trouvés)
|
|||
|
|
|
|||
|
|
#### Jour 23 — Mercredi : Canary release process
|
|||
|
|
- Script `scripts/deploy-canary.sh` :
|
|||
|
|
1. Pull nouvelle image backend-api
|
|||
|
|
2. Désactiver backend-api 2 dans HAProxy (drain mode)
|
|||
|
|
3. Déployer nouvelle image sur backend-api 2
|
|||
|
|
4. Health check : `curl https://api.veza.fr/api/v1/health` doit return 200
|
|||
|
|
5. Re-enable backend-api 2 dans HAProxy
|
|||
|
|
6. Monitor pendant 1h : SLI doivent rester verts (p95 < 500ms, err rate < 0.5%)
|
|||
|
|
7. Si SLI vert : repeat sur backend-api 1 (full deploy)
|
|||
|
|
8. Si SLI rouge : rollback automatique (re-déployer ancienne image)
|
|||
|
|
- Pre-deploy hook : check migrations DB sont backward-compatible (nouveau schema doit fonctionner avec ancienne version code)
|
|||
|
|
- Documentation `docs/CANARY_RELEASE.md`
|
|||
|
|
- Test : faire 3 canary deploys sur staging avec rollback simulé
|
|||
|
|
- **Acceptance** : 3 canary deploys réussis (2 normaux + 1 avec rollback simulé volontaire)
|
|||
|
|
- **Files** : `scripts/deploy-canary.sh` (nouveau), `docs/CANARY_RELEASE.md` (nouveau), `Makefile` (target `deploy-canary`)
|
|||
|
|
|
|||
|
|
#### Jour 24 — Jeudi : Status page + synthetic monitoring
|
|||
|
|
- Setup status page : Cachet (self-hosted) sur conteneur Incus OU statuspage.io free tier
|
|||
|
|
- Composants à monitor : API, Stream, Chat, Marketplace, Live, CDN
|
|||
|
|
- Endpoint `GET /api/v1/status` public qui retourne `{status: "operational"|"degraded"|"down", components: {...}}` (utilisé par la status page + supervision)
|
|||
|
|
- Synthetic monitoring : Blackbox exporter Prometheus rejouant 6 parcours toutes les 5min depuis un Incus externe (hors-réseau prod) :
|
|||
|
|
- Register → verify → login
|
|||
|
|
- Login → search "test" → play first result
|
|||
|
|
- Login → upload tiny audio → poll status
|
|||
|
|
- Login → browse marketplace → add to cart
|
|||
|
|
- WebSocket chat connect + send message
|
|||
|
|
- Live stream metadata fetch
|
|||
|
|
- Alert Prometheus si parcours fail 2 fois consécutives
|
|||
|
|
- **Acceptance** : status page accessible sur `status.veza.fr`, synthetic monitoring vert sur 6 parcours pendant 24h
|
|||
|
|
- **Files** : `infra/ansible/roles/cachet/` (si self-hosted), `veza-backend-api/internal/handlers/status_handler.go` (nouveau), `infra/ansible/roles/blackbox_exporter/`, `config/prometheus/blackbox_targets.yml`
|
|||
|
|
|
|||
|
|
#### Jour 25 — Vendredi : Pentest externe kick-off + buffer
|
|||
|
|
- Briefer le pentester (selon EX-2) : scope auth + paiement + DMCA + uploads + WebRTC + embed widget. Donner accès staging dédié avec données pré-seed.
|
|||
|
|
- Le pentest s'exécute en async semaine 5 et début semaine 6.
|
|||
|
|
- Buffer day pour rattraper les retards des jours 21-24 + tester le canary process une fois encore.
|
|||
|
|
- Si tout est en avance : commencer 2.7 (rate limit tiers per-app) en avance sur la semaine 6.
|
|||
|
|
- **Acceptance** : pentester actif, staging accessible, runbooks à jour
|
|||
|
|
- **Files** : `docs/PENTEST_SCOPE_2026.md` (nouveau, brief technique pour le pentester)
|
|||
|
|
|
|||
|
|
**Verification gate W5** : pentest interne 0 HIGH, game day documenté avec 0 silent fail, 3 canary deploys verts, status page publique, synthetic monitoring vert 24h.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Semaine 6 — GO/NO-GO + go-live
|
|||
|
|
|
|||
|
|
**Objectif** : tout le checklist GO/NO-GO vert, soft launch beta privée, public launch.
|
|||
|
|
|
|||
|
|
#### Jour 26 — Lundi : GO/NO-GO checklist final pass
|
|||
|
|
- Réutiliser et faire passer en vert `docs/GO_NO_GO_CHECKLIST_v1.0.0.md` mais cible **v2.0.0-public** :
|
|||
|
|
- **Sécurité** : pentest 0 critique/haut, JWT RS256 prod ✓, secrets hors git ✓
|
|||
|
|
- **Stabilité** : uptime ≥ 99.9% staging 30j (vérifier dashboards), taux 5xx < 0.1%, 0 incident P0 ouvert
|
|||
|
|
- **Performance** : p95 API < 100ms, Lighthouse perf ≥ 85, a11y ≥ 90, PWA ≥ 90
|
|||
|
|
- **Qualité** : coverage ≥ 70%, 0 lint, CI verte 2 sem
|
|||
|
|
- **Éthique** : audit anti-dark-pattern (relire `ORIGIN_UI_UX_SYSTEM.md` §13), 0 ML reco, feed chronologique, algo découverte documenté
|
|||
|
|
- **Business** : flow paiement E2E réel testé (jour 27), KYC vendeur testé E2E, support accessible
|
|||
|
|
- Documenter chaque ligne avec preuve (lien dashboard, commit, test passing)
|
|||
|
|
- Lister les RED items avec plan de remédiation jour 27-28
|
|||
|
|
- **Acceptance** : checklist exhaustive, RED items < 3 et tous remédiables d'ici jour 28
|
|||
|
|
- **Files** : `docs/GO_NO_GO_CHECKLIST_v2.0.0_PUBLIC.md` (nouveau, dérivé du v1.0.0)
|
|||
|
|
|
|||
|
|
#### Jour 27 — Mardi : Test E2E paiement réel + remediation RED items
|
|||
|
|
- AM : Stripe live mode + Hyperswitch live actifs (selon EX-9), faire un vrai achat marketplace (5€ produit test) avec ta propre carte. Vérifier : webhook reçu, license attribuée, vendeur Connect crédité, payout planifié, refund possible.
|
|||
|
|
- PM : remediation RED items du checklist GO/NO-GO. Si > 5 RED items, escalade : décaler le launch d'1 semaine.
|
|||
|
|
- **Acceptance** : 1 achat E2E réel avec vrais fonds, refund testé, RED items 0
|
|||
|
|
- **Files** : `docs/PAYMENT_E2E_LIVE_REPORT.md` (nouveau, traces de la transaction live)
|
|||
|
|
|
|||
|
|
#### Jour 28 — Mercredi : Game day #2 + canary deploy prod
|
|||
|
|
- Game day #2 : rejouer les 5 scénarios du jour 22 sur prod (avec maintenance window 1h annoncée). Cible : tout vert sans intervention manuelle, runbooks validés.
|
|||
|
|
- Canary deploy prod : déployer la version v2.0.0-rc1 sur le R720 prod via le script du jour 23. Soak test 4h, vérifier SLI verts.
|
|||
|
|
- Annonce interne (Discord/Slack équipe) que prod est sur v2.0.0-rc1.
|
|||
|
|
- **Acceptance** : game day prod vert, canary deploy v2.0.0-rc1 vert, soak 4h vert
|
|||
|
|
- **Files** : `docs/runbooks/game-days/2026-W6-game-day-2.md`, `docs/RELEASE_NOTES_V2.0.0_RC1.md`
|
|||
|
|
|
|||
|
|
#### Jour 29 — Jeudi : Soft launch beta privée
|
|||
|
|
- Inviter 50-100 testeurs (mailing list pré-launch, contacts perso, communautés musicales sélectives)
|
|||
|
|
- Email d'invitation avec lien d'inscription + code beta + form Typeform de feedback
|
|||
|
|
- Monitor en temps réel : status page, Grafana dashboards, Sentry frontend errors, support inbox
|
|||
|
|
- Documenter chaque issue rapportée → triage HIGH/MED/LOW
|
|||
|
|
- HIGH issues fixées le jour même, MED le lendemain, LOW backlog post-launch
|
|||
|
|
- **Acceptance** : 50+ testeurs onboardés, < 3 HIGH issues, monitoring vert
|
|||
|
|
- **Files** : `docs/SOFT_LAUNCH_BETA_2026.md` (rapport feedback consolidé)
|
|||
|
|
|
|||
|
|
#### Jour 30 — Vendredi : Public launch
|
|||
|
|
- AM : final pre-launch checklist :
|
|||
|
|
- Status page tout vert
|
|||
|
|
- Game day #2 runbook signed off
|
|||
|
|
- Pentest report reçu, 0 critique/haut ouvert (ou risques accepted documentés)
|
|||
|
|
- Légal signé : ToS, Privacy, DMCA agent enregistré
|
|||
|
|
- Soft launch beta : 0 HIGH issue ouverte
|
|||
|
|
- PM : `git tag v2.0.0` + push, annonce publique (réseaux sociaux, Hacker News, communautés musicales, Product Hunt prep)
|
|||
|
|
- DNS : couper la maintenance page, ouvrir le trafic public
|
|||
|
|
- War room ouvert (Discord/Slack) pour les 48h post-launch
|
|||
|
|
- **Acceptance** : v2.0.0 tagué, publication publique, monitoring actif 24h
|
|||
|
|
- **Files** : `CHANGELOG.md` (entry v2.0.0), `docs/RELEASE_NOTES_V2.0.0.md`, `docs/POST_LAUNCH_RUNBOOK.md`
|
|||
|
|
|
|||
|
|
**Verification gate W6 = LAUNCH** : tag v2.0.0 poussé, trafic public ouvert, monitoring vert 24h, war room actif.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Post-launch immédiat (D+1 à D+7)
|
|||
|
|
|
|||
|
|
| Jour | Action | Owner |
|
|||
|
|
|------|--------|-------|
|
|||
|
|
| D+1 | War room actif, monitor toutes les 30min, daily standup interne | toi |
|
|||
|
|
| D+2 | Premier patch release v2.0.1 si HIGH issues remontées | toi |
|
|||
|
|
| D+3 | Post-mortem du launch : ce qui a bien marché, ce qui a cassé | toi |
|
|||
|
|
| D+5 | Annonce status : "X users, Y tracks, Z transactions, uptime A%" | toi |
|
|||
|
|
| D+7 | Démarrer v2.1 — backlog post-launch (Capacitor mobile, fingerprinting, distribution DSP) | toi |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Risk register
|
|||
|
|
|
|||
|
|
| # | Risque | Proba | Impact | Mitigation | Owner |
|
|||
|
|
|---|--------|-------|--------|------------|-------|
|
|||
|
|
| R-1 | Légal traîne au-delà de semaine 5 | M | HIGH | Démarrer EX-1 jour 1, relancer chaque semaine, ToS template open-source en backup (`commonsclause-style`) | toi |
|
|||
|
|
| R-2 | Pentest finding CRITICAL semaine 6 | M | CRITICAL | Pentest interne semaine 5 jour 21 pour pré-filtrer, budget 3-5j patch reserve semaine 6 | toi |
|
|||
|
|
| R-3 | Postgres failover ne tient pas RTO < 60s | L | HIGH | Tester en lab dès jour 6, fallback : monitor + alert + manual failover documenté (RTO ~5min) | toi |
|
|||
|
|
| R-4 | Item G subscription bug en prod (paiement réel) | L | CRITICAL | E2E `@critical` + manual smoke jour 27 + reconciliation worker (déjà v1.0.7) catch les drifts | toi |
|
|||
|
|
| R-5 | Coturn deploy raté (NAT/UDP forwarding) | M | MED | Tester en sandbox semaine 1-2 (lab Incus), fallback : STUN seul pour launch + advisory UI | toi |
|
|||
|
|
| R-6 | CDN coûts explosent au launch (audio bandwidth) | M | MED | Bunny.net (~5 €/TB) plus prévisible que Cloudflare R2 ($/GB), monitoring bandwidth daily | toi |
|
|||
|
|
| R-7 | Soft launch beta trouve un vrai bug bloquant | H | HIGH | Buffer jour 27 PM + jour 28, max 3 HIGH issues acceptables | toi |
|
|||
|
|
| R-8 | DDoS / abuse au launch | M | MED | Rate limits déjà en place v0.803, Cloudflare proxy en option pour absorption L7 | toi |
|
|||
|
|
| R-9 | Dette technique remonte (CI rouge, flake) | H | LOW | Buffer 20% dans chaque journée, git revert prêt si une feature sabote l'ensemble | toi |
|
|||
|
|
| R-10 | Burnout / décrochage perso | M | CRITICAL | Pas de week-end de "rattrapage", buffer ½ journée par sem, scope-creep refusé | toi |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Defended scope — ce qu'on REFUSE pendant les 6 semaines
|
|||
|
|
|
|||
|
|
Si pendant les 6 semaines tu te poses la question "devrais-je rajouter
|
|||
|
|
X au scope launch", la réponse par défaut est **non, post-launch**.
|
|||
|
|
|
|||
|
|
Liste explicite des refus pré-approuvés :
|
|||
|
|
|
|||
|
|
- **Native mobile (iOS/Android)** — REFUS. Capacitor wrap post-launch, ~3 sem.
|
|||
|
|
- **Audio fingerprinting** — REFUS. DMCA workflow manuel suffit. Chromaprint v1.1.
|
|||
|
|
- **Public API SDK** — REFUS. API key + webhooks v0.803 restent. SDK v1.1.
|
|||
|
|
- **OAuth2 client credentials** — REFUS. v1.1.
|
|||
|
|
- **Multi-region failover** — REFUS. R720 + Hetzner standby suffit. v1.2.
|
|||
|
|
- **Tipping / fan support** — REFUS. Décision business post-launch.
|
|||
|
|
- **Distribution DSP** (TuneCore/CD Baby) — REFUS. v1.1.
|
|||
|
|
- **Subscription per-creator** (Patreon-style) — REFUS. v1.1+.
|
|||
|
|
- **CarPlay / Android Auto** — REFUS. Nécessite app native.
|
|||
|
|
- **Lossless tier FLAC consommation** — REFUS UI complète. Codec exposé en upload form, consommation v1.1.
|
|||
|
|
- **"Fresh from your follows" tab** — REFUS. Filtre chronologique simple suffit.
|
|||
|
|
- **Editorial collections admin UI** — REFUS. Curation manuelle DB suffit.
|
|||
|
|
- **Saved searches** — REFUS. Faceted search UI suffit.
|
|||
|
|
- **PWA push notifications custom** — REFUS extends. Le push existant v0.302 N1 suffit.
|
|||
|
|
- **Light/dark theme switcher avancé** — REFUS. Le `prefers-color-scheme` actuel suffit.
|
|||
|
|
- **Internationalisation full** — REFUS extends. FR + EN au launch (déjà v0.12.7).
|
|||
|
|
- **Accessibility AAA** — REFUS. AA suffit (déjà v0.12.6).
|
|||
|
|
- **GraphQL API** — REFUS jamais (pas dans la stack).
|
|||
|
|
- **Migration vers cloud managed** — REFUS. Self-hosted Incus est le choix.
|
|||
|
|
|
|||
|
|
Si quelqu'un te pousse à ajouter du scope, refer ce document.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Definition of "Production Ready" — critères absolus
|
|||
|
|
|
|||
|
|
Au tag v2.0.0 le **8 juin 2026** (jour 30 = vendredi semaine 6), Veza
|
|||
|
|
DOIT remplir tous les critères suivants :
|
|||
|
|
|
|||
|
|
### Sécurité (5 critères)
|
|||
|
|
- [ ] JWT RS256 prod, clés rotées récemment (< 90j)
|
|||
|
|
- [ ] Secrets hors git (Vault ou sops/age)
|
|||
|
|
- [ ] Pentest externe rapport reçu, 0 finding critique/haut ouvert (HAUT moyens acceptés documentés)
|
|||
|
|
- [ ] Rate limits prod actifs (1000/s global, 100/IP/s)
|
|||
|
|
- [ ] HTTPS partout, HSTS preload submitted, certs auto-renouvellement
|
|||
|
|
|
|||
|
|
### Stabilité (5 critères)
|
|||
|
|
- [ ] Postgres HA failover testé (RTO < 60s) sur staging ET prod
|
|||
|
|
- [ ] Redis Sentinel failover testé
|
|||
|
|
- [ ] Backup restore drill cron passe vert depuis 7j consécutifs
|
|||
|
|
- [ ] Game day #1 + #2 documentés, runbooks signés
|
|||
|
|
- [ ] Canary release process testé 3 fois, rollback automatique vérifié
|
|||
|
|
|
|||
|
|
### Performance (4 critères)
|
|||
|
|
- [ ] p95 API < 500ms sur 1k VU mixed load (k6 nightly green)
|
|||
|
|
- [ ] Lighthouse Performance ≥ 85, Accessibility ≥ 90, PWA ≥ 90
|
|||
|
|
- [ ] CDN edge actif, latence first byte < 200ms depuis 3 PoPs
|
|||
|
|
- [ ] HLS ABR fonctionne (3 niveaux 128/256/320)
|
|||
|
|
|
|||
|
|
### Observabilité (5 critères)
|
|||
|
|
- [ ] Grafana dashboards : API overview, Chat, Commerce, Stream, Live, Ledger health
|
|||
|
|
- [ ] OpenTelemetry collector vivant, traces visibles dans Tempo
|
|||
|
|
- [ ] Loki HA 3 réplicas, logs application centralisés
|
|||
|
|
- [ ] SLO burn-rate alerts définies (3 SLO), runbooks indexés
|
|||
|
|
- [ ] Status page publique sur `status.veza.fr`, synthetic monitoring vert 7j
|
|||
|
|
|
|||
|
|
### Légal (5 critères)
|
|||
|
|
- [ ] Terms of Service publié sur `/legal/terms`, avocat-validé
|
|||
|
|
- [ ] Privacy Policy publié sur `/legal/privacy`, RGPD + CCPA conformes
|
|||
|
|
- [ ] DMCA notice formulaire actif sur `/legal/dmca`, agent enregistré US Copyright Office
|
|||
|
|
- [ ] DSA point de contact UE désigné, transparency report template prêt
|
|||
|
|
- [ ] CGV vendeur marketplace publiées
|
|||
|
|
|
|||
|
|
### Business (4 critères)
|
|||
|
|
- [ ] Stripe Connect live mode actif, KYC créateur testé E2E
|
|||
|
|
- [ ] Hyperswitch live mode actif, paiement E2E vrai fonds testé (5+€)
|
|||
|
|
- [ ] Refund E2E vrai fonds testé
|
|||
|
|
- [ ] Email transactionnel sur domaine custom (SPF/DKIM/DMARC vert)
|
|||
|
|
|
|||
|
|
### Qualité (4 critères)
|
|||
|
|
- [ ] Coverage tests ≥ 70% (Go + Rust + TS)
|
|||
|
|
- [ ] 0 lint error (golangci-lint, ESLint, clippy)
|
|||
|
|
- [ ] CI verte sur main depuis 2 semaines consécutives
|
|||
|
|
- [ ] E2E `@critical` vert sur les 5 derniers nightly
|
|||
|
|
|
|||
|
|
### Éthique (5 critères absolus, non-négociables)
|
|||
|
|
- [ ] Aucun code AI/ML recommandation (grep `tensorflow|pytorch|sklearn` = 0 hit)
|
|||
|
|
- [ ] Aucune métrique popularité publique (likes/plays cachés des vues publiques)
|
|||
|
|
- [ ] Feed chronologique (`ORIGIN_REVISION_SUMMARY.md` rule 7)
|
|||
|
|
- [ ] Algorithme découverte documenté + auditable (`docs/DISCOVERY_ALGORITHM.md`)
|
|||
|
|
- [ ] Audit UX anti-dark-pattern signed off
|
|||
|
|
|
|||
|
|
**Total : 37 critères. Si > 3 sont rouges au matin du jour 30, le launch décale d'1 semaine.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Communication & external comms
|
|||
|
|
|
|||
|
|
### Pré-launch (semaines 1-5)
|
|||
|
|
- Lundi semaine 1 : annonce interne (Discord équipe / proches) "lancement public début juin 2026"
|
|||
|
|
- Semaine 3 : ouvrir un compte X/Mastodon Veza, premiers posts teaser
|
|||
|
|
- Semaine 4 : open la mailing list pré-launch (formulaire `veza.fr`)
|
|||
|
|
- Semaine 5 : envoi soft launch invitations 50-100 testeurs
|
|||
|
|
|
|||
|
|
### Launch jour 30
|
|||
|
|
- Annonce simultanée : Twitter/X, Mastodon, Hacker News (Show HN), Reddit /r/musicians, /r/Wearethemusicmakers, Product Hunt préparé pour J+1
|
|||
|
|
- Email à la mailing list pré-launch
|
|||
|
|
- Communiqué de presse short (3 paragraphes) à musique-tech press (TechCrunch, ResidentAdvisor, Music Ally)
|
|||
|
|
|
|||
|
|
### Post-launch (D+1 à D+30)
|
|||
|
|
- Daily monitoring stats sur le compte X/Mastodon
|
|||
|
|
- Weekly product update blog
|
|||
|
|
- Office hours hebdo Discord (Q&A créateurs)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. Annexes — références rapides
|
|||
|
|
|
|||
|
|
- **État de départ** : `docs/PROJECT_STATE.md`, `docs/FEATURE_STATUS.md`, `FUNCTIONAL_AUDIT.md`
|
|||
|
|
- **Audit complet** : `AUDIT_REPORT.md`, `docs/audit-2026-04/`
|
|||
|
|
- **Plan original 24 semaines** : `/home/senke/.claude/plans/quelles-sont-les-prochaines-playful-beaver.md`
|
|||
|
|
- **Sprint 1 v1.0.9 commit messages** : `/tmp/v1.0.9-commit-messages.md`
|
|||
|
|
- **Configurations infra** : `infra/coturn/`, `infra/ansible/` (à créer semaine 1)
|
|||
|
|
- **Runbooks** : `docs/runbooks/` + `k8s/disaster-recovery/runbooks/`
|
|||
|
|
- **Règles immuables** : `CLAUDE.md` §🚫 + `veza-docs/ORIGIN/`
|
|||
|
|
- **GO/NO-GO précédent (v1.0.0-rc1)** : `docs/GO_NO_GO_CHECKLIST_v1.0.0.md`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. Cadence quotidienne suggérée
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
08:00-08:30 Café + revue plan (ce doc) + vérif notif Forgejo nightly
|
|||
|
|
08:30-09:00 Revue inbox externe (légal/pentest/ops emails)
|
|||
|
|
09:00-12:30 Bloc focus matin — la tâche du jour (~3.5h)
|
|||
|
|
12:30-13:30 Pause déjeuner OBLIGATOIRE
|
|||
|
|
13:30-17:00 Bloc focus après-midi — finir tâche du jour + tests + commit (~3.5h)
|
|||
|
|
17:00-17:30 Update du checklist + push final + setup demain
|
|||
|
|
17:30 Stop. Pas de "juste un dernier truc".
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Si une journée glisse de > 4h, **ne pas** rattraper le soir/week-end —
|
|||
|
|
re-prioriser la suite. Le burnout au jour 20 = launch raté.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
*Document vivant. Mettre à jour le statut des tâches en cochant directement dans ce fichier (`[ ]` → `[x]`). Commit chaque mise à jour avec `docs: roadmap launch — <jour X> done` pour traçabilité.*
|