Implémente le chantier #6 de docs/tech/landing-optimisations.md. Le
funnel signup propose maintenant un essai 14 j Pro avec carte demandée
mais non prélevée — prélèvement automatique à J+14 avec rappel à J+11
(webhook customer.subscription.trial_will_end de Stripe).
Couverture tests : 60 tests unitaires sur la couche billing
- billing.spec.ts (25) — quota Free, bypass trial, inTrial state
- stripe_billing.spec.ts (24) — handlers webhook, idempotence, dispatcher
- trial_recap_job.spec.ts (11) — stats aggregation, formatRubisToHoursFr
+ 3 nouveaux tests vitest côté SPA (useTrialDaysRemaining,
useIsAtFreeLimit bypass trial).
Backend :
- Migration 1779000000000_add_trial_ends_at_to_organizations
- PLAN_CAPS bypass quand status=trialing AND trial_ends_at futur
- getOrgSubscriptionState expose inTrial + trialEndsAt
- Refactor handlers webhook en service stripe_billing.ts (pures,
testables) — extraction depuis le controller. dispatchWebhookEvent
routeur typé également extrait pour les tests.
- createTrialCheckoutSession avec subscription_data.trial_period_days=14,
garde-fou TrialAlreadyConsumedError contre re-trial.
- handleTrialWillEnd → enqueue job recap (BullMQ jobId déterministe
basé sur subscriptionId, idempotent contre re-delivery Stripe).
- Endpoint POST /api/v1/billing/start-trial.
- Email template trial_recap (React Email, branding Rubis figé) avec
stats: factures importées, relances envoyées, € récupérés, rubis +
heures libérées.
Infra de test :
- tests/helpers/stripe_mock.ts : __setStripeForTests injection +
factories fakeSubscription / fakeCheckoutSession / fakeInvoice.
- __setTrialRecapEnqueueForTests : permet de spy l'enqueue sans Redis.
Frontend :
- /onboarding/billing.tsx (opt-in, pas encore forcé dans le flow) :
bouton primaire essai 14j + fallback "Free 2 factures".
- PlanLimitBanner : nouveau état "Essai Pro · X jours restants" qui
prime sur les autres bandeaux. Discret rubis-glow, non blocant.
- useStartTrial hook + useTrialDaysRemaining (arrondi sup).
- SubscriptionState typé avec inTrial + trialEndsAt.
Landing :
- Sous-texte CTA réactivé : « CB demandée, non prélevée avant J+14 »
(Hero + FinalCTA), maintenant promesse véridique.
Notes ouvertes (à décider ultérieurement) :
- Tunnel /onboarding/billing FORCÉ entre signup et /onboarding/compte :
guard reste à activer (risque cassage du signup actuel sinon).
Pour l'instant l'écran est accessible mais opt-in.
- Cron de redondance trial-recap : pas encore implémenté (le
jobId déterministe BullMQ couvre déjà la double-livraison Stripe).
À ajouter si on observe des trial sans recap en prod.
- Tests E2E avec Stripe test mode à faire avant le go-live (cartes
3DS 4000 0027 6000 3184, declined 4000 0000 0000 0341).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documente la feature ajoutée en V1.1 dans toute la doc cadre :
- **CLAUDE.md** : "Pure-player relance" nuancé en "La relance reste
l'âme du produit", extension douce assumée. Périmètre V1/IN
enrichi avec l'éditeur de factures. Glossaire enrichi (facture
native, numéro de séquence, snapshot, Factur-X). Stack : ajout
@react-pdf/renderer + pointeurs vers pdf-templates et les routes
/parametres/facturation et /factures/nouvelle.
- **docs/produit.md** : nouvelle section 4.2bis "Édition native des
factures" — scope V1.1 minimal, snapshots immuables, numérotation
strict séquentielle, roadmap Factur-X V1.5 / PDP V2.
- **docs/flow.md** : nouvelle section 11bis (3 sources d'une facture,
flow utilisateur de création, génération PDF, numérotation,
snapshots, cas limites). Tableau "Ce que Rubis ne fait PAS" mis à
jour (édition oui mais pas devis/avoirs/Factur-X V1).
- **docs/decisions.md** : ADR-025 "Édition native des factures +
roadmap Factur-X" (rationale extension douce, choix techniques
notables, alternatives écartées).
- **docs/tech/architecture.md** : section 6.1bis (flow technique
édition native, points d'attention numérotation atomique + lazy
PDF regenerate), ajout @react-pdf à la stack, routes /native +
/preview-pdf + /invoice-themes + /invoice-settings documentées.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Les commits récents ont introduit le changelog public, le toast SPA, et la
convention de release (bump version.ts + ajout du .md dans le même commit).
Les docs reflètent maintenant ce qui est en prod :
- CLAUDE.md : V1 IN gagne la mention `/changelog` avec le mécanisme MD
versionné + toast SPA. Table "Documents associés" gagne 3 lignes
(`apps/landing/src/content/changelog/`, `apps/web/src/version.ts`,
`.claude/skills/push/`).
- produit.md : nouvelle §4.9 "Changelog public et toast de version" qui
couvre le ton produit-only, le mécanisme du toast, la première visite
silencieuse, le RSS et le SEO.
- tech/architecture.md : ajoute `/changelog` à la table de stratégie de
rendu (SSG), met à jour l'arbre de fichiers `apps/landing/` avec
`content.config.ts` + `content/changelog/` + `pages/changelog/`, et
ajoute une sous-section "Mécanique du changelog (release workflow)"
qui décrit le couplage `version.ts` ↔ `.md`. Côté SPA, ajoute la
sous-section "Versionnage SPA + toast de release" avant la partie auth.
- decisions.md : ADR-022 nouvelle entrée — Changelog en Markdown
versionné (pas en DB) avec rationale (release-coupled, pas d'admin à
maintenir, review en PR, SSG = LCP optimal, schéma Zod).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Trois surfaces partagent désormais le même design system, Tailwind v4
et React 19 — au lieu d'avoir landing en HTML vanilla, app en React, et
blog en Adonis SSR :
* packages/ui — design system partagé (tokens Tailwind v4 + composants
TSX) extrait depuis apps/web : Brand, Gem, Button, Card, Chip, Eyebrow,
EmptyState. apps/web migre 41 imports vers @rubis/ui.
* apps/landing — nouvelle app Astro 6 SSR (rubis.pro), remplace l'ancienne
landing nginx vanilla. Embarque :
- Landing complète portée en sections React (Hero, Stats, Promise,
HowItWorks, Gamification, Legal, Pricing, FAQ, FinalCTA, Footnotes)
- Pages légales (mentions, confidentialité, CGV) via LegalLayout.astro
- Blog SSR (/blog, /blog/:slug) qui consomme /api/v1/posts
- sitemap.xml, blog/rss.xml, robots.txt en endpoints Astro
- SEO complet (canonical, hreflang, OG, Twitter Card, JSON-LD
Article/BreadcrumbList/Blog/SoftwareApplication)
* apps/api — BlogController réduit à 2 endpoints JSON (GET /api/v1/posts
+ GET /api/v1/posts/:slug). Suppression des templates SSR Adonis
(apps/api/app/blog/), de l'alias #blog/*, des deps react-dom et
@types/react-dom. PostTransformer + PostSummaryTransformer ajoutés.
Le service blog_renderer + le seeder + les 3 articles fondateurs
restent intacts (réutilisés par futurs admin + cron IA).
* Infra :
- Dockerfile.landing (multi-stage Node 22 + tini, Astro standalone)
- k3s/app/landing.yml (Deployment + Service rubis-landing:4321 +
ConfigMap avec API_URL=http://rubis-api.rubis.svc.cluster.local:3333)
- .gitea/workflows/deploy.yml mis à jour pour build rubis-landing
- .gitea/workflows/deploy-web.yml + Dockerfile.web : prennent en
compte packages/ui/ comme dépendance
- Suppression du Dockerfile nginx legacy + k3s/{deployment,service}.yml
- Suppression de landing/ (assets favicons migrés vers
apps/landing/public/)
* Docs : architecture.md (vue d'ensemble + §4bis apps/landing complet,
§3 endpoints JSON blog, layout monorepo), CLAUDE.md (stack technique,
documents associés, déploiement).
Note infra : l'ancien Deployment "rubis" (nginx) et son Service ne sont
PAS supprimés par la CI — à nettoyer manuellement après validation que
Traefik a été repointé sur rubis-landing:4321 dans le repo proxmox.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documentation post-migration du setup email :
- /docs/tech/backend.md §12.5 : architecture des 2 flux
(Resend pour le sortant transactionnel via send.rubis.pro,
OVH MX Plan pour l'entrant humain via @ rubis.pro)
- /CLAUDE.md : tableau récap email infra + maj domaine principal
rubis.pro / app.rubis.pro, suppression de la question ouverte
"domaine définitif" (résolue) et "endpoint waitlist" (remplacé
par CTA app)
- /.claude/deploy-memory.md : section migration rubis.pro marquée
✅ avec checklist décommissionnement legacy
- /landing/confidentialite.html : remplace privacy@rubis.pro
par contact@rubis.pro (alignement avec les boîtes OVH créées)
Adresses opérationnelles :
- contact@rubis.pro (général + RGPD)
- dev@rubis.pro (notifs techniques)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bascule du domaine principal vers rubis.pro / app.rubis.pro :
- K3s ConfigMaps (api.yml, web.yml) : APP_URL, WEB_URL,
COOKIE_DOMAIN, OAUTH callbacks pointent vers app.rubis.pro
- Dockerfile.web : ARG VITE_API_URL et VITE_PUBLIC_LANDING_URL
- Workflows Gitea : commentaires + build args web → rubis.pro
- Code API (mail_dispatcher, send_test_email, config/mail) :
defaults env LANDING_URL et MAIL_FROM_ADDRESS migrés
- Templates env (.env.example) idem
- Docs (architecture, backend, frontend, brand-identity) idem
- AGENTS.md / CLAUDE.md / deploy-memory : pointeurs domaine MAJ
Note : MAIL_FROM_ADDRESS dans le secret K3s reste sur
rubis@arthurbarre.fr tant que le domaine rubis.pro n'est pas
Verified dans Resend. À switcher manuellement après vérif Resend.
Compat : un 301 Traefik redirige rubis.arthurbarre.fr → rubis.pro
(et app.X aussi) — config Ansible dans le repo proxmox.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Nouvelle doc orientée comportement produit : explique précisément ce que
fait Rubis du point de vue user-lambda. Pour les arch/tech → architecture.md.
Pour la spec features → produit.md.
Sections :
1. Modèle mental
2. Glossaire (rubis, plan, étape, confirmation, mise en demeure, DSO, LME)
3. Cycle de vie d'une facture (6 statuts + diagramme transitions ASCII +
détails par transition avec effets en cascade)
4. Surfaces UI où l'user agit (modale check-in, email check-in, fiche
facture, slide-over démo) — avec différences mobile/desktop
5. Mécanique de confirmation deep-dive (le coeur du produit)
6. Plans de relance (structure, plans pré-fournis, wizard custom, vars)
7. Mode démo (flag, fork point unique, horloge virtuelle)
8. KPIs & calculs (rubis, encaissé, DSO, pipeline)
9. Edge cases & règles
10. Métriques produit à instrumenter
11. Ce que Rubis ne fait PAS
CLAUDE.md mis à jour pour pointer vers cette doc dans la liste des
documents associés.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convention dure : tous les identifiants applicatifs sont des UUID v4 générés par PG (default gen_random_uuid()), aucun increments/serial même pour les tables techniques.
- CLAUDE.md → "Conventions techniques" : règle énoncée explicitement (anti-énumération, multi-tenant, génération côté client, dumps propres).
- docs/tech/backend.md §4.0 : exemple de migration + raisons.
- 4 migrations existantes réécrites en uuid (users, auth_access_tokens, organizations, alter users.organization_id). Les access tokens d'Adonis acceptent un tokenable_id uuid sans changement côté provider.
- Transformers nettoyés : plus de String(id), les UUID sont déjà des string.
- DB régénérée from scratch (migrations sont éditées avant tout déploiement, pas un cas où un autre dev a une DB en prod).
Monorepo Turborepo (pnpm workspaces) avec 3 packages :
- apps/web : SPA React 19 + Vite 8 + Tailwind v4 (CSS-first)
• TanStack Router (file-based, auto code-splitting), Query, Form
• Radix primitives bruts + CVA + clsx + tailwind-merge
• MSW pour mocker l'API tant qu'Adonis n'est pas branché
• Polices Bricolage Grotesque + Inter self-hostées via fontsource
• Tokens marque (rubis, cream, ink) exposés via @theme
• Primitives maison : Gem, Brand, Eyebrow, Button, Input, Field
• Route /login full flow : TanStack Form + Zod + mutation Query
- apps/api : Adonis 7 (kit api, scaffold via create-adonisjs)
• Auth access tokens (Bearer) — cf. ADR-017
• Tuyau core déjà câblé pour la génération de types
• Routes /api/v1/auth/{signup,login} + /api/v1/account/{profile,logout}
• Minimal — uniquement le pont front ↔ back
- packages/shared : types TS + schemas Zod + constantes
• Source unique de vérité partagée api ↔ web
• Domaines : User, Org, Auth, Client, Invoice, Plan
Tooling racine : Turbo, ESLint v9 flat, Prettier, husky, lint-staged.
CLAUDE.md et docs/decisions.md mis à jour avec ADR-014 à ADR-018
(stack, monorepo, PG existant, Bearer tokens, MinIO existant)
et le pointeur vers docs/tech/architecture.md.
Logo Rubis déplacé de landing/assets/ vers /assets/ (source unique
réutilisée par la landing et l'app).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>