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:
parent
aa6468e9a0
commit
e449b708f3
17
CLAUDE.md
17
CLAUDE.md
@ -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é.
|
||||
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.
|
||||
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").
|
||||
- **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.
|
||||
- **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.
|
||||
- **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)
|
||||
- Upload drag-and-drop + OCR factures (PDF, PNG, JPG)
|
||||
- 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*)
|
||||
- Éditeur de plan (cadence + templates email avec variables)
|
||||
- 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)
|
||||
- SMS et multi-users : V2 + plans payants seulement
|
||||
- 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
|
||||
|
||||
@ -123,6 +130,7 @@ Voir `/docs/decisions.md` pour le log complet avec rationale.
|
||||
| Hosting | **Proxmox + K3s** (perso) | ADR-014 |
|
||||
| OCR provider | à benchmarker | ADR-020 (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`.
|
||||
|
||||
@ -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/site.webmanifest` | Manifest PWA (theme `#9F1239`, background `#FAF7F2`) |
|
||||
| `/packages/ui/` | Design system partagé (tokens Tailwind v4 + composants TSX) |
|
||||
| `/docs/produit.md` | Spec produit haut niveau (features, IN/OUT V1, pricing) |
|
||||
| `/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/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. 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/decisions.md` | Log de décisions avec rationale (format ADR-light) |
|
||||
| `/docs/wireframes-mvp.html` | Wireframes low-fi des 13 écrans MVP |
|
||||
|
||||
@ -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)
|
||||
|
||||
| # | Sujet | Pourquoi en attente |
|
||||
|
||||
59
docs/flow.md
59
docs/flow.md
@ -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)
|
||||
|
||||
| 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. |
|
||||
| Relancer par SMS | V2 (réservé plan le plus cher). |
|
||||
| Multi-utilisateurs | V2 (plans payants seulement). |
|
||||
| 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. |
|
||||
| É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. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -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
|
||||
- **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
|
||||
|
||||
- **Bibliothèque** : 4 plans pré-fournis par défaut (cf. `apps/api/app/services/default_plans.ts`)
|
||||
|
||||
@ -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/limiter`** — rate limiting sur les routes publiques (login, signup)
|
||||
- **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
|
||||
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
|
||||
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
|
||||
GET /api/v1/invoices/:id
|
||||
PATCH /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/mark-paid
|
||||
|
||||
GET /api/v1/invoice-themes # liste des 4 thèmes (ADR-025)
|
||||
|
||||
GET /api/v1/plans
|
||||
POST /api/v1/plans
|
||||
PATCH /api/v1/plans/:id
|
||||
@ -168,6 +174,9 @@ GET /api/v1/clients
|
||||
POST /api/v1/clients
|
||||
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/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.
|
||||
|
||||
### 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
|
||||
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user