docs(invoices): édition native + ADR-025 + roadmap Factur-X (Phase 5)

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>
This commit is contained in:
ordinarthur 2026-05-14 03:18:11 +02:00
parent aa6468e9a0
commit e449b708f3
5 changed files with 171 additions and 4 deletions

View File

@ -24,7 +24,7 @@ TPE-PME françaises, 5 à 50 salariés, qui émettent 10 à 200 factures par moi
1. **3 clics maximum** pour lancer une relance sur une facture neuve. Idéalement 2 si bien configuré. 1. **3 clics maximum** pour lancer une relance sur une facture neuve. Idéalement 2 si bien configuré.
2. **Mobile et desktop** — la photo de facture depuis le téléphone est un usage clé. 2. **Mobile et desktop** — la photo de facture depuis le téléphone est un usage clé.
3. **Pure-player relance** — on ne fait pas CRM, pas facturation, pas comptabilité. On fait une chose et on la fait bien. 3. **La relance reste l'âme du produit** — c'est notre cœur de promesse. L'**édition native de factures**, ajoutée en V1.1 (cf. ADR-025), est une *extension douce* pour les utilisateurs sans outil de facturation existant. On reste sous-positionnés vs les vrais outils (Pennylane, Sellsy), pas concurrents frontaux. On ne fait toujours pas CRM ni comptabilité.
4. **Respectueux du client final** — le ton monte avec le retard, jamais avant. Pas d'agressivité par défaut. 4. **Respectueux du client final** — le ton monte avec le retard, jamais avant. Pas d'agressivité par défaut.
5. **Le rubis est une vraie devise produit** — 1 rubis = 10 min libérées. La gamification doit être tangible et défendable. 5. **Le rubis est une vraie devise produit** — 1 rubis = 10 min libérées. La gamification doit être tangible et défendable.
@ -57,6 +57,10 @@ Direct, concret, chaleureux, précis, empathique. *On parle comme un bon associ
- **Étape** : un email programmé dans un plan (ex. "J+10 — relance ferme"). - **Étape** : un email programmé dans un plan (ex. "J+10 — relance ferme").
- **Confirmation** *(anciennement « check-in »)* : email envoyé **à l'utilisateur** (pas au client) pour confirmer si une facture a été payée avant l'envoi de la prochaine relance. Remplace l'intégration banking en V1. - **Confirmation** *(anciennement « check-in »)* : email envoyé **à l'utilisateur** (pas au client) pour confirmer si une facture a été payée avant l'envoi de la prochaine relance. Remplace l'intégration banking en V1.
- **Mise en demeure** : étape ferme du plan. **Toujours sous validation manuelle** via modale de confirmation, jamais auto. - **Mise en demeure** : étape ferme du plan. **Toujours sous validation manuelle** via modale de confirmation, jamais auto.
- **Facture native** : facture **créée dans Rubis via l'éditeur** `/factures/nouvelle` (vs. facture importée par OCR/saisie manuelle). PDF généré côté serveur via `@react-pdf/renderer`, snapshots client + émetteur immuables figés à l'émission. Drapeau `invoices.is_native = true`.
- **Numéro de séquence** : compteur strict séquentiel par organisation (`invoices.sequence_number`), alloué à l'émission d'une facture native via verrou row-level. Conforme art. 242 nonies A du CGI (chronologie continue). Le numéro affiché est `<prefix><seq padé>` (ex. `FAC-2026-0042`). Brouillons exclus du compteur.
- **Snapshot** : copie figée des données du client (`client_snapshot`) et de l'émetteur (`issuer_snapshot`) au moment de l'émission d'une facture native. Garantit l'immutabilité légale : la facture reste intacte même si le client change d'adresse ou si l'org modifie ses settings.
- **Factur-X** : format de facturation électronique mixte PDF/A-3 + XML CII embarqué, conforme à la réforme française B2B (obligation d'émission au 1er septembre 2027 pour TPE-PME). Roadmap V1.5 — pas en V1.
- **DSO** : Days Sales Outstanding. Métrique secondaire dans l'app, jamais dans la com publique. - **DSO** : Days Sales Outstanding. Métrique secondaire dans l'app, jamais dans la com publique.
- **LME** : loi de modernisation de l'économie (2008). Plafonne les délais de paiement à 60 jours (ou 45 jours fin de mois). Sanctions DGCCRF jusqu'à 2 M€. - **LME** : loi de modernisation de l'économie (2008). Plafonne les délais de paiement à 60 jours (ou 45 jours fin de mois). Sanctions DGCCRF jusqu'à 2 M€.
@ -68,6 +72,7 @@ Direct, concret, chaleureux, précis, empathique. *On parle comme un bon associ
- Onboarding 3 étapes (compte, entreprise, signature email) - Onboarding 3 étapes (compte, entreprise, signature email)
- Upload drag-and-drop + OCR factures (PDF, PNG, JPG) - Upload drag-and-drop + OCR factures (PDF, PNG, JPG)
- Saisie manuelle (fallback) - Saisie manuelle (fallback)
- **Édition native de factures** (V1.1) — éditeur `/factures/nouvelle` avec lignes structurées, 4 thèmes pré-faits (Classique, Moderne, Minimal, Élégant), couleur d'accent paramétrable, génération PDF côté serveur via `@react-pdf/renderer`. Settings de facturation sur `/parametres/facturation` (identité émetteur, RIB, mentions légales, numérotation strict séquentielle). PDF classique en V1, **Factur-X visé en V1.5** (Q3-Q4 2026), avant l'échéance d'émission TPE-PME au 1er sept 2027. Détails dans `/docs/produit.md` et ADR-025.
- Bibliothèque de plans (4 plans fournis par défaut : *Standard B2B*, *Rapide*, *Patient*, *Ferme*) - Bibliothèque de plans (4 plans fournis par défaut : *Standard B2B*, *Rapide*, *Patient*, *Ferme*)
- Éditeur de plan (cadence + templates email avec variables) - Éditeur de plan (cadence + templates email avec variables)
- Confirmation par email à l'utilisateur (cadence configurable) → confirme si payé → relance ou stop. *Anciennement « check-in ».* - Confirmation par email à l'utilisateur (cadence configurable) → confirme si payé → relance ou stop. *Anciennement « check-in ».*
@ -110,6 +115,8 @@ Voir `/docs/decisions.md` pour le log complet avec rationale.
- Mise en demeure : validation manuelle obligatoire (modale) - Mise en demeure : validation manuelle obligatoire (modale)
- SMS et multi-users : V2 + plans payants seulement - SMS et multi-users : V2 + plans payants seulement
- Banking intégration : pas en V1, remplacée par check-in emails - Banking intégration : pas en V1, remplacée par check-in emails
- **Édition native de factures** : extension douce (V1.1), pas pivot vers facturation complète. Conformité Factur-X visée en V1.5, PDP partenaire évaluée en V2 si demandes clients (cf. ADR-025).
- **Numérotation strict séquentielle** : compteur par org alloué en transaction (verrou row-level), brouillons exclus du compteur — choix vs flexible motivé par art. 242 nonies A du CGI.
## Stack technique ## Stack technique
@ -123,6 +130,7 @@ Voir `/docs/decisions.md` pour le log complet avec rationale.
| Hosting | **Proxmox + K3s** (perso) | ADR-014 | | Hosting | **Proxmox + K3s** (perso) | ADR-014 |
| OCR provider | à benchmarker | ADR-020 (en attente) | | OCR provider | à benchmarker | ADR-020 (en attente) |
| Email outbound | à benchmarker | ADR-021 (en attente) | | Email outbound | à benchmarker | ADR-021 (en attente) |
| **Génération PDF (factures natives)** | **`@react-pdf/renderer`** côté API (Node), 4 templates dans `apps/api/app/pdf-templates/` | ADR-025 |
**Architecture** : monorepo Turborepo (`apps/api` AdonisJS, `apps/web` React SaaS, `apps/landing` Astro public, `packages/shared` types/schemas, `packages/ui` design system). API REST Bearer-auth, deux frontends qui consomment `@rubis/ui` pour un brand visuel unifié, PG et MinIO existants sur LXC Proxmox. Détails dans `/docs/tech/architecture.md`. **Architecture** : monorepo Turborepo (`apps/api` AdonisJS, `apps/web` React SaaS, `apps/landing` Astro public, `packages/shared` types/schemas, `packages/ui` design system). API REST Bearer-auth, deux frontends qui consomment `@rubis/ui` pour un brand visuel unifié, PG et MinIO existants sur LXC Proxmox. Détails dans `/docs/tech/architecture.md`.
@ -141,8 +149,11 @@ Voir `/docs/decisions.md` pour le log complet avec rationale.
| `/apps/landing/public/favicon.{svg,ico,png}` | Set complet de favicons + apple-touch-icon | | `/apps/landing/public/favicon.{svg,ico,png}` | Set complet de favicons + apple-touch-icon |
| `/apps/landing/public/site.webmanifest` | Manifest PWA (theme `#9F1239`, background `#FAF7F2`) | | `/apps/landing/public/site.webmanifest` | Manifest PWA (theme `#9F1239`, background `#FAF7F2`) |
| `/packages/ui/` | Design system partagé (tokens Tailwind v4 + composants TSX) | | `/packages/ui/` | Design system partagé (tokens Tailwind v4 + composants TSX) |
| `/docs/produit.md` | Spec produit haut niveau (features, IN/OUT V1, pricing) | | `/docs/produit.md` | Spec produit haut niveau (features, IN/OUT V1, pricing). Inclut la section "Édition native des factures". |
| `/docs/flow.md` | **Comportement produit deep-dive** : cycle de vie d'une facture, statuts + transitions, surfaces UI, mécanique de confirmation (check-in), mode démo, edge cases | | `/docs/flow.md` | **Comportement produit deep-dive** : cycle de vie d'une facture, statuts + transitions, surfaces UI, mécanique de confirmation (check-in), mode démo, edge cases. Flow native = lignes structurées + snapshots immuables. |
| `/apps/api/app/pdf-templates/` | 4 templates `@react-pdf/renderer` (Classique, Moderne, Minimal, Élégant) + dispatcher. Génération PDF native côté serveur. |
| `/apps/web/src/routes/_app/parametres_.facturation.tsx` | Page de paramétrage de l'éditeur de factures (identité émetteur, RIB, mentions, numérotation, thème par défaut). |
| `/apps/web/src/routes/_app/factures_.nouvelle.tsx` | Éditeur split-view : édition à gauche, preview PDF live à droite (debounce 500 ms). |
| `/docs/marque.md` | Référence marque écrite (palette, typo, voix, do/don't) | | `/docs/marque.md` | Référence marque écrite (palette, typo, voix, do/don't) |
| `/docs/decisions.md` | Log de décisions avec rationale (format ADR-light) | | `/docs/decisions.md` | Log de décisions avec rationale (format ADR-light) |
| `/docs/wireframes-mvp.html` | Wireframes low-fi des 13 écrans MVP | | `/docs/wireframes-mvp.html` | Wireframes low-fi des 13 écrans MVP |

View File

@ -362,6 +362,38 @@
--- ---
## ADR-025 · Édition native des factures + roadmap Factur-X
- **Date** : 2026-05-14
- **Statut** : ✅ Validée (V1.1)
- **Contexte** : utilisateurs cibles TPE-PME — beaucoup n'ont pas d'outil de facturation et émettent leurs factures à la main (Word, Excel, parfois rien). Friction à l'adoption de Rubis : "je dois d'abord créer ma facture ailleurs, puis l'uploader ici". Question : Rubis peut-il aussi émettre les factures, ou rester pure-player relance ?
- **Décision** : ajouter une **édition native des factures** en V1.1 (`/factures/nouvelle`) comme **extension douce** au cœur relance, **pas** comme pivot vers un outil de facturation complet. Périmètre V1.1 minimal : factures simples avec lignes, TVA, 4 thèmes pré-faits, numérotation strict séquentielle, snapshots immuables. Pas de devis, pas d'avoirs, pas d'acomptes, pas de récurrence (tout V2+).
- **Rationale** :
- **Marché adressable élargi** : on capture les TPE-PME qui n'ont aucun outil de facturation (segment "Excel" ou "Word + papier"). Coûte peu de complexité produit et ne nous met pas en concurrence frontale avec Pennylane/Sellsy (qui font CRM + comptabilité + multi-fonctions).
- **Cohérence avec la promesse** : la relance reste l'âme. La création de facture est un *moyen* pour amener plus vite à la relance ("vous créez, on relance"), pas une feature de premier rang dans la com publique.
- **Snapshots immuables** : une facture émise ne change jamais — c'est une preuve comptable. `client_snapshot` et `issuer_snapshot` figés à l'émission, le PDF stocké sur MinIO. Modifier l'adresse du client ou les settings de l'org n'altère pas les factures déjà émises.
- **Numérotation strict séquentielle** : l'art. 242 nonies A du CGI exige une chronologie continue, sans rupture. Compteur per-org alloué en transaction avec `SELECT FOR UPDATE` sur la ligne `organizations`, brouillons exclus (qui peuvent être supprimés sans créer de gap). Choisi vs flexible parce que la conformité prime sur l'ergonomie de "je veux mettre n'importe quel numéro".
- **Génération PDF côté serveur via `@react-pdf/renderer`** : composants TSX dans `apps/api/app/pdf-templates/`, dispatcher par slug. Léger (pas de Chromium dans K3s, image Docker reste petite), composants React → preview client possible plus tard si nécessaire. Pour V1.1, la preview web passe par `POST /invoices/preview-pdf` → Blob → objectURL → iframe (debounce 500 ms côté éditeur). Single source of truth pour le rendu.
- **4 thèmes pré-faits + accent paramétrable** : couvre 80 % des besoins esthétiques. Plus simple à livrer qu'un éditeur WYSIWYG drag-and-drop, plus différenciant qu'un seul template.
- **Roadmap conformité Factur-X (réforme 2026-2027)** :
- **V1 (maintenant)** : PDF classique avec mentions fr-FR complètes (pénalités L441-10, escompte L441-9, identité émetteur). Suffit jusqu'à l'échéance d'émission TPE-PME au **1er septembre 2027**.
- **V1.5 (Q3-Q4 2026)** : génération **Factur-X natif** (PDF/A-3 + XML CII embarqué). On reste l'émetteur direct, pas besoin de devenir PDP. Compatible avec les PDP des destinataires (réception côté ETI/GE obligatoire 1er sept 2026).
- **V2 (S1 2027)** : intégration **PDP partenaire** pour la transmission via le PPF si demandes clients. Choix du partenaire (Pennylane Connect, Cegid, Tiime…) à benchmarker au moment.
- **Alternatives écartées** :
- **Rester pure-player relance** : laisse de côté un segment significatif (TPE qui facturent dans Excel). On gagne en simplicité mais on perd en TAM.
- **Pivot complet vers facturation** : énorme chantier (devis, avoirs, acomptes, récurrence, multi-TVA, multi-devises, FEC, e-invoicing PDP), concurrence frontale avec des outils établis, dilue la promesse "relance toutes seules".
- **Mode brouillon interne uniquement** (factures non-légales, watermark "Brouillon") : pas de valeur réelle — un utilisateur qui édite chez Rubis veut envoyer la facture au client, pas un brouillon.
- **Éditeur WYSIWYG drag-and-drop** : équivalent d'un Figma simplifié dans le navigateur, plusieurs mois de boulot. Galerie de 4 thèmes pré-faits couvre l'usage avec une fraction du coût.
- **Pas de Factur-X** : ignorer la réforme = laisser nos clients en infraction au 1er sept 2027. Inacceptable.
- **Intégration PDP partenaire en V1** : prématuré (PDP encore peu matures), coûts récurrents partagés, dépendance forte. À reconsidérer si le marché se consolide d'ici 2027.
- **Conséquences** :
- Le `CLAUDE.md` est nuancé : "*La relance reste l'âme du produit*" remplace "*Pure-player relance*". La V1.1 est une extension, pas un pivot.
- Nouvelle stack côté API : `@react-pdf/renderer` ajouté aux dependencies. Image Docker grossit peu (pas de Chromium).
- Nouvelle table jamais : tout passe par enrichissement de `invoices` (jsonb) et `organizations.invoice_settings` (jsonb). Migrations rétro-compatibles (factures OCR existantes restent intactes, `is_native = false`).
- Marketing : positionnement reste "Vos factures relancées toutes seules". L'éditeur natif est un *feature secondaire* dans la landing, pas la tagline.
---
## Décisions à venir (en attente) ## Décisions à venir (en attente)
| # | Sujet | Pourquoi en attente | | # | Sujet | Pourquoi en attente |

View File

@ -498,16 +498,73 @@ En dev local, exposer le webhook via `stripe listen --forward-to localhost:3333/
--- ---
## 11bis. Édition native des factures (V1.1)
> Pour le rationale, voir ADR-025. Ici on documente le flow.
### 11bis.1 Trois sources d'une facture dans Rubis
| Source | Origine | Drapeau DB | PDF | Snapshots |
|---|---|---|---|---|
| **OCR** | Upload drag-and-drop, extraction Mindee/Document AI | `is_native = false` | Fichier source uploadé (`pdf_storage_key`) | aucun |
| **Saisie manuelle** | `ManualInvoiceDialog`, 6 champs | `is_native = false` | `pdf_storage_key = null` (pas de fichier) | aucun |
| **Native (V1.1)** | Éditeur `/factures/nouvelle` | `is_native = true` | Généré côté serveur, stocké MinIO | `client_snapshot` + `issuer_snapshot` figés |
Les statuts (`pending`, `in_relance`, `paid`…) et le cycle de vie (cf. §3) sont **identiques** pour les 3 sources. La distinction est UX / présentation : une facture native peut être ré-éditée (avec re-génération PDF) tant qu'elle n'est pas dans un relance déclenchée ; une OCR ne peut pas.
### 11bis.2 Création (flow utilisateur)
1. `/factures` → clic "Créer une facture" (bouton primaire à côté de "Importer").
2. `/factures/nouvelle` : split-view. À gauche, formulaire ; à droite, iframe PDF live (debounce 500 ms via `POST /api/v1/invoices/preview-pdf`).
3. L'utilisateur saisit : client (combobox autocomplete), dates (émission + délai → échéance calculée), plan de relance (optionnel), thème + accent, lignes (désignation/qté/PU/TVA), notes pied de page.
4. Le serveur recalcule HT/TVA/TTC à chaque preview (jamais confiance au client). Le front affiche aussi un total live en local pour feedback instantané (mêmes règles d'arrondi : `Math.round` par ligne).
5. Deux boutons en footer :
- **Enregistrer en brouillon**`POST /invoices/native` avec `draft: true`. Statut `pending`, `sequence_number = null`, `numero = "BROUILLON-XXXX"`. Pas de check-in programmé.
- **Émettre la facture**`POST /invoices/native` avec `draft: false`. Alloue le prochain numéro de la séquence (`sequence_number = N`, `numero = "<prefix>0042"`) en transaction avec verrou `FOR UPDATE` sur la ligne `organizations`. Programme le check-in si un plan est associé.
### 11bis.3 Génération PDF
- Templates dans `apps/api/app/pdf-templates/` (4 fichiers TSX + `common.tsx` + `index.tsx` dispatcher).
- Pipeline : `renderInvoiceToBuffer(themeSlug, props)``@react-pdf/renderer.renderToBuffer``uploadBuffer(buf, 'invoice-pdf', orgId)``invoices/<orgId>/<uuid>.pdf` sur MinIO.
- Snapshot `client_snapshot` lu en priorité, fallback sur le client live pour la preview (qui n'a pas encore figé les snapshots).
- Lazy regenerate : si `GET /invoices/:id/pdf` reçoit une facture native sans `pdf_storage_key` (génération échouée au store), on retente à la volée et on persiste.
### 11bis.4 Numérotation (point sensible légalement)
- Compteur dans `organizations.invoice_settings.numeroNextSeq` (JSONB).
- Allocation : `SELECT invoice_settings FROM organizations WHERE id = $1 FOR UPDATE` → lit le compteur, increment, écrit `invoice_settings = jsonb_set(...)`. Garantit l'unicité même sous concurrence (deux onglets, deux jobs).
- Brouillons : `numero` éphémère type `BROUILLON-A1B2C3D4`, `sequence_number = null`. Aucun risque de gap si l'utilisateur supprime un brouillon (la séquence n'a pas été allouée).
- Unicité : `UNIQUE (organization_id, numero)` + `UNIQUE (organization_id, sequence_number)` (partial, autorise plusieurs `NULL`).
- Override initial : l'utilisateur peut définir `numeroNextSeq = 42` dans les settings une fois (pour reprendre une séquence existante d'un autre outil). Au-delà, c'est auto-incrémenté.
### 11bis.5 Snapshots (immutabilité)
À l'émission d'une facture native, deux JSONB sont gelés :
- `client_snapshot` : nom, email, contact, SIREN/SIRET, TVA intra, adresse structurée du client tel qu'il était.
- `issuer_snapshot` : identité émetteur tel qu'elle était dans `invoice_settings.issuer`.
Si plus tard le client déménage ou si l'org modifie son SIRET, **les factures déjà émises restent identiques** au PDF stocké. Cf. ADR-025 pour le rationale (preuve comptable).
### 11bis.6 Cas limites
- **Plan limite Free atteint** (5 factures actives) : `POST /invoices/native` renvoie 402 `plan_limit_reached` — même règle que la saisie OCR/manuelle.
- **Lignes vides** : le SPA bloque le submit si une ligne n'a pas de description ou si `unitPriceCents < 0`.
- **Génération PDF échoue post-store** : on log, on continue (la facture est créée), `pdf_storage_key = null`. Le prochain `GET /:id/pdf` regénère lazy.
- **Aperçu live et client inexistant** : le SPA ne POST pas tant qu'on n'a pas de `clientId` (combobox doit avoir sélectionné une fiche).
- **Race condition sur la séquence** : verrou row-level sur `organizations` → sérialise les `storeNative` concurrents pour la même org. Pas de gaps possibles hors brouillons supprimés (et les brouillons ne consomment pas la séquence).
## 12. Ce que Rubis ne fait PAS (rappel) ## 12. Ce que Rubis ne fait PAS (rappel)
| Hors-scope | Pourquoi | | Hors-scope | Pourquoi |
|---|---| |---|---|
| Émettre des factures | On n'est pas un Henrri-bis. On relance ce qui sort d'ailleurs. | | ~~Émettre des factures~~ → édité V1.1 : on émet maintenant des factures natives (cf. §11bis et ADR-025), mais on n'est toujours pas un outil de facturation complet (pas d'avoirs, pas de devis, pas d'acomptes en V1.1). | Extension douce, pas pivot. |
| Devis, avoirs (credit notes), acomptes, facturation récurrente | V2+. La V1.1 reste minimale (factures simples uniquement). |
| Réconciliation banking auto | V2+. V1 = check-in email. | | Réconciliation banking auto | V2+. V1 = check-in email. |
| Relancer par SMS | V2 (réservé plan le plus cher). | | Relancer par SMS | V2 (réservé plan le plus cher). |
| Multi-utilisateurs | V2 (plans payants seulement). | | Multi-utilisateurs | V2 (plans payants seulement). |
| CRM / pipeline commercial | On reste pure-player relance. | | CRM / pipeline commercial | On reste pure-player relance. |
| Recouvrement contentieux | Hors-scope définitif. La mise en demeure est le seuil. Au-delà, c'est huissier. | | Recouvrement contentieux | Hors-scope définitif. La mise en demeure est le seuil. Au-delà, c'est huissier. |
| Émission Factur-X / transmission via PDP (réforme 2026-2027) | V1.5 (Factur-X natif) puis V2 (PDP partenaire si demande client) — cf. ADR-025. |
--- ---

View File

@ -59,6 +59,21 @@ Rubis Sur l'Ongle libère le temps des dirigeants de TPE-PME en automatisant la
- **Liste filtrable** : par statut (toutes, à relancer, en relance, encaissées, litige) via chips - **Liste filtrable** : par statut (toutes, à relancer, en relance, encaissées, litige) via chips
- **Actions en lot** : checkboxes pour relancer manuellement, changer le plan, archiver - **Actions en lot** : checkboxes pour relancer manuellement, changer le plan, archiver
### 4.2bis Édition native des factures (V1.1, extension douce)
> **Cadre** : Rubis reste un *pure-player relance*. L'édition native s'adresse aux utilisateurs sans outil de facturation existant — ce n'est pas un pivot vers une concurrence frontale avec Pennylane/Sellsy. Voir ADR-025 pour le rationale et la roadmap Factur-X.
- **Éditeur split-view** `/factures/nouvelle` : panneau d'édition à gauche, preview PDF en live à droite (debounce 500 ms via `POST /api/v1/invoices/preview-pdf`).
- **Lignes structurées** : désignation, quantité (décimale autorisée pour heures/demi-jours), prix unitaire HT, taux de TVA (`0`, `2.1`, `5.5`, `10`, `20`). Le serveur recalcule HT/TVA/TTC + ventilation par taux ; les totaux côté client utilisent les mêmes règles d'arrondi pour feedback instantané.
- **Numérotation strict séquentielle** : préfixe + compteur incrémental par organisation (ex. `FAC-2026-0042`), alloué en transaction avec verrou row-level pour éviter les doublons sous concurrence. Brouillons exclus du compteur. Conforme art. 242 nonies A du CGI.
- **4 thèmes pré-faits** : *Classique* (sobre, cabinets/professions réglementées), *Moderne* (bandeau coloré, agences/studios), *Minimal* (noir & blanc, indépendants/designers), *Élégant* (Times Roman, boutiques premium). Couleur d'accent paramétrable. Galerie de sélection avec previews CSS miniatures dans `/parametres/facturation`.
- **Snapshots immuables** : à l'émission, le client (`client_snapshot`) et l'émetteur (`issuer_snapshot`) sont copiés dans la facture. Modifier ses settings ou le client n'altère jamais une facture déjà émise (exigence comptable).
- **Page paramètres** `/parametres/facturation` : 5 sections autonomes (chacune son Save) — identité émetteur (SIREN, SIRET, TVA intracom, RCS, capital, NAF, adresse structurée), RIB (IBAN normalisé + BIC + banque), numérotation (préfixe + compteur + padding avec aperçu live), mentions légales (délai par défaut + pénalités L441-10 + escompte L441-9 + texte libre), thème + accent.
- **Plan de relance optionnel** : si associé à l'émission, Rubis programme le check-in puis les relances à l'échéance — mécanique identique à l'OCR.
- **Brouillon** : créer une facture sans consommer le compteur (numéro éphémère `BROUILLON-XXXX`), pour préparer plusieurs factures avant d'émettre.
- **Génération PDF côté serveur** via `@react-pdf/renderer` (4 composants TSX dans `apps/api/app/pdf-templates/`). PDF stocké sur MinIO (`invoices/<orgId>/<uuid>.pdf`) et exposé via `GET /api/v1/invoices/:id/pdf`. Lazy regenerate si la génération initiale a échoué.
- **Roadmap conformité Factur-X** : V1 = PDF classique. **V1.5 (Q3-Q4 2026)** = Factur-X natif (PDF/A-3 + XML CII embarqué). **V2 (S1 2027)** = intégration PDP partenaire si demandes clients, avant l'échéance d'émission TPE-PME au 1er septembre 2027.
### 4.3 Plans de relance ### 4.3 Plans de relance
- **Bibliothèque** : 4 plans pré-fournis par défaut (cf. `apps/api/app/services/default_plans.ts`) - **Bibliothèque** : 4 plans pré-fournis par défaut (cf. `apps/api/app/services/default_plans.ts`)

View File

@ -136,6 +136,7 @@ pnpm build # build api + web pour prod
- **`@adonisjs/queue`** ou **BullMQ** — jobs différés (relances programmées, OCR, check-ins) - **`@adonisjs/queue`** ou **BullMQ** — jobs différés (relances programmées, OCR, check-ins)
- **`@adonisjs/limiter`** — rate limiting sur les routes publiques (login, signup) - **`@adonisjs/limiter`** — rate limiting sur les routes publiques (login, signup)
- **Vine** (validateur natif Adonis 7) ou **Zod** côté API pour validation des payloads - **Vine** (validateur natif Adonis 7) ou **Zod** côté API pour validation des payloads
- **`@react-pdf/renderer`** (ADR-025) — génération des PDF de factures natives côté serveur. 4 templates TSX dans `apps/api/app/pdf-templates/` (`classique.tsx`, `moderne.tsx`, `minimal.tsx`, `elegant.tsx`) + `common.tsx` (formatters fr-FR, palette) + `index.tsx` (dispatcher slug → composant). L'import alias `#pdf-templates/*` est déclaré dans `package.json`.
### Conventions de routes ### Conventions de routes
Toutes les routes API sous `/api/v1/`. Versioning explicite — V2 vivra côté `/api/v2/` sans casser V1. Toutes les routes API sous `/api/v1/`. Versioning explicite — V2 vivra côté `/api/v2/` sans casser V1.
@ -152,13 +153,18 @@ GET /api/v1/organizations/:id
GET /api/v1/invoices GET /api/v1/invoices
POST /api/v1/invoices # create manual POST /api/v1/invoices # create manual
POST /api/v1/invoices/native # editor natif (ADR-025)
POST /api/v1/invoices/preview-pdf # preview PDF stream (debounced)
POST /api/v1/invoices/upload # OCR pipeline POST /api/v1/invoices/upload # OCR pipeline
GET /api/v1/invoices/:id GET /api/v1/invoices/:id
PATCH /api/v1/invoices/:id PATCH /api/v1/invoices/:id
DELETE /api/v1/invoices/:id DELETE /api/v1/invoices/:id
GET /api/v1/invoices/:id/pdf # PDF natif (lazy regenerate si manquant)
POST /api/v1/invoices/:id/relance # relance manuelle POST /api/v1/invoices/:id/relance # relance manuelle
POST /api/v1/invoices/:id/mark-paid POST /api/v1/invoices/:id/mark-paid
GET /api/v1/invoice-themes # liste des 4 thèmes (ADR-025)
GET /api/v1/plans GET /api/v1/plans
POST /api/v1/plans POST /api/v1/plans
PATCH /api/v1/plans/:id PATCH /api/v1/plans/:id
@ -168,6 +174,9 @@ GET /api/v1/clients
POST /api/v1/clients POST /api/v1/clients
PATCH /api/v1/clients/:id PATCH /api/v1/clients/:id
GET /api/v1/organizations/me/invoice-settings # ADR-025
PATCH /api/v1/organizations/me/invoice-settings
GET /api/v1/dashboard/kpis GET /api/v1/dashboard/kpis
GET /api/v1/dashboard/activity GET /api/v1/dashboard/activity
``` ```
@ -439,6 +448,49 @@ SPA: poll ou WebSocket → reçoit l'Invoice prête à valider
**Points d'attention** : le job OCR doit être idempotent (même uploadId rejoué = pas de duplicate). Le SPA peut afficher un spinner pendant les 3-10 secondes d'OCR. **Points d'attention** : le job OCR doit être idempotent (même uploadId rejoué = pas de duplicate). Le SPA peut afficher un spinner pendant les 3-10 secondes d'OCR.
### 6.1bis Édition native d'une facture (V1.1)
Source secondaire pour les utilisateurs sans outil de facturation existant. Voir ADR-025 pour le rationale, `docs/flow.md` §11bis pour le flow produit.
```
SPA (/factures/nouvelle, éditeur split-view)
│ POST /api/v1/invoices/preview-pdf (body JSON, debounce 500 ms)
api: validate, compute totals, render @react-pdf/renderer → Buffer
│ stream application/pdf
SPA: Blob → URL.createObjectURL → iframe src
│ utilisateur clique "Émettre"
│ POST /api/v1/invoices/native (draft: false)
api: tx{ SELECT … FOR UPDATE organizations.invoice_settings
→ allocate next sequence number
→ snapshot client + issuer (figés à l'émission)
→ INSERT invoices (is_native=true, lines, snapshots, theme_slug…)
}
│ post-commit
api: renderInvoiceToBuffer(themeSlug, props) → uploadBuffer → MinIO
│ UPDATE invoices SET pdf_storage_key = '…' WHERE id = …
api: schedule check-in (si plan associé)
SPA: navigate vers /factures/:id
```
**Points d'attention** :
- **Numérotation atomique** : `SELECT FOR UPDATE` sur la ligne `organizations` sérialise les `storeNative` concurrents pour la même org. Pas de gaps possibles (les brouillons ne consomment pas la séquence). Conforme art. 242 nonies A du CGI.
- **Snapshots immuables** : `client_snapshot` et `issuer_snapshot` figés à l'émission. Modifier le client ou les settings post-émission n'altère pas la facture (preuve comptable).
- **Échec de la génération PDF** : la facture est créée en DB malgré tout (log warning). Le PDF est régénéré lazy au prochain `GET /invoices/:id/pdf` (idempotent : on retente puis on persiste la storageKey).
- **Templates partagés** : 4 composants TSX dans `apps/api/app/pdf-templates/` (Classique, Moderne, Minimal, Élégant) + dispatcher `index.tsx`. Tous consomment le même `InvoiceTemplateProps` (cf. `common.tsx`) — ajouter un thème = créer un nouveau composant et mapper le slug dans `THEMES`.
- **Roadmap Factur-X** : le pipeline `renderInvoiceToBuffer` est un point d'extension `Buffer → Buffer`. V1.5 ajoutera l'injection d'un XML CII en pièce jointe PDF/A-3 sans toucher aux templates eux-mêmes.
### 6.2 Programmation des relances ### 6.2 Programmation des relances
``` ```