Files
office_translator/docs/PRIX-ABONNEMENTS.md
Sepehr Ramezani 26bd096a06 feat: production deployment - full update with providers, admin, glossaries, pricing, tests
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>
2026-04-25 15:01:47 +02:00

7.3 KiB
Raw Permalink Blame History

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 ladmin) 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 denvironnement 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. Ladmin peut mettre à jour ce fichier lors dune sauvegarde.
Valeurs par défaut du code models/subscription.py, dictionnaire PLANS Utilisé si une valeur nexiste 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 doverride.

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

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.8 dans services/pricing_config.py.
  • Interprétation : le total annuel payé dun coup = 80 % de ce que coûteraient 12 mois au tarif mensuel. Cest é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 lannuel et lenregistre dans pricing_overrides.json lors dun 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 :

  1. Lire price_monthly dans data/pricing_overrides.json pour ce plan.
  2. Si absent, utiliser price_monthly dans PLANS (models/subscription.py).
  3. Calculer price_yearly avec 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 :

  1. Dabord : champs stripe_price_id_monthly and stripe_price_id_yearly dans data/pricing_overrides.json pour le plan.
  2. Sinon : variables denvironnement STRIPE_PRICE_<PLAN>_MONTHLY et STRIPE_PRICE_<PLAN>_YEARLY (ex. STRIPE_PRICE_STARTER_MONTHLY), après rechargement du fichier .env en mémoire pour le processus (voir reload_dotenv_from_dotenv_file dans services/pricing_config.py).

Il ny a plus de repli sur les os.getenv figés dans le dictionnaire PLANS au moment de limport du module pour ces identifiants.

4.3 Comportement du checkout Stripe (services/payment_service.py)

  1. 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).
  2. Sinon : création dune ligne avec price_data (montant en centimes) calculé à partir des mêmes règles euros que laffichage (get_subscription_line_amount_eur), sans redémarrage du serveur tant que pricing_overrides.json est à 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 de PLANS.
  • Métadonnées : meta.annual_discount_percent (20) et meta.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_KEY présente dans lenvironnement et commençant par sk_.
  • 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 identifiants price_… sont enregistrés dans .env et dans data/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 .env par ladmin, le code appelle apply_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 lorsquil 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)

  1. Te connecter en admin.
  2. Ouvrir Pricing & Stripe.
  3. Saisir le prix mensuel pour Starter, Pro, Business (lannuel affiché est calculé ; il nest pas saisi librement).
  4. Optionnel : renseigner les Price ID Stripe ou utiliser Créer automatiquement si la clé secrète Stripe est configurée.
  5. 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.