Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.3 KiB
Prix et abonnements — référence exacte
Ce document décrit uniquement le comportement actuel du code (chemins, formules, endpoints). Aucune phrase générique : chaque affirmation correspond à une implémentation précise.
1. Où sont stockés les données tarifaires
| Rôle | Emplacement | Contenu |
|---|---|---|
| Surcharges (prix modifiables par l’admin) | Fichier data/pricing_overrides.json à la racine du dépôt backend (répertoire de travail du processus Python) |
Pour chaque clé starter, pro, business : price_monthly, price_yearly (recalculé par le serveur), stripe_price_id_monthly, stripe_price_id_yearly (optionnel, chaînes vides possibles). |
| Variables d’environnement | Fichier .env à la racine du backend |
Clés STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRET, et STRIPE_PRICE_STARTER_MONTHLY, STRIPE_PRICE_STARTER_YEARLY, idem pour PRO et BUSINESS. L’admin peut mettre à jour ce fichier lors d’une sauvegarde. |
| Valeurs par défaut du code | models/subscription.py, dictionnaire PLANS |
Utilisé si une valeur n’existe pas dans pricing_overrides.json pour le prix mensuel de chaque plan. Les quotas (documents/mois, pages, etc.) et les textes de fonctionnalités viennent toujours de PLANS, pas du JSON d’override. |
2. Qui peut modifier les prix
- Interface admin : page Pricing & Stripe (
frontend/src/app/admin/pricing/page.tsx). - API : uniquement avec un jeton administrateur valide.
- Lecture :
GET /api/v1/admin/pricing - Écriture :
PUT /api/v1/admin/pricing - Création automatique Stripe :
POST /api/v1/admin/pricing/setup-stripe
- Lecture :
Les utilisateurs non admin ne peuvent pas modifier les tarifs. Ils ne voient que la liste publique (voir section 5).
3. Règle de calcul du prix annuel (pas de choix libre)
Le serveur impose une seule règle :
prix_annuel = arrondi(prix_mensuel × 12 × 0,8 ; 2 décimales)
- Constante dans le code :
YEARLY_DISCOUNT_FACTOR = 0.8dansservices/pricing_config.py. - Interprétation : le total annuel payé d’un coup = 80 % de ce que coûteraient 12 mois au tarif mensuel. C’est équivalent à une réduction de 20 % sur ce total « 12 × mensuel ».
- Constante affichée :
ANNUAL_DISCOUNT_PERCENT = 20(même valeur, autre formulation).
Conséquence : tu ne définis pas un annuel arbitraire. Tu définis le mensuel ; le serveur recalcule l’annuel et l’enregistre dans pricing_overrides.json lors d’un PUT. Un champ price_yearly envoyé par un client est ignoré pour la logique métier (le serveur normalise).
Plage autorisée pour le prix mensuel (forfaits payants starter / pro / business) : entre 0,01 € et 50 000 € (validation dans validate_monthly_price_eur).
4. Ordre de résolution pour les prix affichés et le paiement
4.1 Montants en euros (mensuel / annuel)
Pour un plan starter, pro ou business :
- Lire
price_monthlydansdata/pricing_overrides.jsonpour ce plan. - Si absent, utiliser
price_monthlydansPLANS(models/subscription.py). - Calculer
price_yearlyavec la formule de la section 3.
Pour les plans gratuit (free) et entreprise (enterprise), les montants spéciaux (0 ou « sur devis ») viennent de PLANS ; pas de même logique de remise annuelle.
4.2 Identifiants Stripe Price (price_…)
Pour savoir quel Stripe Price utiliser au checkout :
- D’abord : champs
stripe_price_id_monthlyandstripe_price_id_yearlydansdata/pricing_overrides.jsonpour le plan. - Sinon : variables d’environnement
STRIPE_PRICE_<PLAN>_MONTHLYetSTRIPE_PRICE_<PLAN>_YEARLY(ex.STRIPE_PRICE_STARTER_MONTHLY), après rechargement du fichier.enven mémoire pour le processus (voirreload_dotenv_from_dotenv_filedansservices/pricing_config.py).
Il n’y a plus de repli sur les os.getenv figés dans le dictionnaire PLANS au moment de l’import du module pour ces identifiants.
4.3 Comportement du checkout Stripe (services/payment_service.py)
- Si un identifiant
price_…valide est trouvé pour la période mensuelle ou annuelle : la session Checkout utilise ce Stripe Price (montant défini dans Stripe). - Sinon : création d’une ligne avec
price_data(montant en centimes) calculé à partir des mêmes règles euros que l’affichage (get_subscription_line_amount_eur), sans redémarrage du serveur tant quepricing_overrides.jsonest à jour.
5. Ce que voit le site public (sans être admin)
- Endpoint HTTP :
GET /api/v1/auth/plans(sans authentification). - Réponse : liste des plans avec
price_monthly,price_yearly,annual_discount_percent, et les limites (documents, pages, etc.) issues dePLANS. - Métadonnées :
meta.annual_discount_percent(20) etmeta.yearly_discount_factor(0,8).
La page /pricing du frontend charge cet endpoint et remplace les données statiques de secours si la réponse est valide.
6. Packs de crédits (hors admin)
Les prix des packs de crédits (nombre de crédits, prix en euros) sont définis dans models/subscription.py, structure CREDIT_PACKAGES. Ils ne sont pas modifiables via l’écran Pricing & Stripe actuel. Ils apparaissent dans GET /api/v1/auth/plans sous credit_packages.
7. Bouton « Créer automatiquement » (Stripe)
- Endpoint :
POST /api/v1/admin/pricing/setup-stripe. - Condition :
STRIPE_SECRET_KEYprésente dans l’environnement et commençant parsk_. - Effet : le backend crée ou retrouve des produits Stripe et des prix mensuels et annuels en euros dont les montants en centimes sont calculés à partir des mêmes règles euros que ci-dessus (mensuel effectif + annuel =
mensuel × 12 × 0,8). Les identifiantsprice_…sont enregistrés dans.envet dansdata/pricing_overrides.json.
8. Redémarrage du serveur
- Pas requis pour que les montants (JSON) soient pris en compte : le fichier est lu à chaque requête qui appelle
load_pricing_overrides(). - Après modification du
.envpar l’admin, le code appelleapply_runtime_config_after_admin_write()pour recharger les variables dans le processus courant.
En cas de plusieurs processus (plusieurs workers), chaque processus recharge les variables lorsqu’il en a besoin ou après une écriture admin sur le même worker ; le fichier data/pricing_overrides.json est partagé sur le disque.
9. Résumé opérationnel (ce que tu fais concrètement)
- Te connecter en admin.
- Ouvrir Pricing & Stripe.
- Saisir le prix mensuel pour Starter, Pro, Business (l’annuel affiché est calculé ; il n’est pas saisi librement).
- Optionnel : renseigner les Price ID Stripe ou utiliser Créer automatiquement si la clé secrète Stripe est configurée.
- Cliquer sur Sauvegarder la configuration.
Les changements sont persistés dans data/pricing_overrides.json et, le cas échéant, dans .env. Les pages publiques qui consomment GET /api/v1/auth/plans reflètent les nouveaux montants sans redémarrage obligatoire du serveur.