Piste d’audit
Slonge Billing journalise chaque action d’écriture — qu’elle provienne du tableau de bord, de la CLI ou d’un client MCP — de manière inaltérable dans deux tables :
ApiTokenUsage: enveloppe de la requête (endpoint, méthode HTTP, code de statut, temps de réponse, adresse IP, user agent) pour chaque appel effectué avec un token API.AuditLog: Qui (userIdet/outokenId), Quoi (action + entité + ID d’entité), diff avant/après pour les mises à jour, ainsi que les métadonnées de contexte.
Exactement une ligne AuditLog est créée par entité métier modifiée avec succès. Les appels PATCH qui ne modifient aucun champ suivi ne génèrent aucune entrée — le journal reste ainsi exempt d’enregistrements no-op dénués de sens.
Modèle à deux niveaux
Chaque appel CLI/MCP
│
├─► ApiTokenUsage (toujours : métadonnées d’enveloppe, indépendamment du succès)
│
└─► AuditLog (uniquement en cas de succès + modification réelle)
Les actions du tableau de bord n’écrivent pas de ligne ApiTokenUsage (aucun token API n’est impliqué), mais elles écrivent une entrée AuditLog avec le userId de la personne connectée.
Cycle de vie financier : registre de conformité
Pour les actions de cycle de vie sur toutes les entités financièrement pertinentes (factures · écritures · notes de crédit · factures fournisseurs · dépenses · offres), un événement chaîné par hachage est en outre ajouté au registre ComplianceEvent. Cela s’applique de la même manière aux actions initiées depuis le tableau de bord et depuis la CLI/MCP. Les documents PDF envoyés sont par ailleurs enregistrés comme DocumentArtifact avec une somme de contrôle SHA-256. Toutes les données de conformité sont incluses dans l’export de sauvegarde du locataire — voir Réglages → Données & Export → Dossier de conformité.
Que journalise-t-on ?
| Action | Entité | Code d’action | Exemple de métadonnées |
|---|---|---|---|
| Créer un client | Client | create | { name, email } |
| Mettre à jour un client | Client | update | Diff des champs modifiés |
| Supprimer un client | Client | delete | { name } |
| Créer un projet | Project | create | { name, clientId } |
| Créer une facture | Invoice | create | { invoiceNumber, clientId, totalAmount } |
| Envoyer une facture | Invoice | send | { invoiceNumber, recipientEmail } |
| Marquer une facture comme payée | Invoice | status_change | { invoiceNumber, status: "paid" } |
| Créer une offre | Quote | create | { quoteNumber, amount } |
| Envoyer une offre | Quote | send | { quoteNumber, recipientEmail } |
| Convertir une offre → facture | Invoice + Quote | create + status_change | { quoteNumber, invoiceNumber } |
| Créer une saisie de temps | TimeEntry | create | { projectId, hours, date } |
| Créer une dépense | Expense | create | { amount, vendor, date } |
| Téléverser un justificatif (OCR) | Expense | view | { fileSize, mimeType, parsedAmount, parsedVendor, parsedDate } |
| Mettre à jour les réglages | Settings | update | Diff des champs modifiés |
| Créer un token API | ApiToken | create | { tokenName, tokenPrefix, expiresAt } |
| Révoquer un token API | ApiToken | revoke | { tokenName, tokenPrefix } |
| Rappel envoyé (cron ou CLI) | Invoice | status_change | { invoiceNumber, source: "cron"/"cli" } |
| Créer une écriture | JournalEntry | journal.created | Instantané complet, positions incluses |
| Modifier une écriture | JournalEntry | journal.updated | Avant + après |
| Supprimer une écriture | JournalEntry | journal.deleted | Instantané complet |
| Créer une note de crédit | CreditNote | creditNote.created | Instantané complet |
| Note de crédit depuis une facture | CreditNote | creditNote.created_from_invoice | sourceInvoiceId + instantané |
| Modifier une note de crédit | CreditNote | creditNote.updated | Avant + après |
| Supprimer une note de crédit | CreditNote | creditNote.deleted | Instantané complet |
| Créer une facture fournisseur | VendorBill | vendorBill.created | Instantané complet |
| Modifier une facture fournisseur | VendorBill | vendorBill.updated | Avant + après |
| Supprimer une facture fournisseur | VendorBill | vendorBill.deleted | Instantané complet |
| Facture fournisseur payée | VendorBill | vendorBill.paid | paidAt + paymentReference |
| Créer une dépense | Expense | expense.created | Instantané complet |
| Modifier une dépense | Expense | expense.updated | Avant + après |
| Supprimer une dépense | Expense | expense.deleted | Instantané complet |
| Téléverser un justificatif (OCR) | Expense | expense.uploaded | fileSize, mimeType, parsedAmount, parsedVendor, parsedDate |
| Créer une offre | Quote | quote.created | Instantané complet |
| Modifier une offre | Quote | quote.updated | Avant + après |
| Supprimer une offre | Quote | quote.deleted | Instantané complet |
| Envoyer une offre | Quote | quote.sent | recipientEmail + instantané |
| Accepter une offre | Quote | quote.accepted | Instantané complet |
| Convertir une offre | Quote | quote.converted | createdInvoiceId + instantané |
Note de sécurité : la valeur complète du token n’est jamais journalisée — uniquement le nom et le préfixe (p. ex.
slk_live_abc…).
Attribution de l’origine
Chaque entrée AuditLog porte soit un userId, soit un tokenId (ou les deux) :
| Interface | userId | tokenId |
|---|---|---|
| Tableau de bord | ✓ (personne connectée) | — |
| CLI / MCP / Streamable HTTP | — | ✓ (token API utilisé) |
Le nom du token que vous avez attribué lors de la création (p. ex. « Claude Desktop — Laptop Ben ») apparaît dans la piste d’audit et facilite l’attribution. C’est pourquoi nous recommandons de créer un token distinct par appareil et par application.
Consulter la piste d’audit
La piste d’audit n’est actuellement pas consultable directement dans le tableau de bord. Les données brutes sont toutefois incluses dans l’export du dossier de conformité :
- Réglages → Données & Export → Exporter le dossier de conformité
- Le ZIP contient
compliance/events.json(journal de cycle de vie chaîné par hachage) etcompliance/document-artifacts.json(sommes de contrôle des PDF).
Si vous avez besoin d’une interface utilisateur dédiée à la piste d’audit, contactez-nous à l’adresse [email protected].
Lien avec les autres fonctions de sécurité
| Fonction | Objectif |
|---|---|
| Piste d’audit (cette page) | Qui a modifié quoi — pour le contrôle interne et le débogage |
| Registre de conformité | Événements de factures chaînés par hachage — pour les vérificateurs externes |
| ApiTokenUsage | Statistiques de requêtes par token — pour le rate limiting et la détection d’anomalies |
| Artefacts de documents SHA-256 | Preuve d’intégrité des PDF envoyés |
Les quatre niveaux se complètent : la piste d’audit explique ce qui a été modifié, le registre de conformité atteste *qu’*une facture a existé et a été envoyée, et les artefacts de documents prouvent que la version PDF stockée est bien celle qui a été envoyée.