diff --git a/docs/tech/backend.md b/docs/tech/backend.md index 949e1f0..56f29d7 100644 --- a/docs/tech/backend.md +++ b/docs/tech/backend.md @@ -1193,6 +1193,97 @@ CronJob K3s qui run `node ace migration:run --force` avant chaque rollout. Alter --- +## 17-bis. Observability — Sentry (ADR-024) + +Error monitoring API via `@sentry/node`. Init au plus tôt dans +`bin/server.ts` AVANT le boot Ignitor pour capturer même les erreurs +de bootstrap. + +### Configuration + +```ts +// apps/api/start/sentry.ts +// No-op si SENTRY_DSN_API absent → dev local sans bruit Sentry par défaut +``` + +| Aspect | Valeur | Rationale | +|---|---|---| +| Sample rate traces | 10 % prod, 100 % dev | Quota free tier (5K events/mois) | +| Sample rate profiles | 100 % | Sampled par traces de toute façon | +| `release` | `APP_VERSION` runtime (sha git) | Set par `kubectl set env` post-deploy | +| User context | `user.id` UUID seulement | Pas d'email/nom (PII minimisée) | +| `beforeSend` | drop 4xx | Validation, auth invalide = bruit | + +### Capture automatique + +Le `report()` du `HttpExceptionHandler` (`apps/api/app/exceptions/handler.ts`) +capture **uniquement les 5xx** (status >= 500 ou status absent). Tout le +reste — `E_INVALID_CREDENTIALS`, `E_VALIDATION_ERROR`, custom 4xx — +n'arrive **jamais** dans Sentry. + +```ts +// handler.ts:report (extrait) +const isServerError = !status || status >= 500 +if (isServerError) { + Sentry.captureException(error, { + tags: { + // PATTERN de route (/api/v1/checkin/:token/paid), pas l'URL réelle + // → les codes OAuth, tokens checkin, etc. ne fuitent JAMAIS dans + // les tags Sentry indexés. + url: ctx.route?.pattern ?? ctx.request.url(false), + method: ctx.request.method(), + status: status?.toString() ?? '500', + }, + user: ctx.auth?.user + ? { id: String(ctx.auth.user.id) } + : undefined, + }) +} +``` + +### Capturer manuellement (cas métier) + +Dans un service ou job où une exception métier doit être tracée : + +```ts +import * as Sentry from '@sentry/node' + +try { + await mistralOcr.extract(buffer) +} catch (err) { + Sentry.captureException(err, { + tags: { feature: 'ocr', provider: 'mistral' }, + extra: { batchId, fileSize: buffer.length }, + }) + throw err // re-throw pour que le contrôleur fasse son job de réponse +} +``` + +### Tester l'intégration en prod (E2E) + +Endpoint debug `/api/v1/_debug/sentry-test` (gardé par +`NODE_ENV !== 'production'` OU `DEBUG_SENTRY_TEST=true`). Pour activer +temporairement sur la prod et lancer un test : + +```bash +KUBECTL="kubectl --kubeconfig ~/dev/perso/proxmox/k3s/kubeconfig.yaml -n rubis" + +$KUBECTL set env deploy/rubis-api DEBUG_SENTRY_TEST=true +$KUBECTL rollout status deploy/rubis-api --timeout=120s + +curl -i https://app.rubis.pro/api/v1/_debug/sentry-test +# 500 attendu — vérifier Sentry sous 30s + +$KUBECTL set env deploy/rubis-api DEBUG_SENTRY_TEST- +``` + +### Variables d'env requises + +- **K3s secret `rubis-app-secrets`** : `SENTRY_DSN_API` (DSN privé du projet rubis-api) +- **K3s ConfigMap (set par CI)** : `APP_VERSION` = sha git pour le tag release + +--- + ## 18. Pointeurs vers l'existant Avant de coder un endpoint, **toujours consulter** : diff --git a/docs/tech/frontend.md b/docs/tech/frontend.md index a33c49e..e6c6a49 100644 --- a/docs/tech/frontend.md +++ b/docs/tech/frontend.md @@ -738,6 +738,93 @@ Quand tu reconstruis l'app, **rien ne se réinvente sans consulter** : --- +## 12-bis. Observability — Sentry (ADR-024) + +Error monitoring + replay sur le SPA via `@sentry/react`. Init au plus tôt +dans `main.tsx` AVANT tout autre import non-essentiel pour capturer les +erreurs de bootstrap. + +### Configuration + +```ts +// apps/web/src/lib/sentry.ts — init basé sur VITE_SENTRY_DSN_WEB +// (no-op si DSN absent → dev local sans bruit Sentry par défaut) +``` + +| Aspect | Valeur | Rationale | +|---|---|---| +| Sample rate traces | 10 % prod, 100 % dev | Quota free tier (5K events/mois) | +| Sample rate replay session | **0 %** | Pas de replay sans erreur — économie quota | +| Sample rate replay sur erreur | 100 % | Capture les 30 s précédant le crash | +| `maskAllText` / `blockAllMedia` | true | Privacy par défaut, on relâche après | +| `release` | sha git court (CI build-arg) | Une régression ↔ un commit | +| User context | `user.id` UUID seulement | Pas d'email/nom (PII minimisée) | + +### Triggers automatiques (déjà câblés) + +- **Erreurs runtime** : `window.onerror` + `unhandledrejection` interceptés par le SDK. +- **`Sentry.ErrorBoundary`** dans `main.tsx` autour de l'app → capture les erreurs React + affiche ``. +- **User context** : `authStore.setSession` appelle `Sentry.setUser({ id })`, `authStore.clear` reset. + +### Capturer manuellement une erreur métier + +Dans un component / handler : + +```ts +import * as Sentry from "@sentry/react" + +try { + await doSomethingRisky() +} catch (err) { + Sentry.captureException(err, { + tags: { feature: "ocr-import" }, + extra: { batchId }, + }) + toast.error("Quelque chose a coincé.") +} +``` + +### Tester l'intégration en prod + +⚠️ Les `throw` tapés dans la console DevTools **ne hittent PAS** `window.onerror` +(ils restent dans le scope d'eval du devtools). Pour un test valide : + +```js +// Dans la console DevTools +setTimeout(() => { throw new Error("sentry test") }, 0) +// OU +Promise.reject(new Error("sentry test")) +``` + +Les deux méthodes traversent la vraie boucle d'événements de la page → +Sentry intercepte. Vérifier ensuite Sentry Dashboard → projet `rubis-web`. + +Pour vérifier que le SDK est bien init : +```js +typeof __SENTRY__ // doit être "object" (sinon DSN absent au build) +``` + +### Source maps + +`@sentry/vite-plugin` est actif au build CI (gardé par `SENTRY_AUTH_TOKEN`). +Il : +1. Upload les `.map` à Sentry (désobfuscation des stack traces) +2. **Supprime les `.map` du `dist/` final** (`filesToDeleteAfterUpload`) + +→ nginx en prod ne sert pas les sourcemaps publiquement. Sécurité critique. + +### Variables CI (secrets Gitea Actions) + +Cf. `.gitea/workflows/deploy-web.yml`. Les 4 secrets requis : + +- `SENTRY_DSN_WEB` — DSN public projet rubis-web (bake-able dans le bundle) +- `SENTRY_AUTH_TOKEN` — scope `project:releases` + `project:write` (upload sourcemaps) +- `SENTRY_ORG` — slug org Sentry + +Le build est tolérant : si `SENTRY_AUTH_TOKEN` manque, le plugin Vite est skip et les sourcemaps ne sont pas uploadées (Sentry capture quand même mais stack traces minifiées). + +--- + ## 13. Points d'attention - **Auth Bearer en mémoire** : si l'utilisateur reload, l'access token est perdu — toujours appeler `/auth/refresh` au boot avant le render initial (cf. section 7) diff --git a/landing/cgv.html b/landing/cgv.html new file mode 100644 index 0000000..7e00291 --- /dev/null +++ b/landing/cgv.html @@ -0,0 +1,406 @@ + + + + + + + + + + + + + Conditions Générales de Vente · Rubis sur l'ongle + + + + + +
+
+

Conditions contractuelles

+

Conditions Générales de Vente

+

+ Ces conditions encadrent l'utilisation du service Rubis sur l'ongle entre l'éditeur + (Arthur Barré, entrepreneur individuel) et l'utilisateur professionnel (TPE, PME, + freelance, ou personne morale française) qui souscrit à un plan payant ou utilise + la version gratuite. +

+

Dernière mise à jour : 7 mai 2026

+ + + +

1. Définitions

+
    +
  • Éditeur : Arthur Barré, entrepreneur individuel, responsable + de la publication et de l'édition du service Rubis sur l'ongle (cf. + mentions légales).
  • +
  • Utilisateur : toute personne physique ou morale exerçant à + titre professionnel qui crée un compte et utilise le service.
  • +
  • Service : la plateforme SaaS « Rubis sur l'ongle » accessible + depuis app.rubis.pro, permettant d'automatiser + la relance de factures impayées.
  • +
  • Compte : espace utilisateur protégé par un identifiant et un + mot de passe permettant d'accéder au service.
  • +
  • Plan : formule d'abonnement choisie par l'utilisateur (Free, + Pro ou Business) déterminant le périmètre des fonctionnalités et le tarif.
  • +
  • Client final : tiers à qui l'utilisateur facture des + prestations et à qui les emails de relance sont adressés.
  • +
+ +

2. Objet

+

+ Les présentes conditions ont pour objet de définir les modalités contractuelles + applicables à l'utilisation du service Rubis sur l'ongle, qui permet à l'utilisateur + de : +

+
    +
  • Importer des factures (PDF, image, ou saisie manuelle) ;
  • +
  • Configurer des plans de relance avec emails programmés ;
  • +
  • Envoyer automatiquement ces relances à ses clients finaux selon la cadence + choisie ;
  • +
  • Suivre le statut des factures, valider les paiements, gérer les mises en demeure.
  • +
+ +

3. Acceptation des CGV

+

+ L'inscription au service et la création d'un compte impliquent l'acceptation pleine + et entière des présentes CGV par l'utilisateur, ainsi que de la + politique de confidentialité. +

+

+ L'utilisateur déclare agir dans le cadre d'une activité professionnelle. Le service + n'est pas destiné aux consommateurs au sens du Code de la + consommation. +

+ +

4. Création du compte

+

+ L'inscription nécessite la fourniture d'une adresse email valide et d'un mot de + passe (ou d'une connexion via un fournisseur d'identité tiers — Google, Microsoft). + L'utilisateur s'engage à fournir des informations exactes et à les tenir à jour. +

+

+ L'utilisateur est seul responsable de la confidentialité de ses identifiants et de + toutes les actions effectuées depuis son compte. En cas de soupçon de compromission, + il doit immédiatement réinitialiser son mot de passe et nous prévenir à + contact@rubis.pro. +

+ +

5. Description du service

+

+ Le service comprend, selon le plan souscrit, les fonctionnalités suivantes : +

+ + + + + + + + + + + + + + + + + + + + + +
PlanPérimètre principal
Free + Jusqu'à 5 factures actives en relance simultanément. Plans de relance + standards. OCR limité. Un seul utilisateur. +
Pro + Factures et OCR illimités, plans personnalisables, statistiques détaillées, + relances signées au nom de l'utilisateur (sous-domaine Rubis), support + prioritaire. Un seul utilisateur. +
Business + Tout du Pro, plus jusqu'à 5 collaborateurs, envoi des relances depuis le + domaine propre de l'utilisateur (configuration DKIM/SPF), onboarding personnel. +
+

+ La liste détaillée et à jour des fonctionnalités est disponible sur la page + tarifs du site. +

+ +

6. Tarifs, essai et facturation

+ +

6.1 Tarifs

+

+ Les tarifs en vigueur sont indiqués sur la page tarifs du site, en euros et hors + taxes. La TVA, lorsque applicable, est ajoutée selon le taux en vigueur (20 % en + France métropolitaine). +

+ +

6.2 Période d'essai gratuite

+

+ Tout nouvel utilisateur bénéficie d'une période d'essai de 30 jours + permettant l'accès au plan Pro sans engagement et sans carte bancaire requise. + À l'issue de cette période, l'utilisateur peut souscrire à un plan payant ou + poursuivre gratuitement avec le plan Free (5 factures actives). +

+ +

6.3 Modalités de paiement

+

+ Le paiement des plans payants s'effectue en ligne via notre prestataire de + paiement Stripe, par carte bancaire ou prélèvement SEPA. Aucune + donnée bancaire n'est stockée sur les serveurs de l'éditeur. +

+

+ Le règlement est effectué d'avance, par mensualités successives, à la date + anniversaire de la souscription. +

+ +

6.4 Facturation

+

+ Une facture est émise automatiquement à chaque échéance et mise à disposition dans + l'espace utilisateur (rubrique « Paramètres › Facturation »). Elle est également + envoyée par email à l'adresse de contact renseignée. +

+ +

6.5 Défaut de paiement

+

+ En cas de défaut de paiement (rejet bancaire, expiration de la carte, etc.), une + relance automatique est envoyée à l'utilisateur. À défaut de régularisation sous 14 + jours, l'éditeur se réserve le droit de suspendre l'accès aux fonctionnalités + payantes du compte. Les données de l'utilisateur restent conservées pendant cette + période, et l'accès est rétabli dès la régularisation. +

+ +

6.6 Évolution tarifaire

+

+ L'éditeur se réserve le droit de modifier ses tarifs. Toute évolution est notifiée + par email à l'utilisateur au moins 30 jours avant son entrée en + vigueur. L'utilisateur peut alors résilier son abonnement avant l'application du + nouveau tarif sans pénalité. +

+ +

7. Durée et résiliation

+ +

7.1 Durée

+

+ L'abonnement est conclu pour une durée d'un mois et se renouvelle tacitement à + chaque échéance, sauf résiliation par l'une des parties. +

+ +

7.2 Résiliation par l'utilisateur

+

+ L'utilisateur peut résilier son abonnement à tout moment, en un clic, depuis son + espace personnel (« Paramètres › Facturation › Annuler l'abonnement »). La + résiliation prend effet à la fin de la période en cours (déjà payée). Aucun + remboursement prorata temporis n'est dû. +

+

+ La suppression complète du compte (et de toutes les données associées) peut être + demandée par email à contact@rubis.pro ou + via le bouton dédié dans les paramètres. Voir la + politique de confidentialité pour les durées + de conservation post-suppression. +

+ +

7.3 Résiliation par l'éditeur

+

+ L'éditeur peut résilier le compte de l'utilisateur, sans préavis ni indemnité, + dans les cas suivants : +

+
    +
  • Défaut de paiement persistant (au-delà de 30 jours) ;
  • +
  • Violation manifeste des présentes CGV ou de la législation en vigueur ;
  • +
  • Utilisation du service à des fins illicites, frauduleuses, de harcèlement ou + de spam ;
  • +
  • Atteinte à la sécurité ou à l'intégrité du service.
  • +
+ +

8. Disponibilité du service

+

+ L'éditeur met en œuvre les moyens raisonnables pour assurer la disponibilité du + service 24h/24 et 7j/7. Aucun engagement de disponibilité chiffré (SLA) n'est + contractuellement garanti dans cette version. Des interruptions peuvent survenir + pour des opérations de maintenance, des mises à jour, ou des causes indépendantes + de la volonté de l'éditeur. +

+

+ Les opérations de maintenance planifiée sont annoncées à l'avance par email ou + notification dans l'application lorsque possible. +

+ +

9. Obligations de l'utilisateur

+

L'utilisateur s'engage à :

+
    +
  • Utiliser le service conformément à sa destination, à la législation française + et aux usages commerciaux loyaux ;
  • +
  • Respecter le cadre légal applicable aux relances de factures, notamment la + loi LME sur les délais de paiement et les règles de procédure + civile concernant la mise en demeure ;
  • +
  • S'assurer du caractère professionnel et licite de ses relations commerciales + avec ses clients finaux ;
  • +
  • Ne pas utiliser le service pour adresser des communications non sollicitées + (spam) à des destinataires sans relation commerciale préexistante ;
  • +
  • Disposer du droit d'utilisation des données client (email, nom, etc.) qu'il + renseigne dans le service ;
  • +
  • Ne pas tenter de contourner les limitations techniques du service ou + d'extraire massivement des données via des moyens automatisés non documentés.
  • +
+

+ La mise en demeure est traitée par le service comme une étape de + plan particulière nécessitant une validation manuelle de + l'utilisateur avant envoi. L'éditeur ne saurait être tenu responsable du contenu + ou de la qualification juridique de cette mise en demeure. +

+ +

10. Propriété intellectuelle

+

+ La marque « Rubis sur l'ongle », le logo (◆), les textes, le code source, les + chartes graphiques et l'ensemble des éléments composant le service sont la propriété + exclusive de l'éditeur ou de ses partenaires. +

+

+ L'utilisateur conserve l'intégralité de la propriété sur les données qu'il + importe ou crée dans le service (factures, plans de relance, templates + d'emails personnalisés, données clients). L'éditeur ne dispose que d'un droit + d'usage strictement limité à la fourniture du service. +

+ +

11. Données personnelles

+

+ Le traitement des données personnelles par l'éditeur est régi par notre + politique de confidentialité, qui fait partie + intégrante des présentes CGV. +

+

+ Pour les données des clients finaux de l'utilisateur (emails, + noms, etc.), l'éditeur agit en tant que sous-traitant au sens de + l'article 28 du RGPD. Un avenant DPA (Data Processing Agreement) peut être fourni + sur demande à contact@rubis.pro. +

+ +

12. Responsabilité

+

+ L'éditeur fournit un outil d'assistance à l'envoi de relances automatisées. + L'utilisateur reste seul responsable : +

+
    +
  • Du contenu des emails envoyés à ses clients ;
  • +
  • De la légalité et de la qualité de la relation commerciale qui motive la + relance ;
  • +
  • De la qualification juridique éventuelle d'une mise en demeure ;
  • +
  • De l'exactitude des données saisies dans le service.
  • +
+

+ La responsabilité de l'éditeur est strictement limitée aux dommages directs et + prévisibles, liés à un défaut prouvé du service. Les dommages indirects + (notamment : perte de données, perte de chiffre d'affaires, perte de clientèle, + atteinte à l'image) sont exclus dans toute la mesure permise par la loi. +

+

+ En tout état de cause, et conformément aux usages commerciaux entre professionnels, + la responsabilité totale de l'éditeur est plafonnée au montant des sommes + effectivement versées par l'utilisateur au titre des 12 mois précédant le fait + générateur de la responsabilité. +

+ +

13. Force majeure

+

+ L'éditeur ne saurait être tenu responsable d'un manquement à ses obligations en + cas de survenance d'un événement de force majeure au sens de l'article 1218 du + Code civil (catastrophe naturelle, attaque informatique majeure, panne réseau + d'envergure, décision gouvernementale, etc.). +

+ +

14. Modification des CGV

+

+ L'éditeur peut modifier les présentes CGV pour refléter des évolutions du service, + de la législation ou des conditions commerciales. Toute modification substantielle + est notifiée à l'utilisateur par email au moins 30 jours avant + son entrée en vigueur. +

+

+ La poursuite de l'utilisation du service au-delà de cette période vaut acceptation + des nouvelles CGV. À défaut, l'utilisateur peut résilier son abonnement sans + pénalité avant l'entrée en vigueur des nouvelles conditions. +

+ +

15. Cession

+

+ L'éditeur peut librement céder les présentes CGV ainsi que les contrats en cours + dans le cadre d'une opération de restructuration, de fusion ou de cession + d'activité. L'utilisateur en sera informé par email. +

+ +

16. Droit applicable et juridiction

+

+ Les présentes CGV sont régies par le droit français. Tout litige relatif à leur + formation, exécution ou interprétation, qui n'aurait pu être réglé à l'amiable, + relèvera de la compétence exclusive des tribunaux français du siège de l'éditeur, + y compris en cas de pluralité de défendeurs ou d'appel en garantie, et nonobstant + toute clause contraire éventuelle. +

+

+ Avant toute action contentieuse, les parties s'engagent à rechercher une solution + amiable, par échange écrit à contact@rubis.pro, + dans un délai raisonnable. +

+
+
+ + + + diff --git a/landing/confidentialite.html b/landing/confidentialite.html index 62949d0..75f2afe 100644 --- a/landing/confidentialite.html +++ b/landing/confidentialite.html @@ -78,7 +78,7 @@

2.1 Données d'inscription et de compte

@@ -98,9 +98,9 @@

2.3 Données techniques et journaux

3. Finalités et bases légales

@@ -141,9 +141,9 @@

4. Sous-traitants et hébergement

- Tout l'hébergement principal (base de données, fichiers PDF, application) reste sur - notre infrastructure auto-hébergée en France. Quelques services tiers spécialisés - interviennent uniquement pour des fonctions ciblées : + L'application, la base de données et les fichiers utilisateurs sont hébergés + en France. Trois sous-traitants spécialisés interviennent pour des + fonctions ciblées :

@@ -155,32 +155,21 @@ - + - + - +
Stripe - Traitement des paiements et abonnements. Données : email, nom, CB (jamais - stockée chez nous, gérée par Stripe). Stripe est certifié PCI-DSS niveau 1. - Hébergement principal : Irlande (UE). - Traitement des paiements. Hébergement : Union européenne.
Resend - Envoi des emails transactionnels (relances et confirmations). Données : - adresses email, contenu des emails. Hébergement : UE/US avec - clauses contractuelles types. - Envoi des emails transactionnels et de relance. Hébergement : Union européenne (clauses contractuelles types pour les éventuels traitements hors UE).
Mistral AI - OCR sur les factures uploadées. Les fichiers sont envoyés à Mistral pour - extraction du texte puis supprimés de leur côté. Hébergement : France. - Reconnaissance du texte sur les factures importées. Hébergement : France.

- Aucun transfert hors UE n'a lieu sans encadrement contractuel approprié (clauses - contractuelles types de la Commission européenne). + Aucun transfert de données hors Union européenne n'a lieu sans encadrement + contractuel approprié.

5. Durée de conservation

@@ -233,44 +222,19 @@ au fonctionnement du service. Aucun cookie publicitaire ni de mesure d'audience tierce n'est déposé.

- - - - - - - - - - - - - - - - - - - - - -
CookieRôle & durée
rubis_refreshCookie httpOnly maintenant la session connectée. Durée : 30 jours.
localStorage access_token - Token JWT de courte durée (30 min) pour authentifier les appels API. Pas un - cookie au sens technique mais un stockage local du navigateur. -
localStorage rubis.sidebar.collapsedPréférence d'affichage (sidebar repliée ou non). Aucun tracking.
+

+ Un cookie de session permet de maintenir la connexion à votre compte. Aucun + consentement préalable n'est requis pour ces cookies fonctionnels (article 82 de + la loi Informatique et Libertés). +

8. Sécurité

- Nous appliquons les mesures de sécurité usuelles pour un service SaaS : + Nous mettons en œuvre les mesures techniques et organisationnelles appropriées + pour préserver la confidentialité, l'intégrité et la disponibilité de vos données : + chiffrement des échanges, contrôle des accès, sauvegardes régulières et journalisation + des opérations sensibles.

-

9. Réclamation auprès de la CNIL

diff --git a/landing/index.html b/landing/index.html index 42b5dd7..c8827ec 100644 --- a/landing/index.html +++ b/landing/index.html @@ -1954,7 +1954,7 @@

- 3 mois gratuits puis Free 5 factures + 30 jours gratuits puis Free 5 factures Hébergement souverain @@ -2511,7 +2511,7 @@