Plateforme complète de gestion du cycle de vie contractuel : de la demande initiale jusqu'à la signature, l'exécution et le suivi post-contrat. Le projet couvre l'ensemble du parcours — création de dossier, vérification documentaire assistée par IA, workflow de validation configurable, conformité SLA, reporting — pour des organisations qui traitent un volume important de contrats avec des tiers (prestataires, partenaires, collectivités, particuliers).
Le dépôt contient deux applications indépendantes communiquant par API REST :
clm/
├── clm_backend/ # API Flask (Python) + tâches asynchrones Celery
└── clm_frontend/ # Application Angular 18 (SPA)
- Vue d'ensemble fonctionnelle
- Architecture technique
- Backend — Flask
- Frontend — Angular
- Démarrage rapide
- Déploiement
- Variables d'environnement
- Modèle de données
- Sécurité
- Tests
- Maintenance et conventions
| Profil | Rôle dans le cycle de vie |
|---|---|
| Demandeur (interne ou externe) | Crée une demande de contrat, complète son profil, fournit les pièces justificatives, suit l'avancement |
| Juriste | Traite les dossiers qui lui sont affectés : checklist de conformité, analyse de risques, échanges avec le demandeur |
| Responsable juridique | Valide les dossiers, affecte les juristes, supervise la charge de travail de l'équipe |
| Directeur | Valide les dossiers à enjeu élevé (au-delà d'un seuil configurable) |
| Superviseur SLA | Suit les délais contractuels et les dépassements à l'échelle de l'organisation |
| Gestionnaire de contrats | Gère les contrats actifs après signature : échéances, avenants, renouvellements |
| Auditeur | Accès en lecture au journal d'audit et aux indicateurs |
| Administrateur | Configure l'intégralité du système (voir ci-dessous) |
- Création — le demandeur choisit un type de structure (personne physique, société, ONG, institution publique…) puis un type de contrat. Des formulaires dynamiques et une liste de documents requis sont générés automatiquement selon la configuration.
- Soumission — validation des champs obligatoires et des documents, génération d'une référence unique.
- Analyse IA — extraction du contenu des documents (OCR si nécessaire), détection d'anomalies (document manquant, illisible, expiré), calcul d'un score de conformité, classification automatique du niveau de risque.
- Affectation — un juriste est désigné, manuellement ou automatiquement selon la charge de travail et l'expertise requise.
- Workflow de validation — le dossier traverse les étapes configurées (juriste → responsable → direction → signature), chacune avec son propre délai SLA, ses actions autorisées (valider, refuser, demander un complément, escalader) et son acteur responsable.
- Règles métier automatiques — un moteur de règles (BRE) déclenche des actions (affectation spécialisée, étape supplémentaire, alerte, changement de priorité) en fonction de conditions sur les données du dossier.
- Signature et activation — passage en suivi post-signature : numéro de contrat, échéances, gestion des avenants.
Toute la logique métier est pilotée par configuration depuis l'interface d'administration, sans déploiement :
- Organisations — entités juridiques multi-tenant, avec leur propre charte (couleurs, jours fériés, horaires de travail).
- Types de structures — profils de demandeurs avec champs et documents requis propres à chaque catégorie (personne physique, société, ONG, institution publique, organisation internationale, cabinet/profession libérale…).
- Types de contrats — catalogue de contrats avec formulaire dynamique, documents requis, seuil d'approbation direction, workflow associé.
- Workflows — éditeur d'étapes et de transitions (qui valide, quelles actions sont permises, délai SLA par étape).
- Règles métier (BRE) — conditions et actions automatiques déclenchées par événement (dossier créé, étape franchie, analyse IA terminée…).
- Configuration SLA — délais par type de contrat, priorité, étape de workflow, avec calcul en jours ouvrés ou calendaires.
- Checklists et modèles de notification — réutilisables, paramétrables par canal (email, SMS, in-app, WhatsApp).
- Utilisateurs, rôles, permissions, groupes — contrôle d'accès granulaire.
┌─────────────────┐ HTTPS / REST + WebSocket ┌──────────────────┐
│ clm_frontend │ ───────────────────────────────────▶ │ clm_backend │
│ Angular 18 SPA │ ◀─────────────────────────────────── │ Flask API │
└─────────────────┘ └─────────┬────────┘
│
┌───────────────────────────────────┼────────────────────┐
│ │ │
┌─────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ PostgreSQL │ │ Redis │ │ MinIO │
│ (externe) │ │ (cache, │ │ (stockage │
│ │ │ queue, rate │ │ documents) │
│ │ │ limit) │ │ (externe) │
└────────────┘ └──────┬──────┘ └─────────────┘
│
┌─────▼─────┐
│ Celery │
│ worker + │
│ beat │
└────────────┘
- PostgreSQL et MinIO (stockage objet S3-compatible pour les documents) sont
des services externes, non gérés par les
docker-compose.ymlfournis — à provisionner séparément. - Redis sert de broker Celery, de cache et de backend pour le rate limiting.
- Celery worker + beat exécutent les tâches asynchrones (analyse IA, envoi de notifications, vérification des SLA, alertes d'expiration de contrat).
- Flask + Flask-SQLAlchemy (ORM) + Flask-Migrate (Alembic)
- Flask-JWT-Extended pour l'authentification par jeton (access + refresh)
- Flask-SocketIO pour les notifications temps réel
- Celery + Redis pour les tâches asynchrones et planifiées
- MinIO (client
minio) pour le stockage des documents - OpenAI API pour l'analyse IA des documents et l'assistant juridique
- python-ldap pour l'authentification LDAP/Active Directory optionnelle
- pyotp pour l'authentification à deux facteurs (TOTP)
- structlog pour les logs structurés JSON
- Gunicorn (worker
eventlet, requis pour Socket.IO) en production
clm_backend/
├── app/
│ ├── api/v1/ # Blueprints REST (auth, users, organizations, contracts,
│ │ # workflows, documents, notifications, sla, kpi, admin, ai)
│ ├── models/ # Modèles SQLAlchemy (user, organization, contract,
│ │ # workflow, notification)
│ ├── services/ # Logique métier (auth, contract, business_rule, sla,
│ │ # ai, document, dynamic_form, kpi, notification, storage)
│ ├── tasks/ # Tâches Celery (ai, notifications, sla, maintenance, reports)
│ ├── utils/ # Décorateurs (permissions, audit), validateurs
│ └── celery_app.py # Configuration Celery + planification (beat)
├── migrations/ # Migrations Alembic
├── scripts/seed_data.py # Peuplement des données de référence
├── tests/ # Suite pytest
├── docker/ # Entrypoint, configuration Nginx
├── config.py # Configuration par environnement
├── wsgi.py # Point d'entrée Gunicorn
└── docker-compose.yml
| Préfixe | Contenu |
|---|---|
/auth |
Inscription, connexion (mot de passe, LDAP), OTP, rafraîchissement de jeton, réinitialisation de mot de passe |
/users |
CRUD utilisateurs, délégations, rôles, permissions, groupes |
/organizations |
Organisations, départements, types de structures, champs dynamiques, profils demandeurs |
/contracts |
Types de contrats, dossiers (création → soumission → workflow), checklist, risques, contrats actifs, avenants |
/workflows |
Workflows, étapes, transitions, règles métier (BRE), configurations SLA |
/documents |
Téléversement, validation, lien de téléchargement présigné |
/notifications |
Centre de notifications, modèles, tâches, vue calendrier |
/sla |
Statut SLA d'un dossier, suspension/reprise, statistiques de conformité, dossiers en dépassement |
/kpi |
Tableaux de bord (général, juriste, management), rapports personnalisés, export CSV |
/admin |
Journal d'audit, données de référence, paramètres système, amorçage (bootstrap) |
/ai |
Analyse de dossier/document, assistant conversationnel, comparaison de documents, génération de clauses |
Chaque règle est déclenchée par un événement (REQUEST_CREATED, STEP_CHANGED,
AI_ANALYSIS_COMPLETE, SLA_EXCEEDED…) et évalue une liste de conditions
(field, operator, value, logique AND/OR) sur le contexte du dossier
(request.*, contract_type.*, form_data.*). Si les conditions sont satisfaites,
les actions associées s'exécutent : affectation d'un juriste spécialisé, ajout d'une
étape de validation, changement de priorité ou de niveau de risque, notification d'un
rôle, blocage de la progression. Implémenté dans
app/services/business_rule_service.py.
| Tâche | Fréquence | Rôle |
|---|---|---|
check_sla_alerts |
toutes les 15 min | Alertes à 75/90/100 % du délai SLA, escalade automatique en cas de dépassement |
check_contract_expiries |
quotidienne | Alertes d'échéance de contrat (180/90/60/30/7 jours) et de jalons |
send_scheduled_reports |
quotidienne | Envoi des rapports programmés (quotidien/hebdo/mensuel) |
cleanup_expired_tokens |
quotidienne | Purge des jetons JWT révoqués expirés |
check_overdue_tasks |
horaire | Marquage des tâches en retard et notification |
- Angular 18 — composants standalone, signals, nouvelle syntaxe de contrôle de
flux (
@if/@for) - PrimeNG 18 + Tailwind CSS 3 pour l'interface
- Chart.js pour les graphiques de tableau de bord
- Socket.IO client pour les notifications en temps réel
- date-fns, jwt-decode comme utilitaires
clm_frontend/src/app/
├── core/
│ ├── models/ # Interfaces TypeScript miroir des modèles backend
│ ├── services/ # Un service HTTP par domaine
│ ├── guards/ # authGuard, permissionGuard, guestGuard
│ ├── interceptors/ # JWT, rafraîchissement de jeton, toasts d'erreur
│ ├── constants/ # Codes de permission, configuration de navigation
│ └── theme/ # Preset PrimeNG personnalisé
├── layout/ # Shell applicatif, sidebar dynamique, topbar, panneau de notifications
├── shared/ # Composants réutilisables (jauge SLA, badges, formulaires dynamiques…)
└── features/ # Un dossier par domaine fonctionnel
├── auth/ # Connexion, inscription, OTP, LDAP, mot de passe, amorçage
├── dashboard/ # 4 vues selon le profil
├── contracts/ # Liste, assistant de création, détail (6 onglets), contrats actifs
├── documents/, sla/, kpi/, notifications/, ai/, delegations/, profile/
└── admin/ # Organisations, structures, types de contrats, workflows,
# règles métier, SLA, checklists, utilisateurs, rôles, groupes,
# audit, paramètres
- Navigation adaptative : la barre latérale s'ajuste dynamiquement selon le profil et les permissions effectives de l'utilisateur connecté, sans build séparé par profil.
- Formulaires dynamiques : un moteur générique (
shared/components/dynamic-form) construit les champs (texte, date, liste déroulante, montant + devise, adresse, fichier…) à partir de la configuration retournée par l'API, avec gestion des conditions d'affichage. - Lazy-loading systématique par fonctionnalité pour garder le bundle initial léger (~160 Ko gzippé) malgré la richesse fonctionnelle.
- Jauge SLA (
shared/components/sla-gauge) — élément visuel récurrent du produit, cercle ou barre dont la couleur évolue selon le pourcentage de délai consommé. - Configuration runtime sans rebuild : l'URL de l'API est injectée au démarrage du
conteneur Docker via
docker/env.sh, ce qui permet de déployer la même image sur plusieurs environnements.
- Python 3.11+, Node.js 20+
- PostgreSQL accessible (local ou distant)
- MinIO accessible (ou autre stockage compatible S3)
- Redis (fourni par le
docker-compose.ymldu backend, ou local)
cd clm_backend
cp .env.example .env
# Renseigner DATABASE_URL, MINIO_*, SECRET_KEY, JWT_SECRET_KEY, etc.
pip install -r requirements.txt
# Création du schéma (si aucune migration n'existe encore dans migrations/versions/)
flask db migrate -m "initial schema"
flask db upgrade
# Peuplement des données de référence (rôles, permissions, structures, workflow par défaut…)
python scripts/seed_data.py
# Démarrage
python wsgi.py
# ou, pour le worker Celery dans un autre terminal :
celery -A celery_worker.celery_app worker --loglevel=info
celery -A celery_worker.celery_app beat --loglevel=infoL'API écoute par défaut sur http://localhost:5000. Le premier compte administrateur
se crée via POST /api/v1/admin/bootstrap/init (ou le formulaire /auth/bootstrap
côté frontend) — il faut au préalable que le seed ait créé le rôle SUPER_ADMIN.
cd clm_frontend
npm install
npm startDisponible sur http://localhost:4200, pointant par défaut vers
http://localhost:5000/api/v1 (voir src/environments/environment.ts).
Les deux applications fournissent un Dockerfile et un docker-compose.yml
indépendants.
cd clm_backend
cp .env.example .env # configurer DATABASE_URL, MINIO_*, FRONTEND_URL, etc.
docker compose up -d --buildServices démarrés : api (Gunicorn + worker eventlet), worker (Celery),
beat (Celery scheduler), flower (monitoring Celery, optionnel), redis,
nginx (reverse-proxy avec limitation de débit). PostgreSQL et MinIO restent
externes — pointer DATABASE_URL et MINIO_ENDPOINT vers vos instances.
cd clm_frontend
cp .env.example .env # configurer CLM_API_URL vers l'API accessible depuis le navigateur
docker compose up -d --buildBuild Angular multi-stage servi par Nginx. L'URL de l'API est injectée à l'exécution du conteneur (pas figée dans le bundle JS), ce qui permet de réutiliser la même image sur plusieurs environnements en changeant uniquement les variables d'environnement.
Deux approches possibles :
- Reverse-proxy commun (recommandé) : un Nginx/Traefik frontal route
/api/*et/socket.io/*vers le backend, et le reste vers le frontend. Dans ce cas,CLM_API_URL=/api/v1(chemin relatif) côté frontend. - Proxy intégré au conteneur frontend : décommenter les blocs
location /api/etlocation /socket.io/dansclm_frontend/docker/nginx/default.conf.
⚠️ Important :FRONTEND_URLcôté backend doit correspondre exactement à l'origine depuis laquelle le frontend est servi (protocole + hôte + port), sinon le navigateur bloquera les requêtes pour cause de CORS malgré une réponse200au preflightOPTIONS.
| Variable | Description |
|---|---|
SECRET_KEY, JWT_SECRET_KEY |
Clés de signature — à générer aléatoirement en production |
DATABASE_URL |
Connexion PostgreSQL |
REDIS_URL, CELERY_BROKER_URL, CELERY_RESULT_BACKEND |
Connexions Redis |
MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET |
Stockage des documents |
MAIL_* |
Configuration SMTP pour les notifications email |
TWILIO_* |
SMS (optionnel) |
LDAP_* |
Authentification LDAP/AD (optionnel, LDAP_ENABLED=false par défaut) |
OPENAI_API_KEY, OPENAI_MODEL, AI_ENABLED |
Fonctionnalités IA |
FRONTEND_URL |
Origine autorisée pour CORS — doit correspondre exactement à l'URL du frontend |
BASE_URL |
URL publique du backend, utilisée dans les liens générés (emails de vérification, réinitialisation) |
| Variable | Description | Défaut |
|---|---|---|
CLM_API_URL |
URL de l'API REST, accessible depuis le navigateur | /api/v1 |
CLM_SOCKET_URL |
URL du serveur Socket.IO | / |
FRONTEND_PORT |
Port local exposé par le conteneur | 8080 |
- Utilisateurs & accès :
User,Role,Permission,Group,Delegation,TokenBlocklist,AuditLog - Organisation :
Organization,Department,StructureType,DynamicField,RequiredDocument,RequesterProfile - Contrats :
ContractType,ContractRequest,RequestHistory,Comment,ChecklistItem/ChecklistTemplate,LegalRisk,ActiveContract,ContractMilestone,Amendment - Workflow :
Workflow,WorkflowStep,WorkflowTransition,StepExecution,BusinessRule,SLAConfig - Documents & notifications :
Document,NotificationTemplate,Notification,Task
Toutes les entités utilisent un identifiant UUID (chaîne) et un horodatage
created_at/updated_at ; la suppression est généralement logique (soft_delete)
plutôt que physique.
- Authentification par JWT (access + refresh), liste de révocation en base
(
TokenBlocklist) consultée à chaque requête. - 2FA (TOTP) optionnelle par utilisateur, avec QR code de provisionnement.
- LDAP/Active Directory en option, avec auto-provisionnement des comptes.
- Verrouillage de compte après 5 tentatives de connexion échouées (30 minutes).
- Limitation de débit (
Flask-Limiter) sur les routes sensibles (connexion, inscription, réinitialisation de mot de passe). - Contrôle d'accès par permissions granulaires, résolues à partir des rôles attribués
à l'utilisateur (
app/utils/decorators.pycôté backend,core/guards/permission.guard.tscôté frontend). - Journal d'audit (
AuditLog) pour les actions sensibles. - CORS strictement limité à l'origine déclarée dans
FRONTEND_URL.
# Backend
cd clm_backend
pytest
# Frontend
cd clm_frontend
npm testLa suite backend couvre notamment l'authentification, le moteur de règles métier,
la validation des formulaires dynamiques et le calcul des délais SLA
(clm_backend/tests/).
- Les modèles TypeScript (
clm_frontend/src/app/core/models/) sont un miroir direct des modèles Python (clm_backend/app/models/) ; toute évolution de l'API doit être répercutée des deux côtés. - Les codes de permission (
clm_frontend/src/app/core/constants/permissions.ts) doivent rester synchronisés avecclm_backend/scripts/seed_data.py. - Si
clm_backend/migrations/versions/est vide, exécuterflask db migrate -m "..."avantflask db upgrade: la commandeupgradeseule n'a aucun effet si aucune migration n'a encore été générée. - Le moteur de règles métier expose actuellement un éditeur de conditions/actions en JSON brut côté interface d'administration plutôt qu'un constructeur visuel avancé — fonctionnel mais perfectible.