Issue #72: Étudier l’opportunité d’une matrice des droits dynamique (RBAC granulaire)
- State:
OPEN
- Milestone:
Jalon 4: Automation & Intégrations 📅
- Labels:
enhancement
- Assignees:
Unassigned
- Created:
2025-10-31
- Updated:
2025-11-13
- URL:
Description
## 🎯 Objectif
Étudier la faisabilité et l'opportunité de remplacer le système RBAC actuel basé sur des rôles fixes par une matrice de permissions dynamique et granulaire.
## 📋 Contexte actuel
### Système RBAC actuel (Role-Based Access Control)
KoproGo utilise actuellement **4 rôles prédéfinis** avec des permissions fixes :
| Rôle | Permissions | Limitations |
|------|-------------|-------------|
| **SuperAdmin** | Accès complet multi-tenant | Aucune limitation |
| **Syndic** | Gestion copropriété (owners, expenses, meetings) | Pas de modif structural data |
| **Accountant** | Saisie comptable, pointer paiements | Lecture seule sur reste |
| **Owner** | Lecture seule complète | Aucune modification |
**Documentation** : `docs/ROLE_PERMISSIONS_MATRIX.rst`
### Limites du système actuel
1. **Rigidité** : Impossible de créer des rôles personnalisés ou d'ajuster finement les permissions
2. **Scalabilité** : Ajout de nouveaux rôles = modification du code + migration base de données
3. **Besoins métier évolutifs** : Demandes pour Organization Admin, Building Manager (issue #71)
4. **Cas d'usage complexes** :
- Déléguer uniquement la gestion documentaire à un utilisateur
- Donner accès lecture/écriture aux expenses mais pas aux meetings
- Restreindre un syndic à certains immeubles uniquement
## 🆕 Proposition : Matrice des droits dynamique
### Concept
Remplacer le système de rôles fixes par un système de **permissions granulaires** assignables dynamiquement.
### Architecture proposée
#### 1. Table `permissions` (catalogue des permissions disponibles)
```sql
CREATE TABLE permissions (
id UUID PRIMARY KEY,
resource VARCHAR(50) NOT NULL, -- Ex: "buildings", "units", "owners"
action VARCHAR(20) NOT NULL, -- Ex: "create", "read", "update", "delete"
scope VARCHAR(20) NOT NULL, -- Ex: "all", "organization", "assigned"
description TEXT,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(resource, action, scope)
);
-- Exemples d'entrées :
-- ('buildings', 'create', 'all', 'Créer des immeubles dans toute la plateforme')
-- ('buildings', 'read', 'organization', 'Lire les immeubles de son organisation')
-- ('buildings', 'update', 'assigned', 'Modifier uniquement les immeubles assignés')
-- ('expenses', 'create', 'organization', 'Créer des charges dans son organisation')
-- ('expenses', 'mark_paid', 'organization', 'Marquer des charges comme payées')
```
#### 2. Table `roles` (définition dynamique des rôles)
```sql
CREATE TABLE roles (
id UUID PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE, -- Ex: "syndic", "accountant", "building_manager"
display_name VARCHAR(100) NOT NULL, -- Ex: "Gestionnaire de Copropriété"
description TEXT,
is_system BOOLEAN DEFAULT FALSE, -- TRUE = rôle système (non supprimable)
organization_id UUID, -- NULL = rôle global, UUID = rôle spécifique org
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
#### 3. Table `role_permissions` (assignation permissions → rôles)
```sql
CREATE TABLE role_permissions (
id UUID PRIMARY KEY,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
granted_at TIMESTAMP DEFAULT NOW(),
granted_by UUID REFERENCES users(id),
UNIQUE(role_id, permission_id)
);
```
#### 4. Table `user_assignments` (utilisateurs + contraintes de scope)
```sql
CREATE TABLE user_assignments (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
organization_id UUID REFERENCES organizations(id), -- Scope organisation
constraints JSONB, -- Contraintes additionnelles
-- Ex: {"building_ids": ["uuid1", "uuid2"], "unit_ids": [...]}
is_active BOOLEAN DEFAULT TRUE,
assigned_at TIMESTAMP DEFAULT NOW(),
assigned_by UUID REFERENCES users(id),
UNIQUE(user_id, role_id, organization_id)
);
```
### Exemples de configurations
#### Exemple 1 : Building Manager (gestionnaire de portefeuille)
```json
{
"role": "building_manager",
"permissions": [
{"resource": "buildings", "action": "read", "scope": "assigned"},
{"resource": "buildings", "action": "update", "scope": "assigned"},
{"resource": "owners", "action": "create", "scope": "assigned"},
{"resource": "owners", "action": "update", "scope": "assigned"},
{"resource": "expenses", "action": "create", "scope": "assigned"},
{"resource": "meetings", "action": "create", "scope": "assigned"}
],
"constraints": {
"building_ids": ["building-uuid-1", "building-uuid-2", "building-uuid-3"]
}
}
```
#### Exemple 2 : Document Manager (gestionnaire documents uniquement)
```json
{
"role": "document_manager",
"permissions": [
{"resource": "buildings", "action": "read", "scope": "organization"},
{"resource": "documents", "action": "create", "scope": "organization"},
{"resource": "documents", "action": "delete", "scope": "organization"}
]
}
```
## 🔍 Avantages et Inconvénients
### ✅ Avantages
1. **Flexibilité maximale** : Création de rôles personnalisés sans modification du code
2. **Granularité** : Permissions ajustables au niveau action + ressource + scope
3. **Scalabilité** : Nouveaux besoins = ajout de permissions en base, pas de déploiement
4. **Multi-tenant amélioré** : Chaque organisation peut définir ses propres rôles
5. **Audit trail** : Traçabilité de qui a donné quelles permissions à qui
6. **Interface admin** : UI pour configurer les rôles sans toucher au code
### ❌ Inconvénients
1. **Complexité accrue** :
- Logique de vérification des permissions plus complexe
- Plus de requêtes SQL (JOINs multiples)
- Risque de bugs dans la vérification des permissions
2. **Performance** :
- Latence accrue : chaque requête doit vérifier permissions dynamiquement
- Cache nécessaire pour maintenir P99 < 5ms
3. **Migration** :
- Migration des rôles actuels vers le nouveau système
- Rétrocompatibilité pendant la transition
4. **UX** :
- Interface de configuration complexe
- Risque de confusion pour les utilisateurs
5. **Tests** :
- Explosion du nombre de cas de tests
- Tests de non-régression critiques
## 🏗️ Implémentation envisagée
### Phase 1 : Étude et validation (2-3 jours)
- [ ] Valider le besoin métier avec utilisateurs pilotes
- [ ] Benchmark performance : comparer latence système actuel vs dynamique
- [ ] Définir périmètre des permissions (liste exhaustive)
- [ ] Concevoir l'interface admin de configuration des rôles
### Phase 2 : Backend core (1 semaine)
- [ ] Migrations PostgreSQL (4 nouvelles tables)
- [ ] Domain entities : `Permission`, `Role`, `RolePermission`, `UserAssignment`
- [ ] Repositories (ports + impls)
- [ ] Use cases :
- `create_role`, `update_role_permissions`
- `assign_role_to_user`, `check_user_permission`
- [ ] Middleware : remplacer `AuthenticatedUser.role` par `AuthenticatedUser.check_permission()`
- [ ] Cache : Redis/DragonflyDB pour cache des permissions par user
### Phase 3 : Migration et handlers (1 semaine)
- [ ] Script de migration : mapper rôles actuels → nouvelles permissions
- [ ] Adapter tous les handlers pour utiliser `check_permission()`
- [ ] Rétrocompatibilité : garder l'ancien système en parallèle (feature flag)
### Phase 4 : Frontend admin UI (1 semaine)
- [ ] Page "Gestion des Rôles" : CRUD rôles personnalisés
- [ ] Interface glisser-déposer : assigner permissions aux rôles
- [ ] Page "Assignation Utilisateurs" : assigner rôles + contraintes
- [ ] Prévisualisation : "Ce rôle peut faire X, Y mais pas Z"
### Phase 5 : Tests et documentation (3 jours)
- [ ] Tests unitaires : validation des permissions
- [ ] Tests d'intégration : vérification end-to-end
- [ ] Tests de performance : vérifier P99 < 5ms maintenu
- [ ] Documentation complète : guide admin + guide développeur
## 📊 Alternatives
### Alternative 1 : Système hybride (rôles fixes + permissions additionnelles)
- Garder les 4 rôles actuels comme base
- Ajouter une colonne JSONB `extra_permissions` sur `user_roles`
- Permissions additionnelles = extension du rôle de base
**Avantages** : Migration progressive, simplicité relative
**Inconvénients** : Moins flexible, pas de rôles complètement custom
### Alternative 2 : Étendre le système actuel avec plus de rôles fixes
- Ajouter Organization Admin, Building Manager, Document Manager, etc.
- Rester sur le système de rôles fixes mais en augmenter le nombre
**Avantages** : Simplicité, performance maintenue
**Inconvénients** : Rigidité, scalabilité limitée
### Alternative 3 : Utiliser une librairie existante (Casbin, Oso)
- Intégrer une solution RBAC/ABAC tierce (ex: Casbin pour Rust)
- Déléguer la logique de permissions à une librairie éprouvée
**Avantages** : Robustesse, gain de temps
**Inconvénients** : Dépendance externe, courbe d'apprentissage
## ✅ Critères de décision
- [ ] **Besoin métier validé** : Les utilisateurs ont-ils réellement besoin de cette flexibilité ?
- [ ] **Performance acceptable** : P99 < 5ms maintenu même avec système dynamique ?
- [ ] **Complexité justifiée** : Le gain de flexibilité vaut-il l'effort d'implémentation ?
- [ ] **Maintenabilité** : L'équipe peut-elle maintenir ce système à long terme ?
- [ ] **ROI** : Valeur ajoutée vs coût de développement (estimation 3-4 semaines)
## 📈 Métriques de succès
Si implémentation validée :
- **Performance** : P99 latency < 5ms maintenu
- **Flexibilité** : 5+ rôles personnalisés créés par utilisateurs pilotes
- **Adoption** : 80%+ des organisations utilisent au moins 1 rôle custom
- **Stabilité** : 0 bug critique lié aux permissions sur 3 mois post-release
## 📚 Références
- Documentation actuelle : `docs/ROLE_PERMISSIONS_MATRIX.rst`
- Issue connexe : #71 (Organization Admin et Building Manager)
- Multi-role support : `docs/MULTI_ROLE_SUPPORT.md`
- Casbin (Rust) : https://github.com/casbin/casbin-rs
- Oso (Authorization library) : https://www.osohq.com/
## 📅 Priorité
**Faible à Moyen** :
- Pas bloquant pour MVP
- Valeur ajoutée importante si besoin métier confirmé
- Effort conséquent (3-4 semaines)
- Décision à prendre après validation utilisateurs
---
**Next Steps** :
1. Validation métier : interviews utilisateurs pilotes (syndics gérant >10 immeubles)
2. Benchmark performance : POC avec système dynamique
3. Décision go/no-go basée sur critères ci-dessus
4. Si GO → planifier sprint dédié (4 semaines)