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.
This commit is contained in:
245
docs/domains/premium/rules/premium.md
Normal file
245
docs/domains/premium/rules/premium.md
Normal file
@@ -0,0 +1,245 @@
|
||||
## 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](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** :
|
||||
|
||||
```sql
|
||||
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
|
||||
Reference in New Issue
Block a user