6.1 Plan comptable général
Référentiel des comptes SYSCOHADA de la société.
- Créer un compte (code, libellé, classe, type)
- Importer / exporter le plan
- Activer ou désactiver un compte
VAN INTERNATIONAL SA
Guide utilisateur, architecture technique, exploitation, schéma de base de données et inventaire des dépendances — OHADA / SYSCOHADA.
Documentation utilisateur
Guide complet pour utiliser la plateforme comptable VAN INTERNATIONAL SA, conforme au référentiel OHADA / SYSCOHADA : comptabilité générale, achats, ventes, stocks, trésorerie, contrôle de gestion et intégrations.
Utilisez l’action Déconnexion dans la barre supérieure. Cela invalide la session côté serveur.
Pour changer votre mot de passe une fois connecté : Paramètres → Mot de passe.
Le menu regroupe les modules :
L’application gère plusieurs entités du groupe. Chaque document, écriture et stock est isolé par société.
Les utilisateurs SUPER_ADMIN peuvent accéder à toutes les sociétés. Les autres utilisateurs ne voient que les sociétés qui leur sont attribuées.
Création / édition des sociétés : menu Paramètres → Sociétés.
| Rôle | Droits typiques |
|---|---|
| SUPER_ADMIN | Tous les modules + gestion des utilisateurs & privilèges + toutes les sociétés |
| ADMIN | Accès large à tous les modules métier |
| ASSISTANT_COMPTABLE / COMPTABLE | Modules selon les permissions cochées |
| Clé | Accès |
|---|---|
| dashboard | Accueil & tableaux de bord |
| accounting | Comptabilité générale |
| tiers | Clients & fournisseurs |
| purchases | Achats |
| sales | Ventes |
| stocks | Stocks |
| treasury | Trésorerie |
| analytics | Contrôle de gestion |
| reports | Déclarations & états |
| integrations | VAN & imports |
| settings | Paramètres / sociétés / devises |
Gestion : Paramètres → Utilisateurs & privilèges (réservé au SUPER_ADMIN). Le profil, les infos société et le mot de passe restent accessibles à tout utilisateur connecté.
/Vue de pilotage : indicateurs OHADA/SYSCOHADA, alertes de workflows (factures ouvertes, validations en attente, etc.) et raccourcis vers les écrans clés.
/tresorerie/dashboard-dafVision DAF consolidée de la trésorerie et de la santé financière de la société active.
Référentiel des comptes SYSCOHADA de la société.
Pièces manuelles (OD, régularisations, etc.).
| Écran | Usage |
|---|---|
| Livre journal | Chronologie obligatoire des écritures |
| Journaux comptables | Paramétrage des journaux (ACH, VTE, BNQ…) |
| Journal général | Centralisation |
| Grand Livre | Mouvements par compte, filtrables par période |
| Balance générale | Soldes (vues 2 / 4 / 6 colonnes) |
| Livre d’inventaire | Synthèse utile en clôture |
| Piste d’audit | Historique des actions sensibles |
Verrouillez un mois pour empêcher les modifications a posteriori. Vous pouvez clôturer ou rouvrir une période selon vos droits.
Statuts : Ouverte Clôturée
Référentiel clients : identité, contacts, compte tiers, conditions.
Actions : Ajouter, Modifier, Supprimer, consulter le détail.
Référentiel fournisseurs, même logique que les clients.
Analyse de l’ancienneté des créances (clients) et dettes (fournisseurs) par tranches d’âge. Utile pour le recouvrement et le pilotage trésorerie.
Statuts fréquents : Brouillon Validé Réception partielle Réception totale Facturé Clôturé Annulé
Statuts paiement : Impayée Partiellement payée Payée
Notes de crédit fournisseur pour retours, rabais ou corrections.
Statuts : Brouillon Soumis Validé Rejeté Transformé en BC
Création depuis commande ou manuelle. Après validation : sortie de stock et possibilité de facturer.
Facture comptabilisée avec écriture automatique, puis Valider l’encaissement ou passer par Règlements clients.
Avoirs de vente pour retours, remises ou annulations partielles.
Catalogue produits / services : référence, libellé, comptes associés, suivi de stock, quantités.
Définissez les prix d’achat par fournisseur pour faciliter les commandes.
Traçabilité des entrées, sorties et ajustements (souvent automatiques).
Valorisation selon la méthode CMUPACE (coût moyen pondéré).
Anticipation J+30 / J+60 / J+90. Vous pouvez générer des prévisions à partir des factures ouvertes ou ajouter des lignes manuelles.
Même logique en décaissement : payer une facture ou le solde restant.
| Écran | À quoi ça sert |
|---|---|
| Projets & Chantiers | Suivi BTP / prestations par projet |
| Prix de revient | Coûts réels vs budget |
| Centres de coûts | Nomenclature analytique DAF |
| Saisie budgétaire | Saisir les budgets |
| Suivi budgétaire | Écarts et alertes de dépassement |
| Sections | Axes analytiques |
| Postes analytiques | Détail des postes |
| Balance analytique | Soldes par axe / poste |
Bilan et compte de résultat périodiques (mois, trimestre, semestre, exercice) pour la société active.
Synthèse TVA collectée / déductible. Préparez la déclaration, enregistrez, exportez en PDF ou Excel.
Demandes provenant des systèmes RH, Logistique ou BTP. Pour chaque demande :
Statuts : PENDING VALIDATED REJECTED
Import Excel des référentiels :
Modes : Ajouter (append) ou Remplacer. Téléchargez d’abord le modèle, remplissez-le, puis lancez l’import.
Menu VAN & intégrations → Sauvegarde / restauration
(/outils/sauvegarde).
van-compta-backup-AAAA-MM-JJ.json
hors du poste (disque externe, cloud sécurisé)..json de sauvegarde VAN valide.
En production, cette sauvegarde JSON est un complément :
la sauvegarde de référence reste le dump MySQL
+ le dossier uploads/ (voir document d’exploitation).
Taux de change (référentiel BEAC) et convertisseur.
Vue groupe : détection des transactions intra-groupe, éliminations, validation et saisie manuelle si besoin.
Votre compte n’a probablement pas la permission du module. Demandez au SUPER_ADMIN d’activer le droit correspondant (achats, ventes, stocks, etc.).
L’écriture de facturation (comptabilisation) n’est pas celle de règlement. Le statut « Payée » change après un encaissement / décaissement (ou validation de paiement) avec lettrage.
Vérifiez que l’article est en suivi de stock, puis que la réception ou la livraison a bien été validée.
Les sessions sont courtes pour la sécurité. Reconnectez-vous ; le renouvellement automatique peut aussi échouer si le serveur a redémarré avec de nouveaux secrets.
Une session locale peut être disponible si un utilisateur est déjà en cache, mais le mode nominal est connecté à l’API (mode strict recommandé).
Paramètres → Informations société.
Documentation technique
Document d’architecture de l’ERP comptable VAN INTERNATIONAL SA : frontend React, API Express, MySQL / Sequelize, référentiel OHADA / SYSCOHADA, multi-sociétés et intégrations M2M.
Navigateur (React CRA :3000)
│ HTTPS + cookies (withCredentials)
▼
API Express (:4000) ── /api/* ──► Controllers / Services / Modules
│
▼
MySQL 8 (van_comptabilite)
▲
uploads/ (médias privés via /api/media ou /uploads signés)
comptable-ohadas/ ├── package.json # Frontend CRA ├── .env / .env.example ├── public/ # PWA, assets ├── src/ # Frontend React │ ├── app/ # providers, router │ ├── components/ # écrans métier │ ├── modules/ # workspaces UI │ ├── context/ # Auth, notifications │ ├── services/ # apiClient, auth, sync, domain │ └── shared/config/ # menu, pageRegistry ├── backend/ │ ├── package.json │ ├── .env / .env.example │ └── src/ │ ├── server.js # bootstrap + listen │ ├── app.js # Express pipeline │ ├── bootstrap/ # schéma, OHADA, validate prod │ ├── config/ # database, jwt │ ├── routes/api/ # REST + permissions │ ├── controllers/ │ ├── models/ # Sequelize (~49) │ ├── middlewares/ │ ├── services/ # posting, stock, media, auth │ ├── modules/ # achats, ventes, trésorerie… │ ├── utils/ # companyScope, cookies, upload │ └── seeders/ ├── guide/ # Guide utilisateur HTML └── architecture/ # Ce document
Une version courte existe aussi dans docs/architecture.md.
/login + routes protégées| Fichier / dossier | Rôle |
|---|---|
| src/services/apiClient.js | Axios : withCredentials, header X-Company-Id, refresh auto sur 401 |
| src/services/authService.js | login / me / refresh / logout ; profil user en localStorage |
| src/services/sync/ | Hydratation API, cache société, file offline |
| src/services/domain/ | Règles métier UI (achats, ventes, trésorerie…) |
| src/services/core/companyScope.js | Société active van_active_company_id |
van_at / van_rt httpOnly uniquement.
Seul le profil utilisateur (UI / offline) reste en localStorage.
backend/src/server.js charge l’env,
valide la prod, authentifie Sequelize, synchronise le schéma
(alter: false), bootstrap OHADA, puis écoute
0.0.0.0:PORT.
backend/src/app.js enchaîne :
security headers → rate limit → cookies → CORS credentials →
JSON → CSRF Origin → morgan → routes médias → /api → errorHandler.
backend/src/routes/api/index.js :
helper mount(path, permissions, router) =
auth + requireAnyPermission.
| Préfixe | Auth | Exemples |
|---|---|---|
/api/health | Public | Santé DB |
/api/auth/* | Mixte | login, refresh, me, logout |
/api/media/* | Signature ou session | Images |
/api/purchase-orders… | JWT + permissions | CRUD métier |
/api/integrations/van | API key (+ JWT validation) | RH / Logistique / BTP |
| Fichier | Rôle |
|---|---|
| middlewares/auth.js | JWT + tokenVersion + société active |
| middlewares/permissions.js | Catalogue modules, bypass ADMIN |
| middlewares/rateLimit.js | API / login / refresh |
| middlewares/integrationAuth.js | API key + HMAC optionnel |
| middlewares/secureImageUpload.js | Multer sécurisé |
| middlewares/csrfOriginCheck.js | Origin/Referer si cookies |
| utils/companyScope.js | Anti-IDOR companyId |
| Élément | Détail |
|---|---|
| Access JWT | TTL défaut 15 min — payload : id, email, role, companyId, tv |
| Refresh | Opaque 48 bytes, hash HMAC-SHA256 en table RefreshToken, TTL 14 j |
| Cookies | van_at, van_rt — httpOnly, Secure en prod, SameSite lax/none |
| Rotation | Chaque refresh révoque l’ancien ; réutilisation → révocation globale |
| tokenVersion | Mismatch → TOKEN_REVOKED ; bump à logout / reset MDP |
Services : backend/src/services/authToken.service.js, backend/src/utils/authCookies.js, backend/src/controllers/authController.js.
X-Company-Id (sinon JWT / société par défaut).canUseCompany : SUPER_ADMIN libre ; sinon société autorisée / groupe.req.companyId propage le scope à tous les contrôleurs.scopedWhere, findByPkInCompany, assertBelongsToCompany empêchent l’IDOR.companyId: -1
(aucune ligne retournée) plutôt qu’un accès global.
express.static public sur /uploads.GET /uploads/:subdir/:filename et GET /api/media/....?exp=&sig= ou session JWT.products, companies.Préfixe /api/integrations/van (vanIntegrations.routes.js).
X-API-Key = VAN_INTEGRATION_API_KEYX-Van-Timestamp + X-Van-Signature (HMAC-SHA256, skew 5 min)integrations / accountingIndex : backend/src/models/index.js — tables underscored + timestamps.
| Domaine | Modèles |
|---|---|
| Identité | Company, User, RefreshToken, AuditLog |
| Comptable | Account, Journal, FiscalYear, AccountingPeriod, Section, AnalyticPost |
| Écritures | AccountingEntry, EntryLine, EntryLineAnalytic |
| Tiers / stock | Client, Supplier, Product, SupplierPrice, StockMovement |
| Achats | PurchaseOrder(+Line), GoodsReceipt(+Line), PurchaseInvoice(+Line), SupplierCreditNote |
| Ventes | SalesQuote(+Line), SalesOrder(+Line), DeliveryNote(+Line), SalesInvoice(+Line), CustomerCreditNote |
| Trésorerie | BankAccount, Payment, PaymentAllocation, BankReconciliation, CashForecast, ExchangeRate |
| Fiscal / analytique | FixedAsset, Depreciation, VatDeclaration, Budget, Project, InterCompanyTransaction |
| Document | Service | Journal / comptes typiques |
|---|---|---|
| Réception stock | stockPostingService.applyGoodsReceiptStock | STK/OD — 311 / 603 |
| Facture achat | accountingPostingService.postPurchaseInvoice | ACH — 601 / 445 / 401 |
| Facture vente | postSalesInvoice | VTE — 411 / 701 / 443… |
| Règlement | postPayment | BNQ/CAI — 401↔521 ou 411↔521 |
ensureEntry(sourceType, sourceId) garantit
une seule écriture par document source.
Orchestrateur : modules/comptabilite/services/accountingEngineV2.service.js.
| Variable | Rôle |
|---|---|
REACT_APP_API_BASE_URL | Base API (prod : api.vancomptabilite.com/api) |
REACT_APP_STRICT_API | Mode strict API / cache |
| Variable | Rôle |
|---|---|
DB_* | Connexion MySQL |
JWT_SECRET / JWT_EXPIRES_IN | Access token |
REFRESH_TOKEN_SECRET / REFRESH_TOKEN_EXPIRES_IN | Pepper refresh |
COOKIE_* | SameSite, Secure, Domain |
CORS_ORIGIN | Origines front autorisées |
PUBLIC_BASE_URL | Base URLs médias signées |
MEDIA_URL_SECRET | HMAC médias |
VAN_INTEGRATION_API_KEY | Intégrations M2M |
LOGIN_* / API_* | Rate limits |
En production, le démarrage est refusé si secrets faibles ou CORS *
(bootstrap/validateProductionEnv.js).
tokenVersioncompanyId anti-IDOR
Acteurs principaux et cas d’utilisation métier de VAN Comptabilité.
Les inclusions (include) représentent des prérequis techniques
(authentification, choix de société).
flowchart TB
subgraph Acteurs
SA((SUPER_ADMIN))
AD((ADMIN / Comptable))
AS((Assistant))
DAF((DAF / Direction))
SYS((Systèmes VAN
RH / Logistique / BTP))
end
subgraph Authentification
UC_LOGIN[Se connecter]
UC_LOGOUT[Se déconnecter]
UC_PWD[Changer mot de passe]
UC_CO[Changer de société]
end
subgraph Comptabilite
UC_PC[Gérer plan comptable]
UC_ECR[Saisir écritures]
UC_LIV[Consulter livres / balance]
UC_CLO[Clôturer une période]
end
subgraph Achats
UC_BC[Créer commande fournisseur]
UC_BR[Réceptionner marchandises]
UC_FA[Facturer un achat]
UC_PA[Payer un fournisseur]
end
subgraph Ventes
UC_DV[Émettre un devis]
UC_BCV[Valider commande client]
UC_BL[Livrer un client]
UC_FV[Facturer une vente]
UC_ENC[Encaisser un client]
end
subgraph Stocks
UC_ART[Gérer articles]
UC_MOV[Consulter mouvements]
UC_VAL[Valoriser stocks CMUPACE]
end
subgraph Tresorerie
UC_PREV[Prévoir trésorerie]
UC_RAP[Rapprocher banque]
end
subgraph Pilotage
UC_KPI[Consulter tableaux de bord]
UC_TVA[Préparer déclaration TVA]
UC_EF[Consulter états financiers]
UC_BUD[Suivre budget / projets]
end
subgraph Administration
UC_USER[Gérer utilisateurs et permissions]
UC_SOC[Gérer sociétés]
UC_IMP[Importer données Excel]
UC_BAK[Sauvegarder / restaurer]
end
subgraph Integrations
UC_ING[Injecter flux RH / Logistique / BTP]
UC_VALV[Valider ou rejeter demandes VAN]
end
SA --> UC_USER
SA --> UC_SOC
SA --> UC_LOGIN
AD --> UC_LOGIN
AD --> UC_PC
AD --> UC_ECR
AD --> UC_BC
AD --> UC_BR
AD --> UC_FA
AD --> UC_PA
AD --> UC_DV
AD --> UC_BCV
AD --> UC_BL
AD --> UC_FV
AD --> UC_ENC
AD --> UC_ART
AD --> UC_RAP
AD --> UC_TVA
AD --> UC_VALV
AD --> UC_IMP
AS --> UC_LOGIN
AS --> UC_BC
AS --> UC_BR
AS --> UC_DV
AS --> UC_LIV
DAF --> UC_LOGIN
DAF --> UC_KPI
DAF --> UC_PREV
DAF --> UC_EF
DAF --> UC_BUD
DAF --> UC_CLO
SYS --> UC_ING
UC_BC -.->|include| UC_LOGIN
UC_FA -.->|include| UC_BR
UC_PA -.->|include| UC_FA
UC_FV -.->|include| UC_BL
UC_ENC -.->|include| UC_FV
UC_VALV -.->|include| UC_LOGIN
UC_ING -.->|API key| SYS
flowchart LR
Comptable((Comptable))
UC1([Créer BC fournisseur])
UC2([Valider réception BR])
UC3([Comptabiliser facture achat])
UC4([Enregistrer règlement])
UC5([Générer écriture SYSCOHADA])
UC6([Mettre à jour stock])
Comptable --> UC1
Comptable --> UC2
Comptable --> UC3
Comptable --> UC4
UC2 -->|include| UC6
UC3 -->|include| UC5
UC4 -->|include| UC5
UC2 --> UC3
UC3 --> UC4
flowchart LR
Commercial((Commercial / Comptable))
V1([Créer devis])
V2([Transformer en BC])
V3([Livrer BL])
V4([Facturer client])
V5([Encaisser])
V6([Sortie stock])
V7([Écritures VTE / BNQ])
Commercial --> V1
Commercial --> V2
Commercial --> V3
Commercial --> V4
Commercial --> V5
V1 --> V2 --> V3 --> V4 --> V5
V3 -->|include| V6
V4 -->|include| V7
V5 -->|include| V7
| Acteur | Objectif principal |
|---|---|
| SUPER_ADMIN | Administration globale, multi-sociétés, utilisateurs |
| ADMIN / Comptable | Opérations comptables, achats, ventes, stocks, TVA |
| Assistant | Saisie opérationnelle selon permissions |
| DAF / Direction | Pilotage, budgets, clôtures, états |
| Systèmes VAN | Injection M2M de flux à valider en comptabilité |
Classes dérivées des modèles Sequelize
(backend/src/models/).
Attributs essentiels uniquement ; toutes les entités métier portent un
companyId (multi-tenant).
Vue d’ensemble du domaine : société, utilisateurs, référentiels, cycles achats / ventes, stocks, écritures et trésorerie.
classDiagram
direction TB
class Company {
+id
+name
+currency
+companyId scope
}
class User {
+email
+role
+permissions
+tokenVersion
}
class Account {
+number
+name
+classCode
}
class Journal {
+code
+name
}
class Client {
+code
+name
}
class Supplier {
+code
+name
}
class Product {
+sku
+trackStock
+stockQuantity
}
class PurchaseOrder {
+number
+status
}
class GoodsReceipt {
+number
+status
}
class PurchaseInvoice {
+number
+status
+totalAmount
}
class SalesQuote {
+number
+status
}
class SalesOrder {
+number
+status
}
class DeliveryNote {
+number
+status
}
class SalesInvoice {
+number
+status
+totalAmount
}
class StockMovement {
+quantity
+unitCost
+sourceType
}
class AccountingEntry {
+number
+sourceType
+sourceId
}
class EntryLine {
+debit
+credit
}
class Payment {
+amount
+method
}
class PaymentAllocation {
+allocatedAmount
}
class BankAccount {
+code
+name
}
Company "1" --> "*" User : emploie
Company "1" --> "*" Account
Company "1" --> "*" Journal
Company "1" --> "*" Client
Company "1" --> "*" Supplier
Company "1" --> "*" Product
Company "1" --> "*" BankAccount
Supplier "1" --> "*" PurchaseOrder
PurchaseOrder "1" --> "*" GoodsReceipt
GoodsReceipt "1" --> "*" PurchaseInvoice
Product "1" --> "*" StockMovement
GoodsReceipt ..> StockMovement : génère IN
Client "1" --> "*" SalesQuote
SalesQuote "1" --> "0..1" SalesOrder
SalesOrder "1" --> "*" DeliveryNote
DeliveryNote "1" --> "*" SalesInvoice
DeliveryNote ..> StockMovement : génère OUT
Journal "1" --> "*" AccountingEntry
AccountingEntry "1" --> "*" EntryLine
EntryLine --> Account
PurchaseInvoice ..> AccountingEntry : poste ACH
SalesInvoice ..> AccountingEntry : poste VTE
Payment ..> AccountingEntry : poste BNQ
BankAccount "1" --> "*" Payment
Payment "1" --> "*" PaymentAllocation
PaymentAllocation --> PurchaseInvoice : lettrage
PaymentAllocation --> SalesInvoice : lettrage
classDiagram
class Company {
+id
+name
+rccm
+niu
+currency
+parentCompanyId
}
class User {
+id
+email
+passwordHash
+role
+permissions
+tokenVersion
+companyId
}
class RefreshToken {
+id
+tokenHash
+expiresAt
+revokedAt
+userId
}
class AuditLog {
+id
+action
+entity
+payload
+userId
+companyId
}
Company "1" --> "*" User : emploie
User "1" --> "*" RefreshToken : sessions
Company "1" --> "*" Company : filiales
User --> AuditLog : produit
Company --> AuditLog : scope
classDiagram
class Account {
+code
+label
+class
+type
+companyId
}
class Journal {
+code
+label
+type
+companyId
}
class FiscalYear {
+year
+status
+companyId
}
class AccountingPeriod {
+month
+status
+fiscalYearId
}
class AccountingEntry {
+number
+date
+label
+sourceType
+sourceId
+journalId
+companyId
}
class EntryLine {
+debit
+credit
+accountId
+entryId
}
Company "1" --> "*" Account : possède
Company "1" --> "*" Journal : possède
Company "1" --> "*" FiscalYear : possède
FiscalYear "1" --> "*" AccountingPeriod
Journal "1" --> "*" AccountingEntry
AccountingEntry "1" --> "*" EntryLine
EntryLine --> Account
note for AccountingEntry "Idempotence ensureEntry(sourceType, sourceId)"
classDiagram
class Supplier {
+code
+name
+collectiveAccountId
}
class Product {
+sku
+name
+trackStock
+stockQty
+cmp
}
class PurchaseOrder {
+number
+status
+supplierId
}
class PurchaseOrderLine {
+qty
+unitPrice
+productId
}
class GoodsReceipt {
+number
+status
+purchaseOrderId
}
class GoodsReceiptLine {
+qtyReceived
+productId
}
class PurchaseInvoice {
+number
+status
+goodsReceiptId
+totalTTC
}
class PurchaseInvoiceLine {
+qty
+amount
}
class StockMovement {
+type
+qty
+unitCost
+productId
+sourceType
}
Supplier "1" --> "*" PurchaseOrder
PurchaseOrder "1" --> "*" PurchaseOrderLine
PurchaseOrder "1" --> "*" GoodsReceipt
GoodsReceipt "1" --> "*" GoodsReceiptLine
GoodsReceipt "1" --> "*" PurchaseInvoice
PurchaseInvoice "1" --> "*" PurchaseInvoiceLine
Product "1" --> "*" PurchaseOrderLine
Product "1" --> "*" StockMovement
GoodsReceipt --> StockMovement : génère IN
classDiagram
class Client {
+code
+name
+collectiveAccountId
}
class SalesQuote {
+number
+status
+clientId
}
class SalesOrder {
+number
+status
+salesQuoteId
}
class DeliveryNote {
+number
+status
+salesOrderId
}
class SalesInvoice {
+number
+status
+totalTTC
}
class Payment {
+number
+amount
+method
+direction
+bankAccountId
}
class PaymentAllocation {
+amount
+invoiceId
+paymentId
}
class BankAccount {
+code
+label
+type
}
class PurchaseInvoice {
+number
+status
+totalTTC
}
Client "1" --> "*" SalesQuote
SalesQuote "1" --> "0..1" SalesOrder
SalesOrder "1" --> "*" DeliveryNote
DeliveryNote "1" --> "*" SalesInvoice
Client "1" --> "*" SalesInvoice
Payment "1" --> "*" PaymentAllocation
PaymentAllocation --> SalesInvoice : lettrage vente
PaymentAllocation --> PurchaseInvoice : lettrage achat
BankAccount "1" --> "*" Payment
classDiagram
class Router {
+mount(path, permissions)
}
class AuthMiddleware {
+verifyJWT()
+resolveCompany()
}
class Controller {
+create()
+update()
+remove()
}
class DomainService {
+postPurchaseInvoice()
+applyGoodsReceiptStock()
+postPayment()
}
class SequelizeModel {
+findAll()
+create()
}
Router --> AuthMiddleware : protège
Router --> Controller : délègue
Controller --> DomainService : métier
DomainService --> SequelizeModel : persiste
AuthMiddleware --> SequelizeModel : User / Company
sequenceDiagram
participant U as Utilisateur
participant F as React
participant A as API /auth
participant DB as MySQL
U->>F: email + password
F->>A: POST /auth/login
A->>DB: User + bcrypt
A->>DB: RefreshToken.create
A-->>F: Set-Cookie van_at / van_rt
F->>A: GET /auth/me
A-->>F: user + société
Si Mermaid ne charge pas hors-ligne, le flux est décrit dans le tableau Auth ci-dessus.
sequenceDiagram
participant F as Frontend
participant API as Controllers
participant Stock as stockPosting
participant Acc as accountingPosting
participant DB as MySQL
F->>API: POST purchase-orders
API->>DB: PO APPROVED
F->>API: POST goods-receipts
API->>Stock: applyGoodsReceiptStock
Stock->>DB: StockMovement IN
Stock->>Acc: écriture stock 311/603
F->>API: POST purchase-invoices
API->>Acc: postPurchaseInvoice
Acc->>DB: Entry ACH 601/445/401
F->>API: POST payments
API->>Acc: postPayment
Acc->>DB: Entry BNQ 401/521
API->>DB: invoice PAID / PARTIAL
sequenceDiagram
participant C as Client
participant API as serveMedia
participant S as mediaAccess
participant FS as uploads/
C->>API: GET /api/media/... ?exp&sig
API->>S: whitelist + vérif
alt Signature HMAC OK
S-->>API: autorisé
else Session JWT OK
S-->>API: autorisé
else
API-->>C: 401
end
API->>FS: resolveSafeLocalPath
API-->>C: fichier + nosniff
Vue des nœuds physiques / logiques, artefacts déployés et protocoles.
Les cookies d’auth (van_at / van_rt) transitent
en HTTPS entre le navigateur et l’API.
flowchart TB
subgraph Clients["Nœud : Postes utilisateurs"]
BR["« device » Navigateur
Chrome / Firefox / Safari"]
end
subgraph Edge["Nœud : Frontière Internet / TLS"]
DNS["DNS
api.vancomptabilite.com"]
PX["« device » Reverse proxy
Nginx / Caddy
TLS 1.2+"]
end
subgraph AppTier["Nœud : Serveur applicatif"]
WEB["« artifact » Frontend SPA
build/ React CRA
fichiers statiques"]
API["« artifact » API Node.js
van-comptabilite-backend
Express :4000
PM2 / systemd"]
UP["« artifact » Stockage médias
uploads/products
uploads/companies"]
end
subgraph DataTier["Nœud : Serveur de données"]
DB[("« database » MySQL 8
van_comptabilite")]
end
subgraph Ext["Nœuds externes VAN"]
RH["RH"]
LOG["Logistique"]
BTP["BTP"]
end
BR -->|HTTPS| DNS
DNS --> PX
PX -->|static HTTPS| WEB
PX -->|/api HTTPS| API
WEB -.->|Axios cookies
withCredentials| API
API -->|TCP 3306| DB
API --- UP
RH -->|X-API-Key HTTPS| API
LOG -->|X-API-Key HTTPS| API
BTP -->|X-API-Key HTTPS| API
flowchart LR
subgraph DevMachine["Nœud : Machine développeur"]
B["Navigateur :3000"]
F["« artifact » yarn start
react-scripts"]
A["« artifact » npm run dev
Express :4000"]
M[("MySQL local
:3306")]
U["uploads/"]
end
B --> F
F -->|http://localhost:4000/api
cookies| A
A --> M
A --- U
| Nœud / artefact | Contenu | Exposition |
|---|---|---|
| Frontend SPA | yarn build → dossier build/ |
HTTPS via proxy (domaine app) |
| API Express | backend/src/server.js + .env prod |
https://api.vancomptabilite.com → :4000 |
| MySQL | Schéma Sequelize, données multi-sociétés | Réseau privé uniquement |
| uploads/ | Logos & photos (accès signé / session) | Via API /api/media ou /uploads |
| Systèmes VAN | RH, Logistique, BTP | /api/integrations/van + API key |
yarn start → :3000cd backend && npm run dev → :4000NODE_ENV=productionCORS_ORIGIN = URL front exacteCOOKIE_SECURE=truePUBLIC_BASE_URL = URL API publiqueyarn buildProcédures d’installation, configuration, exploitation courante, sauvegarde et incident pour l’API et le frontend VAN Comptabilité.
van_comptabilite)backend/.env.example → backend/.env.DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD.cd backend npm install # Éditer .env (JWT, refresh, VAN_INTEGRATION_API_KEY, MEDIA_URL_SECRET…) npm run dev
Au démarrage : sequelize.authenticate(), ensure*Schema, sync({ alter: false }), bootstrap OHADA, écoute 0.0.0.0:4000.
Santé : GET /api/health → { ok: true }.
# Racine du projet cp .env.example .env # REACT_APP_API_BASE_URL=http://localhost:4000/api (local) # ou https://api.vancomptabilite.com/api (prod) yarn install yarn start
| Variable | Où | Notes |
|---|---|---|
JWT_SECRET | backend | ≥ 24 car. aléatoires ; refus démarrage prod si faible |
REFRESH_TOKEN_SECRET | backend | Pepper distinct du JWT |
VAN_INTEGRATION_API_KEY | backend | Clé M2M RH/Logistique/BTP |
MEDIA_URL_SECRET | backend | HMAC URLs médias |
CORS_ORIGIN | backend | Origines front exactes (pas * en prod) |
COOKIE_SECURE | backend | true en HTTPS |
PUBLIC_BASE_URL | backend | URL publique API pour médias |
REACT_APP_API_BASE_URL | front | Base API consommée par Axios |
REACT_APP_STRICT_API | front | Mode strict API recommandé true |
flowchart TB U["Navigateur utilisateur"] --> PX["Reverse proxy TLS
Nginx / Caddy"] PX --> WEB["SPA React
build/"] PX --> API["API Express
:4000"] API --> DB[("MySQL 8")] API --> FS["uploads/"] VAN["RH / Logistique / BTP"] -->|API key| API WEB -.->|cookies HTTPS| API
Détail complet : Architecture → §16 Déploiement.
NODE_ENV=productionCORS_ORIGIN = URL HTTPS du frontCOOKIE_SECURE=true (+ COOKIE_DOMAIN si besoin)PUBLIC_BASE_URL=https://api.vancomptabilite.comnode src/server.jsyarn build puis héberger le dossier build/ complet (y compris static/)/ et index.html marchent) — voir §4bVAN_INTEGRATION_API_KEY côté systèmes VANJWT_SECRET / REFRESH_TOKEN_SECRET
invalide toutes les sessions : les utilisateurs doivent se reconnecter.
React utilise le routage côté client (BrowserRouter).
Si le serveur web ne renvoie pas index.html pour les URLs comme
/login ou /comptabilite/…, la page reste cassée ou en 404.
De même, si le dossier build/static/ n’est pas déployé, le HTML s’affiche
mais sans CSS/JS.
yarn build (pas seulement index.html).try_files $uri $uri/ /index.html; — exemple dans deploy/nginx-frontend.conf.example..htaccess est copié dans build/ au build CRA._redirects inclus au build.FRONTEND_BUILD_PATH vers le dossier build/./static/js/… et /static/css/… répondent 200.# Build + déploiement typique
yarn build
# Copier TOUT le dossier build/ vers le serveur, ex. :
# rsync -av --delete build/ user@serveur:/var/www/van-comptabilite/build/
# Nginx (extrait)
# root /var/www/van-comptabilite/build;
# location / { try_files $uri $uri/ /index.html; }
admin@vaninternational.localvan_at (access 15m), van_rt (refresh 14j)combined en prod.envTrois niveaux complémentaires. En production, le couple MySQL + uploads est obligatoire. La sauvegarde JSON de l’écran applicatif est un secours / migration de poste.
| Niveau | Contenu | Usage |
|---|---|---|
MySQL (mysqldump) |
Toute la base métier multi-sociétés | Sauvegarde principale production |
Fichiers uploads/ |
Logos sociétés, photos produits | Toujours avec le dump SQL |
| JSON applicatif | Export navigateur (écran Sauvegarde) | Démo, poste local, secours UI |
Fichier .env |
Secrets & config (hors git) | Coffre-fort ops, jamais dans le dump public |
# Sauvegarde complète (recommandée) mysqldump -u USER -p \ --single-transaction \ --routines --triggers \ van_comptabilite \ > /backups/van_comptabilite_$(date +%F_%H%M).sql # Compression optionnelle gzip /backups/van_comptabilite_*.sql
pm2 stop, systemd, etc.).# Option : sauvegarder l’état actuel avant restore mysqldump -u USER -p van_comptabilite > /backups/pre_restore_$(date +%F_%H%M).sql # Restauration gunzip -c /backups/van_comptabilite_YYYY-MM-DD_HHMM.sql.gz \ | mysql -u USER -p van_comptabilite # ou fichier non compressé mysql -u USER -p van_comptabilite < /backups/van_comptabilite_YYYY-MM-DD_HHMM.sql
GET /api/health puis un login + quelques lectures métier.uploads/)tar -czf /backups/uploads_$(date +%F).tar.gz -C /chemin/vers/backend uploads
cd /chemin/vers/backend tar -xzf /backups/uploads_YYYY-MM-DD.tar.gz # permissions lecture pour l’utilisateur du process Node
Écran VAN & intégrations → Sauvegarde / restauration.
van-compta-backup-AAAA-MM-JJ.json..json..env séparément dans un coffre (pas dans le même zip public que le SQL).prod, preprod).| Contrôle | Comment |
|---|---|
| API up | GET /api/health |
| DB up | Réponse health + logs démarrage Sequelize |
| Auth | Login → cookies posés → GET /api/auth/me |
| CORS | Front prod appelle API sans erreur Origin |
| Médias | Image logo/produit charge via URL signée ou session |
| Intégrations | Appel sans clé → 401 ; avec clé → OK |
| Symptôme | Pistes |
|---|---|
| API refuse de démarrer en prod | Secrets faibles, CORS * → voir validateProductionEnv.js |
| Utilisateur déconnecté en boucle | Secrets JWT changés, cookies bloqués, SameSite / Secure |
| CORS error navigateur | CORS_ORIGIN ne contient pas l’origine exacte du front |
| Images 401 | Signature expirée ou session absente ; vérifier MEDIA_URL_SECRET |
| Données d’une autre société | Vérifier header X-Company-Id / société active |
| Facture Impayée après écriture | Écriture de facturation ≠ règlement ; passer par paiements |
| Commande | Usage |
|---|---|
npm run dev | API + nodemon |
npm start | API production |
npm run db:seed | Bootstrap données |
npm run db:repair:* | Scripts de réparation compta / stock / documents |
yarn audit / npm audit notés (résidus connus : xlsx, CRA)
MySQL 8 via Sequelize 6 — convention underscored: true + timestamps
(created_at / updated_at). Source :
backend/src/models/ (47 modèles métier).
Base typique : van_comptabilite.
company_id. Les accès API filtrent systématiquement sur la société active.
erDiagram
COMPANY ||--o{ USER : emploie
USER ||--o{ REFRESH_TOKEN : sessions
COMPANY ||--o{ ACCOUNT : plan
COMPANY ||--o{ JOURNAL : journaux
COMPANY ||--o{ CLIENT : clients
COMPANY ||--o{ SUPPLIER : fournisseurs
COMPANY ||--o{ PRODUCT : articles
SUPPLIER ||--o{ PURCHASE_ORDER : commande
PURCHASE_ORDER ||--|{ PURCHASE_ORDER_LINE : lignes
PURCHASE_ORDER ||--o{ GOODS_RECEIPT : reception
GOODS_RECEIPT ||--|{ GOODS_RECEIPT_LINE : lignes
GOODS_RECEIPT ||--o{ PURCHASE_INVOICE : facture
PURCHASE_INVOICE ||--|{ PURCHASE_INVOICE_LINE : lignes
PRODUCT ||--o{ STOCK_MOVEMENT : mouvements
CLIENT ||--o{ SALES_QUOTE : devis
SALES_QUOTE ||--o| SALES_ORDER : transforme
SALES_ORDER ||--o{ DELIVERY_NOTE : livraison
DELIVERY_NOTE ||--o{ SALES_INVOICE : facture
JOURNAL ||--o{ ACCOUNTING_ENTRY : pieces
ACCOUNTING_ENTRY ||--|{ ENTRY_LINE : lignes
ENTRY_LINE }o--|| ACCOUNT : impute
PAYMENT ||--o{ PAYMENT_ALLOCATION : lettrage
PAYMENT_ALLOCATION }o--o| SALES_INVOICE : client
PAYMENT_ALLOCATION }o--o| PURCHASE_INVOICE : fournisseur
BANK_ACCOUNT ||--o{ PAYMENT : tresorerie
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| Company | companies | name tradeName email phone address taxId rccm country currency logoUrl parentId isGroup isActive timezone fiscalYearStart vatRate |
| User | users | companyId fullName email passwordHash role permissions isActive tokenVersion |
| RefreshToken | refresh_tokens | userId tokenHash expiresAt revokedAt replacedByTokenHash userAgent ipAddress |
| AuditLog | audit_logs | companyId userId entity entityId action beforeData afterData |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| Account | accounts | companyId number name classCode reportingType isCollective isActive |
| Journal | journals | companyId code name defaultAccountId treasuryType treasuryAccountId sectionId |
| FiscalYear | fiscal_years | companyId code name startDate endDate status |
| AccountingPeriod | accounting_periods | companyId fiscalYearId period label startDate endDate status closedAt closedBy closingNote totalDebit totalCredit resultNet entryCount checksJson |
| Section | sections | companyId code name centreType parentId budgetAmount description isActive sortOrder |
| AnalyticPost | analytic_posts | companyId sectionId code name description nature budgetAmount isActive |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| AccountingEntry | accounting_entries | companyId journalId fiscalYearId number entryDate reference label sourceType sourceId status totalDebit totalCredit sectionId currency exchangeRate |
| EntryLine | entry_lines | entryId accountId clientId supplierId label debit credit counterpartAccountId sectionId analyticPostId projectId currency amountFc exchangeRate |
| EntryLineAnalytic | entry_line_analytics | entryLineId sectionId analyticPostId percentage debit credit projectId label |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| Client | clients | companyId code name email phone address bp taxId rccm vatRegime family paymentMethod creditLimit contactName contactRole bankAccount capitalAmount collectiveAccountId thirdPartyAccountNumber linkedCompanyId |
| Supplier | suppliers | companyId code name email phone address bp paymentTermDays paymentMethod taxId vatRegime rib bankAccount hasVat family contactName contactRole capitalAmount collectiveAccountId thirdPartyAccountNumber linkedCompanyId |
| Product | products | companyId code sku name description imageUrl basePurchasePrice baseSalePrice trackStock stockQuantity purchaseAccountId saleAccountId stockAccountId |
| SupplierPrice | supplier_prices | companyId supplierId productId price currency |
| StockMovement | stock_movements | companyId productId sourceType sourceId sectionId movementDate quantity unitCost notes |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| PurchaseOrder | purchase_orders | companyId supplierId fiscalYearId sectionId number orderDate status currency notes subtotal taxAmount totalAmount |
| PurchaseOrderLine | purchase_order_lines | purchaseOrderId productId description lineLabel sectionId quantity receivedQuantity unitPrice taxRate lineTotal |
| GoodsReceipt | goods_receipts | companyId supplierId purchaseOrderId sectionId number receiptDate status notes |
| GoodsReceiptLine | goods_receipt_lines | goodsReceiptId purchaseOrderLineId productId description lineLabel sectionId quantityReceived unitPrice taxRate |
| PurchaseInvoice | purchase_invoices | companyId supplierId goodsReceiptId purchaseOrderId journalId sectionId number invoiceDate dueDate status notes subtotal taxAmount totalAmount balanceDue |
| PurchaseInvoiceLine | purchase_invoice_lines | purchaseInvoiceId goodsReceiptLineId productId description lineLabel sectionId quantity unitPrice taxRate lineTotal |
| SupplierCreditNote | supplier_credit_notes | companyId supplierId purchaseInvoiceId number reference reason creditDate amount status |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| SalesQuote | sales_quotes | companyId clientId sectionId number quoteDate validUntil status subtotal taxAmount totalAmount |
| SalesQuoteLine | sales_quote_lines | salesQuoteId productId description quantity unitPrice taxRate lineTotal |
| SalesOrder | sales_orders | companyId clientId salesQuoteId sectionId number orderDate status subtotal taxAmount totalAmount |
| SalesOrderLine | sales_order_lines | salesOrderId productId description quantity deliveredQuantity unitPrice taxRate lineTotal |
| DeliveryNote | delivery_notes | companyId clientId salesOrderId sectionId number deliveryDate status |
| DeliveryNoteLine | delivery_note_lines | deliveryNoteId salesOrderLineId productId quantityDelivered unitPrice |
| SalesInvoice | sales_invoices | companyId clientId deliveryNoteId salesOrderId journalId sectionId number invoiceDate dueDate status subtotal taxAmount totalAmount balanceDue |
| SalesInvoiceLine | sales_invoice_lines | salesInvoiceId deliveryNoteLineId productId description quantity unitPrice taxRate lineTotal |
| CustomerCreditNote | customer_credit_notes | companyId clientId salesInvoiceId number reference reason creditDate amount status |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| BankAccount | bank_accounts | companyId accountId code name institution accountNumber openingBalance currentBalance |
| Payment | payments | companyId bankAccountId journalId clientId supplierId sectionId number paymentDate method reference amount status |
| PaymentAllocation | payment_allocations | paymentId purchaseInvoiceId salesInvoiceId customerCreditNoteId supplierCreditNoteId allocatedAmount |
| BankReconciliation | bank_reconciliations | companyId bankAccountId fiscalYearId statementDate statementBalance bookBalance difference status |
| CashForecast | cash_forecasts | companyId bankAccountId sectionId forecastDate horizon category label expectedAmount actualAmount status sourceType sourceId note |
| ExchangeRate | exchange_rates | companyId fromCurrency toCurrency rate rateDate source note |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| FixedAsset | fixed_assets | companyId accountId depreciationAccountId expenseAccountId sectionId code name family acquisitionDate commissionDate grossValue usefulLifeMonths salvageValue depreciationMethod cumulativeDepreciation disposalDate disposalValue status reference location description |
| Depreciation | depreciations | companyId fixedAssetId accountingEntryId periodDate amount |
| VatDeclaration | vat_declarations | companyId fiscalYearId periodStart periodEnd collectedVat deductibleVat netVat status |
| Modèle | Table (approx.) | Champs clés |
|---|---|---|
| Budget | budgets | companyId fiscalYearId sectionId analyticPostId projectId accountId period periodType nature label amount note |
| Project | projects | companyId sectionId clientId code name status description startDate endDate budgetRevenue budgetExpense location reference isActive |
| ProjectCostLine | project_cost_lines | projectId analyticPostId accountId label category budgetAmount actualAmount unit quantity unitPrice date note |
| InterCompanyTransaction | inter_company_transactions | sellerCompanyId buyerCompanyId sourceType sourceId sourceRef transactionDate fiscalYear nature amount currency amountXAF sellerAccountNumber buyerAccountNumber eliminationStatus note |
| Flux | Chaîne FK |
|---|---|
| Achats | purchase_orders → goods_receipts → purchase_invoices → payments / payment_allocations |
| Ventes | sales_quotes → sales_orders → delivery_notes → sales_invoices → payments / payment_allocations |
| Stock | goods_receipts / delivery_notes → stock_movements (product_id) |
| Compta auto | documents → accounting_entries (source_type + source_id) → entry_lines |
Les écritures automatiques sont dédupliquées par couple
source_type + source_id sur accounting_entries
(service ensureEntry).
État des packages déclarés dans package.json (front) et
backend/package.json. Gestionnaire front recommandé : Yarn
(yarn.lock). Backend : npm.
| Package | Version | Type |
|---|---|---|
ajv | ^8.20.0 | prod |
ajv-keywords | ^5.1.0 | prod |
axios | ^1.18.1 | prod |
jspdf | ^4.2.1 | prod |
jspdf-autotable | ^5.0.8 | prod |
react | ^18.2.0 | prod |
react-dom | ^18.2.0 | prod |
react-router-dom | ^6.28.0 | prod |
react-scripts | 5.0.1 | prod |
xlsx | ^0.18.5 | prod |
| Package | Version forcée | Type |
|---|---|---|
nth-check | ^2.0.1 | resolution Yarn |
shell-quote | ^1.10.0 | resolution Yarn |
form-data | ^4.0.6 | resolution Yarn |
ws | ^8.21.1 | resolution Yarn |
serialize-javascript | ^7.0.5 | resolution Yarn |
websocket-driver | ^0.7.5 | resolution Yarn |
axios | ^1.18.1 | resolution Yarn |
jspdf | ^4.2.1 | resolution Yarn |
underscore | ^1.13.8 | resolution Yarn |
postcss | ^8.5.10 | resolution Yarn |
uuid | ^11.1.1 | resolution Yarn |
@tootallnate/once | ^3.0.1 | resolution Yarn |
xlsx : pas de correctif communautaire gratuit
(n’importer que des fichiers de confiance). webpack-dev-server via CRA :
impact limité au poste de développement.
| Package | Version | Type |
|---|---|---|
bcryptjs | ^2.4.3 | prod |
cors | ^2.8.5 | prod |
dotenv | ^16.4.5 | prod |
express | ^4.22.2 | prod |
jsonwebtoken | ^9.0.2 | prod |
morgan | ^1.11.0 | prod |
multer | ^2.1.1 | prod |
mysql2 | ^3.11.3 | prod |
sequelize | ^6.37.3 | prod |
xlsx-populate | ^1.21.0 | prod |
nodemon | ^3.1.4 | dev |
| Override npm | Version | |
|---|---|---|
uuid | ^11.1.1 | override |
| Lib | Rôle |
|---|---|
| react / react-dom / react-router-dom | UI SPA & navigation |
| react-scripts | Build / dev server CRA |
| axios | Client HTTP (cookies, refresh) |
| jspdf / jspdf-autotable | Exports PDF |
| xlsx | Import / export Excel côté navigateur |
| express | API HTTP |
| sequelize / mysql2 | ORM & driver MySQL |
| jsonwebtoken / bcryptjs | Auth JWT & hash MDP |
| multer | Uploads images |
| xlsx-populate | Exports Excel côté serveur (DSF…) |
| cors / morgan / dotenv | CORS, logs, configuration |
# Frontend yarn audit # Backend cd backend && npm audit