veza/docs/ROADMAP_V1.0_LAUNCH.md
senke 5b2f230544
Some checks failed
Veza CI / Rust (Stream Server) (push) Successful in 4m12s
Security Scan / Secret Scanning (gitleaks) (push) Successful in 41s
E2E Playwright / e2e (full) (push) Failing after 14m25s
Veza CI / Backend (Go) (push) Failing after 14m43s
Veza CI / Frontend (Web) (push) Successful in 26m12s
Veza CI / Notify on failure (push) Successful in 4s
docs(roadmap): add v1.0 → v2.0.0-public launch roadmap (6 weeks)
Living operational document tracking the path from v1.0.8 to public
launch as a SoundCloud-alternative. Compresses the original 24-week
plan to 6 weeks by explicit scope-control:

  - §2 Scope contract: IN/OUT/COMPRESSED matrix (what ships, what
    defers post-launch v1.1+, what's MVP-but-shippable)
  - §1 External actions EX-1 to EX-12 (legal, pentest, DMCA agent,
    DNS, TLS, CDN, OAuth secrets, Stripe live, transactional email,
    status page, coturn) with cycle estimates
  - §4 Day-by-day sprint breakdown for 6 weeks (W1 v1.0.9 + Ansible,
    W2 Postgres HA + obs, W3 storage HA + signature features,
    W4 PWA + HLS + faceted search + load test, W5 pentest + game day
    + canary + status page, W6 GO/NO-GO + soft launch + go-live)
  - §6 Risk register (R-1 to R-10) with mitigations
  - §7 Defended scope (refused additions during the 6 weeks)
  - §8 37 absolute Production-Ready criteria

Daily updates expected: tick acceptance criteria as they land, commit
each update with `docs: roadmap launch — <jour X> done`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 23:50:07 +02:00

44 KiB
Raw Blame History

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é.