Files
roadwave/docs/domains/premium/rules/premium.md
jpgiannetti 5e5fcf4714 refactor(docs): réorganiser la documentation selon principes DDD
Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend.

**Structure cible:**
```
docs/domains/
├── README.md (Context Map)
├── _shared/ (Core Domain)
├── recommendation/ (Supporting Subdomain)
├── content/ (Supporting Subdomain)
├── moderation/ (Supporting Subdomain)
├── advertising/ (Generic Subdomain)
├── premium/ (Generic Subdomain)
└── monetization/ (Generic Subdomain)
```

**Changements effectués:**

Phase 1: Création de l'arborescence des 7 bounded contexts
Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/
Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/
Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/
Phase 5: Création des README.md pour chaque domaine
Phase 6: Déplacement des features Gherkin vers domains/*/features/
Phase 7: Création du Context Map (domains/README.md)
Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation
Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh)
Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/)

**Configuration des tests:**
- Makefile: godog run docs/domains/*/features/
- scripts/generate-bdd-docs.py: features_dir → docs/domains

**Avantages:**
 Cohésion forte: toute la doc d'un domaine au même endroit
 Couplage faible: domaines indépendants, dépendances explicites
 Navigabilité améliorée: README par domaine = entrée claire
 Alignement code/docs: miroir de backend/internal/
 Onboarding facilité: exploration domaine par domaine
 Tests BDD intégrés: features au plus près des règles métier

Voir docs/REFACTOR-DDD.md pour le plan complet.
2026-02-07 17:15:02 +01:00

9.3 KiB

10. Premium

10.1 Offre et tarification

Décision : Deux formules sans essai gratuit

Formule Prix Économie Prix effectif
Mensuel 4.99€/mois - 4.99€/mois
Annuel 49.99€/an 2 mois offerts 4.16€/mois

Pas d'essai gratuit

Raisons :

  • Anti-abus vacances : évite inscriptions opportunistes (essai 14j avant road trip vacances, puis annulation)
  • Protection revenus créateurs : les écoutes Premium rémunèrent créateurs dès jour 1
  • Simplicité : pas de gestion période trial + conversion
  • Engagement : utilisateur qui paie dès début = plus engagé

Pas de partage familial (MVP)

Raisons :

  • Complexité technique (gestion invitations, validation liens, limite devices)
  • Risque abus ("familles" de 6 inconnus)
  • Coût dev/support élevé pour ROI incertain
  • La plupart des users RoadWave sont individuels (conducteurs)
  • Post-MVP : Si forte demande, offre "Famille" à 9.99€/mois pour 5 comptes

Justification tarif :

  • Aligné marché bas : Spotify = 10.99€, YouTube Premium = 11.99€, Apple Music = 10.99€
  • Prix accessible : cible conducteurs quotidiens (budget raisonnable)
  • Incitation annuel : 2 mois offerts = engagement long terme + réduction churn

10.2 Multi-devices et détection simultanée

Décision : 1 seul stream actif par compte à tout moment - Priorité au dernier device (KISS)

Règle simple : Le dernier device à démarrer prend toujours la priorité, sans exception temporelle ni géolocalisation.

Comportement multi-devices

Scénario Device 1 Device 2 Résultat Message Device 1
Transition normale Écoute online Démarre 5s après Device 1 coupé, Device 2 actif "Lecture interrompue : compte utilisé sur autre appareil"
Offline connecté internet Écoute offline (avec WiFi) Démarre online Device 1 coupé, Device 2 actif Même message
Offline déconnecté internet Écoute offline (mode avion) Démarre online Device 1 continue, Device 2 actif Pas de détection possible (exception technique)

Implémentation technique détaillée

1. Stream online :

Device 1 écoute online
→ Heartbeat 30s vers serveur
→ Redis : active_streams:{user_id} = {device_id: "iPhone_123", started_at: timestamp}
→ TTL : 5 minutes

Device 2 démarre
→ Détection : active_stream existe
→ Action : Envoi WebSocket close à Device 1
→ Redis : mise à jour active_streams:{user_id} = {device_id: "iPad_456", started_at: timestamp}
→ Device 2 lecture démarre

2. Offline connecté internet :

Device 1 écoute offline MAIS connecté WiFi/4G
→ Heartbeat 30s envoyé quand même
→ Redis : active_streams:{user_id} = {device_id: "iPhone_123", started_at: timestamp, mode: "offline"}
→ Même mécanique que online : Device 2 coupe Device 1

3. Offline déconnecté internet :

Device 1 vraiment offline (mode avion, tunnel)
→ Pas de heartbeat possible
→ Redis : aucune entrée OU expiration TTL après 5 min
→ Device 2 démarre : pas de détection Device 1
→ "Tant pis" (exception technique acceptable)

Message utilisateur (device coupé)

┌────────────────────────────────────────┐
│ ⚠️ Lecture interrompue                 │
├────────────────────────────────────────┤
│ Votre compte est utilisé sur un        │
│ autre appareil.                        │
│                                        │
│ Un seul appareil peut écouter à la     │
│ fois avec votre compte Premium.        │
│                                        │
│ Le partage de compte viole nos CGU     │
│ et peut entraîner une suspension.      │
│                                        │
│ [Reprendre ici] [Sécuriser mon compte] │
└────────────────────────────────────────┘

Boutons :

  • Reprendre ici : Coupe l'autre device, reprend lecture sur ce device
  • Sécuriser mon compte : Lien vers changement mot de passe + déconnexion tous devices

Limite offline 30 jours

Référence : 08-mode-offline.md section 11.2

Contenus téléchargés valides 30 jours
→ Après 30j sans connexion : contenus bloqués
→ Reconnexion WiFi : renouvellement auto si <30j
→ Notification J-3 : "X contenus expirent dans 3 jours"

Cohérence : User offline déconnecté >30j ne peut plus écouter → force reconnexion → détection multi-devices redevient possible.

Détection abus (post-MVP)

Monitoring patterns suspects (backend analytics) :

  • 10 changements devices/jour (suspect)

  • Connexions alternées 2 villes éloignées répétées
  • Signalements users : "je n'ai jamais été à Marseille"

Action : → Email investigation : "Activité suspecte, sécurisez votre compte" → Si confirmé partage : suspension 7j + warning → Récidive : ban définitif

Pas d'action automatique (évite faux positifs), juste flag modération manuelle.

Justification KISS :

  • Simplicité technique : pas de tracking GPS précis, pas de calcul distances, pas de faux positifs (TGV Paris→Lyon = légitime)
  • Assume bonne foi : majorité users honnêtes, partage compte = minorité, gestion réactive suffit
  • Message dissuasif clair : avertissement CGU dans message coupure, possibilité "Sécuriser compte" si suspicion piratage
  • Protection revenus créateurs : 1 abonnement = 1 personne = 1 écoute active
  • UX claire : message explicite, user comprend immédiatement

10.3 Contenus exclusifs Premium

Décision : Créateur décide (déjà couvert section 9.6)

Rappel règles :

  • Toggle "Réservé Premium" par contenu
  • Aucune limite de ratio gratuit/premium
  • Badge 👑 visible
  • Users gratuits : lecture bloquée avec CTA "Passez Premium"

Impact algorithme :

  • Contenus premium inclus dans recommandations
  • Si user gratuit → skip automatique (ne consomme pas slot)
  • Si user premium → diffusé normalement selon score

10.4 Avantages Premium

Inclus dans l'abonnement :

Avantage Gratuit Premium
Publicités 1/5 contenus 0 (aucune)
Contenus exclusifs Bloqués Accès complet
Qualité audio 48 kbps Opus 64 kbps Opus
Mode offline 50 contenus max Illimité
Historique écoute 100 derniers Illimité

Qualité audio :

  • Gratuit : 48 kbps Opus (~20 MB/h) = très correct pour voix
  • Premium : 64 kbps Opus (~30 MB/h) = excellente qualité

Justification différences :

  • 0 pub = argument principal (confort écoute)
  • Qualité audio = avantage tangible audiophiles
  • Offline illimité = use case road trips longs
  • Pas d'over-engineering : pas de badges cosmétiques, fonctionnalités sociales, etc. (focus essentiel)

10.5 Gestion abonnement

Souscription :

Canal Prestataire Prix Commission
Web (desktop/mobile) Mangopay 4.99€ 1.8% + 0.18€ = 0.27€
iOS App Apple In-App Purchase 5.99€ 30% (Apple)
Android App Google Play Billing 5.99€ 30% (Google)

Majoration mobile (5.99€) :

  • Apple/Google prennent 30% de commission
  • RoadWave majore prix de 20% pour compenser
  • Incitation web : Email aux users "Abonnez-vous sur roadwave.com pour 4.99€/mois" (38% moins cher en frais !)

Renouvellement automatique :

  • Email rappel 7 jours avant renouvellement
  • Email confirmation après renouvellement réussi
  • Retry automatique si échec paiement (3 tentatives sur 7 jours)
  • Annulation automatique après 3 échecs

Annulation :

  • Self-service dans Settings app : "Abonnement > Annuler"
  • Accès Premium maintenu jusqu'à fin période payée
  • Pas de remboursement prorata (standard industrie)
  • Email confirmation annulation avec date fin d'accès

Réabonnement :

  • Possibilité immédiate
  • Pas de nouvelle période d'essai (pas d'essai du tout)

Architecture données :

CREATE TABLE subscriptions (
    id UUID PRIMARY KEY,
    user_id UUID NOT NULL REFERENCES users(id) UNIQUE,
    mangopay_recurring_payin_id VARCHAR(255), -- Null si IAP
    mangopay_user_id VARCHAR(255),            -- Null si IAP
    apple_transaction_id VARCHAR(255),        -- Null si Mangopay
    google_purchase_token VARCHAR(255),       -- Null si Mangopay
    status VARCHAR(50) NOT NULL, -- 'active', 'cancelled', 'expired', 'past_due'
    plan VARCHAR(50) NOT NULL, -- 'monthly', 'yearly'
    current_period_start TIMESTAMP NOT NULL,
    current_period_end TIMESTAMP NOT NULL,
    cancelled_at TIMESTAMP,
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Vérification Premium en temps réel :

Cache Redis : premium:{user_id} → boolean (TTL 1h)
Refresh via webhooks :
- Mangopay : PAYIN_NORMAL_SUCCEEDED, PAYIN_NORMAL_FAILED
- Apple : App Store Server Notifications
- Google : Real-time Developer Notifications

Récapitulatif Section 10