ordinarthur
f9cba50b5e
feat(billing,landing): plan Free 2 factures + scaffold preuves sociales/SEO
...
Build & Deploy Landing / build-and-deploy (push) Successful in 1m30s
Build & Deploy API / build-and-deploy (push) Successful in 1m43s
Build & Deploy Web / build-and-deploy (push) Successful in 33s
Suite des chantiers structurants de landing-optimisations.md.
#5 — Plan Free : 5 → 2 factures actives (cf. ADR-023)
- PLAN_CAPS.free.activeInvoicesLimit dans apps/api/app/services/billing.ts
- Tests unitaires alignés (4 → 1, 5 → 2 cap, delta 3 → delta 2)
- billing:scenario command : commentaires + valeur par défaut
- PlanLimitBanner : copy dynamique via {limit} au lieu de "5" hardcodé
- /parametres/abonnement : H1 + tile Free (3 mois → 14 jours, 5 → 2)
- billing.test.tsx (fixtures + cas test)
- landing copy : hero feature pill, Pricing tile, FinalCTA, CGV §5
- CLAUDE.md pricing table
#7 — Scaffold <TrustedBy /> (preuve sociale)
- Composant qui render null tant que copy.trustedBy.{logos,testimonials}
sont vides — pas de placeholder bidon.
- Structure data dans copy.ts avec commentaires sur les prérequis
avant d'ajouter une entrée (accord signé, photo, citation chiffrée).
- Section insérée juste avant <Pricing /> (cf. doc §4).
#8 — Plan articles SEO + brouillon article 1
- docs/marketing/seo-articles.md : 5 articles ciblés, mots-clés,
structure type, lead magnet, calendrier 5 semaines.
- Article 1 ("Modèle d'email de relance facture impayée") en
brouillon complet, prêt à valider via l'admin blog (apps/api).
#6 — Plan détaillé migration Stripe trial 14 j (code reporté)
- docs/tech/stripe-trial-with-card.md : état actuel vs cible,
architecture (Stripe Checkout + trial_period_days), modifs DB
(trial_ends_at), API (start-trial + webhook trial_will_end),
SPA (onboarding/billing), 3 emails transactionnels avec contenu
intégral, risques + mitigations, plan d'exécution 2,5 j.
- Implémentation reportée à une session focus avec accès Stripe
test mode (cartes 3DS, webhook signing secret).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 10:38:52 +02:00
ordinarthur
cb87bbc8d1
feat(billing): expose l'annulation programmée + bouton "Réactiver"
...
Build & Deploy Web / build-and-deploy (push) Successful in 27s
Build & Deploy API / build-and-deploy (push) Successful in 1m14s
Quand l'user annule via le Customer Portal Stripe, la subscription reste
`active` jusqu'à la fin du cycle (cancel_at_period_end=true) — Stripe
n'envoie le `subscription.deleted` qu'à period_end. Avant ce commit, l'UI
affichait toujours "prochaine facture le 28 mai" comme avant l'annulation,
ce qui faisait croire à l'user qu'il allait re-payer.
Backend :
- Migration `cancel_at_period_end boolean DEFAULT false` sur orgs.
- `applySubscriptionToOrg` : lit le flag du Stripe Subscription et
persiste sur l'org.
- `handleSubscriptionDeleted` : reset le flag à false (cohérence DB).
- `OrgSubscriptionState` : nouveau champ `cancelAtPeriodEnd: boolean`.
- Endpoint `POST /api/v1/billing/reactivate` :
• Idempotent (si déjà actif → no-op + 200)
• Appelle `subscriptions.update(id, { cancel_at_period_end: false })`
• Persist le nouvel état sur l'org
Frontend :
- Hook `useReactivateSubscription` (mutation + invalidate billing query).
- `CurrentPlanStrip` :
• Détecte `isCancelling = plan !== 'free' && cancelAtPeriodEnd`
• Switch border/bg en mode rubis-deep + rubis-glow pour attirer l'œil
• Icône Clock à la place de Gem (visuel "compte à rebours")
• Badge "ANNULÉ" en uppercase
• Sous-titre : "Accès Pro jusqu'au DD/MM, puis retour automatique
au plan Free."
• Bouton primary "Réactiver" (RotateCcw icon) qui remplace "Gérer"
• Masque la progress bar Free (non pertinente)
- `SubscriptionState` type étendu avec `cancelAtPeriodEnd`.
- Test factory updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 17:05:02 +02:00
ordinarthur
1952265217
feat(billing): plans Free/Pro/Business + Stripe Checkout & Customer Portal
...
Build & Deploy Web / build-and-deploy (push) Successful in 1m0s
Build & Deploy Landing / build-and-deploy (push) Successful in 31s
Build & Deploy API / build-and-deploy (push) Successful in 1m52s
Pricing V1 :
- Free : 5 factures actives, 1 user, 3 mois de grâce illimité au signup
- Pro : 19 €/mois ou 190 €/an, factures illimitées, 1 user
- Business : 49 €/mois ou 490 €/an, illimité + 5 sièges (V2 multi-users)
+ reply-from-user-email (V2)
Backend :
- Migration : plan, grace_period_ends_at, stripe_customer_id,
stripe_subscription_id, subscription_status, billing_cycle,
current_period_end sur `organizations`. Backfill grace_period auto.
- `app/services/billing.ts` : PLAN_CAPS, countActiveInvoices,
canCreateInvoices (enforce post-grace), getOrgSubscriptionState.
- `app/services/stripe.ts` : client lazy + lookup_keys stables.
- `app/controllers/billing_controller.ts` :
• GET /billing/subscription → state pour l'UI
• POST /billing/checkout → crée une Checkout Session
• POST /billing/portal → Customer Portal Session
• POST /billing/webhook (public) → handle 4 events Stripe
(checkout.completed, subscription.updated/deleted, invoice.payment_failed)
- `commands/stripe_setup.ts` : `node ace stripe:setup` crée Products +
Prices (idempotent via lookup_key).
- Enforcement 402 `plan_limit_reached` sur :
• POST /invoices (saisie manuelle)
• POST /invoices/import-batch/:id/drafts/:draftId/validate (OCR)
Frontend :
- `lib/billing.ts` : useSubscription, useStartCheckout, useOpenPortal,
useIsAtFreeLimit.
- `routes/_app/parametres_.abonnement.tsx` : page comparaison plans
avec toggle mensuel/annuel, current plan + portail Stripe, CTA upgrade
qui redirige vers Checkout hostée.
- `routes/_app/parametres.tsx` : nouvelle section "Abonnement" qui
affiche le plan courant + lien vers la page abonnement.
- `components/billing/PlanLimitBanner.tsx` : banner sur /factures qui
s'adapte selon période (grâce / approche / atteinte).
- Toast dédié 402 sur la validation OCR avec action "Passer Pro".
Doc :
- flow.md : nouvelle section §11 "Pricing & enforcement" qui couvre
plans, grâce, webhook flow, Customer Portal, env vars.
Setup dev :
1. STRIPE_SECRET_KEY (sk_test_...) dans apps/api/.env
2. `stripe listen --forward-to localhost:3333/api/v1/billing/webhook`
→ copier whsec_... → STRIPE_WEBHOOK_SECRET
3. `node ace stripe:setup` une fois pour créer Products+Prices
4. Tester via /parametres/abonnement → checkout en mode test Stripe
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 15:03:28 +02:00