- Gamme officielle : Essentielle (Pro) = deepseek-v4-flash, glm-5.3-flash, minimax-m3 ; Premium (Business) = claude-sonnet-5, deepseek-v4-pro, glm-5.3 - Routage reel : le modele employe suit le palier IA du forfait (reglages admin > defaut du plan), garde anti-croisement de palier - Nouvelle page admin « Modeles & abonnements » (matrice forfaits/paliers, modele par defaut, catalogue OpenRouter) - Statistiques enrichies : revenus (30 j + total), MRR estime, credits, liste d'attente, paliers utilises - Nouvelle page admin « Marketing » : audiences avec compteurs, apercu, envoi test obligatoire, historique, desabonnement public + en-tetes List-Unsubscribe ; .gitignore pour les donnees d'execution - Interface (accueil + tarifs) alignee sur la gamme, 13 langues completes - Tests : routage par palier (fonction + tache), marketing, revenus en base
13 KiB
title, type, created, status, baseline_commit, review_loop_iteration, context
| title | type | created | status | baseline_commit | review_loop_iteration | context |
|---|---|---|---|---|---|---|
| Stratégie LLM par abonnement + admin (modèles, statistiques, emails marketing) | feature | 2026-09-05 | done | 4e6850d6b1 |
0 |
Intent
Problem : Les modèles IA affichés sur la page d'accueil et la page tarifs ne correspondent plus à la gamme réelle (Claude Sonnet 4.6, « Claude Haiku », Gemini) ; aucun modèle n'est réellement routé par abonnement (le modèle employé vient des réglages fournisseur) ; l'admin ne peut ni gérer les modèles par type d'abonnement, ni voir de statistiques de revenus, ni envoyer d'emails de relance marketing.
Approach : (1) Nouvelle gamme officielle — IA Essentielle (plan Pro) : deepseek/deepseek-v4-flash, z-ai/glm-5.3-flash, minimax/minimax-m3 ; IA Premium (plan Business) : anthropic/claude-sonnet-5 (remplace le 4.6, $2/$10 /1M), alternatives deepseek/deepseek-v4-pro et z-ai/glm-5.3. (2) Routage réel : le modèle utilisé par traduction est résolu par le palier IA du plan (réglages admin > défauts des plans). (3) Page admin dédiée « Modèles & abonnements » (matrice plan → palier → modèles actifs + modèle par défaut). (4) Statistiques enrichies : revenus (encaissé, MRR estimé, crédits), conversion, liste d'attente. (5) Page admin « Marketing » : envoi d'emails de relance par audience (liste d'attente, inactifs, par plan) avec aperçu, envoi test, historique et désabonnement — bonnes pratiques type Brevo/Mailchimp.
Boundaries & Constraints
Always : Prix/textes en français correct dans l'interface ; les noms de modèles restent en latin tel quel dans les 13 langues ; ne jamais exposer de clé API dans les réponses admin ; un utilisateur Pro ne doit jamais déclencher un modèle Premium ; SMTP existant (services/email_service.py) réutilisé, pas de nouveau fournisseur.
Ask First : Changer les prix des plans (19 €/49 €) ; créer une table de BDD nouvelle (préférer les fichiers JSON du dossier data/ comme le font waitlist et réglages) ; toucher à la chaîne de secours (FALLBACK_CHAIN).
Never : Modifier le dossier office-translator-landing-page/ (prototype hors production) ni .claude//.agent/ ; supprimer les anciennes clés ai_model_essential/ai_model_premium utilisées ailleurs ; Stripe en mode live ; envoyer un email en masse sans passer par l'envoi test ; citer DeepL comme moteur.
I/O & Edge-Case Matrix
| Scenario | Input / State | Expected Output / Behavior | Error Handling |
|---|---|---|---|
| Traduction Pro, moteur openrouter | plan=pro, réglages admin essential.default=z-ai/glm-5.3-flash |
Job exécuté avec ce modèle, facteur coût 1 | Si vide → défaut du plan (deepseek/deepseek-v4-flash) |
| Traduction Business, premium | plan=business, openrouter_premium | Modèle = premium.default (anthropic/claude-sonnet-5) |
Si clé absente → échec gracieux existant |
| Envoi massif partiel | 200 destinataires, 3 échecs SMTP | Réponse : envoyés/échoués détaillés ; historique journalisé | Continuer après échec individuel, jamais d'HTTP 500 |
| Désabonné | email présent dans data/unsubscribes.json |
Exclu de tout envoi d'audience | N/A |
Code Map
models/subscription.py-- PLANS (l.38-187) : clésai_model_essential/ai_model_premiumà remplacer par listesai_models_essential/ai_models_premium(PRO l.100, BUSINESS l.130-131) ; commentaire d'en-tête l.34-37.routes/translate_routes.py-- résolution modèle l.1277-1280 (openrouter, défautgoogle/gemini-3.5-flash+ remap ancien IDs) et l.1364-1375 (openrouter_premium, défautanthropic/claude-sonnet-4.6) ;_compute_cost_factorl.562 ;_allowed_providers_for_planl.179. C'est ici que le routage par palier s'applique (viaload_settingsdéjà importé l.1269).routes/admin_routes.py--SettingsConfigl.914-928 (ajouter sectionai_tiers) ; GET/PUT/settingsl.956-1054 ;GET /statsl.562 (usage seul, à enrichir) ; catalogue modèles OpenRouterGET /providers/openrouter/modelsexistant (réutiliser pour la combobox admin) ;POST /providers/smtp/test-sendl.1332 (exemple d'envoi).services/email_service.py--send_email_async(to, subject, body)l.94 ;is_smtp_configured()l.53. Réutiliser tel quel.routes/waitlist_routes.py--data/waitlist.json(email, interest, created_at) : audience marketing n°1, motif de fichier JSON à copier (verrou_write_lock) pour historique d'envois et désabonnements.database/models.py--PaymentHistoryl.293 (amount_cents, payment_type, status, created_at) etTranslationl.149 (created_at, provider) : sources des stats de revenus ;repositories.pya les accesseurs.services/pricing_config.py--get_effective_monthly_yearlypour le MRR estimé (prix effectifs, overrides inclus).routes/auth_routes.pyl.763-811 --GET /plans: exposer les listes de modèles (ai_models_essential/premium) au frontend.frontend/src/components/landing/landing-page.tsxl.440-582 -- PricingSection : textes via i18n uniquement.frontend/src/app/pricing/page.tsx--STATIC_PLANSl.62-198 (business.feat3 « Claude Haiku », enterprise.feat2 « Claude Opus 4.6 ») ; section aiModels textée via i18n.frontend/src/lib/i18n/messages/<lang>/{landing,pricing,admin}.json(13 langues : fr,en,de,es,it,pt,nl,ar,fa,ja,ko,ru,zh) -- clés à mettre à jour ; structure identique entre langues.frontend/src/app/admin/--constants.ts(nav, ajouter 2 entrées),settings/page.tsx(motif de page avec combobox modèles),stats/page.tsx+useTranslationStats.ts(motif graphiques),types.ts. Nouvelles pages :models/page.tsx,marketing/page.tsx.tests/-- pytest, motiftest_admin_*.py.
Tasks & Acceptance
Execution :
models/subscription.py-- remplacer les deux clés modèle par les listes de gamme (Essentielle/Premium ci-dessus) -- source de vérité.routes/auth_routes.py-- exposerai_models_essential/ai_models_premiumdansGET /plans-- affichage public.routes/translate_routes.py-- résoudre le modèle par palier : réglages admin (ai_tiers) > défaut du plan ; défauts premium →anthropic/claude-sonnet-5; nettoyer le remap l.1279 -- routage réel par abonnement.routes/admin_routes.py--SettingsConfig.ai_tiers(essential/premium : models[], default_model) avec valeurs par défaut issues de PLANS ; enrichirGET /stats(revenus encaissés 30 j + total via PaymentHistory, MRR estimé par plan, crédits achetés, compteur liste d'attente, répartition paliers IA utilisés) ; nouveaux endpointsGET/POST /marketing/audiences(comptes par audience),POST /marketing/email/send(audience, sujet, html, test_mode ; exclude désabonnés ; historique dansdata/marketing_emails.json),GET /marketing/email/history, et publicGET /api/v1/marketing/unsubscribe-- gestion + stats + relances.services/email_service.py-- ne rien changer sauf si un helper pied-de-page désabonnement s'avère nécessaire.frontend/src/app/admin/models/page.tsx+marketing/page.tsx+constants.ts+types.ts-- deux pages admin (matrice modèles par plan/palier avec défaut radio + combobox du catalogue OpenRouter ; marketing : audience + compteur, sujet/HTML avec aperçu, envoi test, envoi réel, historique) -- l'exigence de Sepehr.frontend/src/app/admin/stats/-- cartes et graphiques des nouvelles métriques (revenus, MRR, liste d'attente) -- visibilité business.frontend/src/app/pricing/page.tsx+components/landing/landing-page.tsx-- textes statiques à jour (Claude 5, gamme) -- cohérence marketing.- i18n
landing.json/pricing.json/admin.json(13 langues) -- clés modifiées/nouvelles traduites ; noms de modèles inchangés -- aucune chaîne manquante. tests/-- tests : routage palier (pro→essential, business→premium, défaut admin), refus modèle premium pour plan pro, endpoint marketing (envoi test, désabonné exclu, historique), stats revenus.
Acceptance Criteria :
- Given un utilisateur Pro, when il traduit avec le moteur openrouter, then le modèle employé est celui du palier Essentielle (jamais un modèle Premium) et la page tarifs affiche la gamme exacte.
- Given l'admin, when il change le modèle par défaut Essentielle puis traduit, then le nouveau modèle est utilisé sans redéploiement.
- Given un désabonné, when un envoi marketing part, then il ne reçoit rien et l'historique trace envoyés/échecs.
- Given
npm run buildetpytest, when exécutés, then succès sans erreur ni chaîne i18n manquante.
Design Notes
Matrice admin (bonne pratique type LiteLLM/OpenRouter) : lignes = plans Pro/Business, colonnes = palier, contenu = modèles actifs (ordre = priorité de secours) + radio « par défaut ». Emails : audience = waitlist | inactive_30 | plan:pro | all_users ; envoi séquentiel 0,2 s d'intervalle dans une tâche de fond ; pied de page avec lien /api/v1/marketing/unsubscribe?email=. Chiffres marketing autorisés : Essentielle « à partir de 0,09 $/M jetons (≈3× moins cher qu'annoncé auparavant) », contexte jusqu'à 1,3 M (GLM-5.3 Flash) ; Premium « Claude 5, 1M de contexte ».
Verification
Commands :
cd frontend && npm run build-- expected: compilation sans erreurcd frontend && npm run test:run-- expected: tests vitest vertspytest -x -q-- expected: nouveaux tests + régression vertsnode -e "…vérif clés i18n identiques fr/en/…"-- expected: aucune clé manquante (script de comparaison)
Manual checks (if no CLI):
- Page d'accueil + /pricing : gamme affichée = deepseek-v4-flash, glm-5.3-flash, minimax-m3 / Claude 5, deepseek-v4-pro, glm-5.3 ; plus aucun « Claude Haiku » ni « Sonnet 4.6 ».
- Admin : pages Modèles et Marketing fonctionnelles ; envoi test reçu.
Spec Change Log
Suggested Review Order
Gamme officielle et exposition publique
-
La source de vérité : les deux gammes officielles (Essentielle Pro / Premium Business) et les défauts.
subscription.py:41 -
L'endpoint public des forfaits expose les listes de modèles aux pages tarifs.
auth_routes.py:786
Routage réel par palier
-
Résolution du modèle : réglages admin > premier de la liste > défaut du plan, avec garde anti-croisement de palier.
translate_routes.py:220 -
Le point d'entrée historique affiche désormais le modèle réellement routé.
legacy_routes.py:91
Côté admin : réglages et protections
-
Bloc
ai_tiers: défauts, normalisation (dédoublonnage, refus de croisement de gamme).admin_routes.py:1055 -
Garde « pristine » : une sauvegarde depuis la page Fournisseurs n'écrase plus les paliers personnalisés.
admin_routes.py:1232
Marketing : audiences, envoi, désabonnement
-
En-têtes de délivrabilité et lien de désabonnement par destinataire.
admin_routes.py:2388 -
Audiences avec compteurs (liste d'attente, inactifs 30 jours, par forfait).
admin_routes.py:2417 -
Envoi : test obligatoire (empreinte), historique « running » avant la boucle, verrou anti-campagne simultanée.
admin_routes.py:2499
Interfaces
-
Page « Modèles & abonnements » : matrice forfaits → paliers, défaut radio, catalogue OpenRouter.
page.tsx:1 -
Page « Marketing » : audience, aperçu, envoi test, historique (textes 100 % i18n).
page.tsx:1 -
Cartes de revenus / MRR / liste d'attente des statistiques.
RevenueOverview.tsx:22 -
Listes de modèles côté client alignées sur la gamme.
store.ts:10
Périphériques
-
En-têtes optionnels du service SMTP existant (aucun changement pour les appels en place).
email_service.py:63 -
Test d'intégration du routage dans la tâche de traduction (faux fournisseur capturant le modèle).
test_worker_tier_routing.py:114 -
Tests marketing (désabonnement en cours de campagne, campagne simultanée, échappement) et revenus en base.
test_admin_marketing.py:1