feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles
- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD) * DEV: Clés TEST Pierre (mode test) * REC: Clés TEST Client (mode test) * PROD: Clés LIVE Client (mode live) - Ajout de la gestion des bases de données immeubles/bâtiments * Configuration buildings_database pour DEV/REC/PROD * Service BuildingService pour enrichissement des adresses - Optimisations pages et améliorations ergonomie - Mises à jour des dépendances Composer - Nettoyage des fichiers obsolètes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
473
api/scripts/orga/TODO-ISOLATION-OPERATIONS.md
Normal file
473
api/scripts/orga/TODO-ISOLATION-OPERATIONS.md
Normal file
@@ -0,0 +1,473 @@
|
||||
# TODO - Isolation complète des opérations
|
||||
|
||||
## 🎯 Objectif
|
||||
|
||||
Mettre en place une **isolation complète par opération** où chaque opération est totalement autonome et peut être supprimée indépendamment sans impacter les autres opérations ou la table centrale `users`.
|
||||
|
||||
## 📊 Architecture cible
|
||||
|
||||
```
|
||||
operations (id: 850)
|
||||
├── ope_users (id: 2500, fk_operation: 850, fk_user: 100)
|
||||
│ ├── ope_users_sectors (fk_user: 2500 ← ope_users.id, fk_sector: 5400)
|
||||
│ └── ope_pass (fk_user: 2500 ← ope_users.id, fk_sector: 5400)
|
||||
└── ope_sectors (id: 5400, fk_operation: 850)
|
||||
|
||||
users (id: 100) ← table centrale (conservée même si opération supprimée)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Tâche 1 : Modification du schéma SQL
|
||||
|
||||
### 📁 Fichier : `scripts/orga/fix_fk_constraints.sql`
|
||||
|
||||
### Actions
|
||||
|
||||
- [ ] **1.1** Tester le script SQL sur **dva_geo** (DEV)
|
||||
```bash
|
||||
incus exec dva-geo -- mysql rca_geo < /var/www/geosector/api/scripts/orga/fix_fk_constraints.sql
|
||||
```
|
||||
|
||||
- [ ] **1.2** Vérifier les contraintes après exécution :
|
||||
```sql
|
||||
SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'rca_geo'
|
||||
AND TABLE_NAME IN ('ope_users_sectors', 'ope_pass')
|
||||
AND COLUMN_NAME = 'fk_user';
|
||||
```
|
||||
Résultat attendu :
|
||||
- `ope_users_sectors.fk_user → ope_users.id`
|
||||
- `ope_pass.fk_user → ope_users.id`
|
||||
|
||||
- [ ] **1.3** Appliquer sur **rca_geo** (RECETTE) après validation sur dva_geo
|
||||
|
||||
- [ ] **1.4** Appliquer sur **pra_geo** (PRODUCTION) après validation sur rca_geo
|
||||
|
||||
### ⚠️ Important
|
||||
|
||||
- Les données existantes doivent être **nettoyées avant** d'appliquer le script
|
||||
- Ou bien : recréer toutes les données avec la nouvelle migration
|
||||
- Les FK `ON DELETE CASCADE` supprimeront automatiquement `ope_users_sectors` et `ope_pass` quand `ope_users` est supprimé
|
||||
|
||||
---
|
||||
|
||||
## ✅ Tâche 2 : Correction du script de migration2
|
||||
|
||||
### 📁 Fichiers concernés
|
||||
|
||||
1. `scripts/migration2/php/lib/SectorMigrator.php`
|
||||
2. `scripts/migration2/php/lib/PassageMigrator.php`
|
||||
|
||||
### Actions
|
||||
|
||||
#### 2.1 SectorMigrator.php - Migration de ope_users_sectors
|
||||
|
||||
- [ ] **Ligne 253** : Changer de `users.id` vers `ope_users.id`
|
||||
|
||||
```php
|
||||
// ❌ AVANT
|
||||
':fk_user' => $us['fk_user'], // ID de users (table centrale)
|
||||
|
||||
// ✅ APRÈS
|
||||
':fk_user' => $userMapping[$us['fk_user']], // ID de ope_users (mapping)
|
||||
```
|
||||
|
||||
#### 2.2 PassageMigrator.php - Migration de ope_pass
|
||||
|
||||
- [ ] **Ligne 64-67** : Vérifier le mapping existe
|
||||
- [ ] **Ligne 77** : Passer `ope_users.id` au lieu de `users.id`
|
||||
|
||||
```php
|
||||
// ❌ AVANT (ligne 77)
|
||||
$newPassId = $this->insertPassage($passage, $newOperationId, $newOpeSectorId, $passage['fk_user']);
|
||||
|
||||
// ✅ APRÈS
|
||||
$newOpeUserId = $userMapping[$passage['fk_user']];
|
||||
$newPassId = $this->insertPassage($passage, $newOperationId, $newOpeSectorId, $newOpeUserId);
|
||||
```
|
||||
|
||||
- [ ] **Ligne 164** : Utiliser le paramètre `$userId` qui sera maintenant `ope_users.id`
|
||||
|
||||
```php
|
||||
// ❌ AVANT
|
||||
':fk_user' => $userId, // ID de users (table centrale)
|
||||
|
||||
// ✅ APRÈS (le paramètre $userId contiendra déjà ope_users.id)
|
||||
':fk_user' => $userId, // ID de ope_users
|
||||
```
|
||||
|
||||
- [ ] **Ligne 71** : Corriger `verifyUserSectorAssociation` pour vérifier avec `ope_users.id`
|
||||
|
||||
```php
|
||||
// ❌ AVANT
|
||||
if (!$this->verifyUserSectorAssociation($newOperationId, $passage['fk_user'], $newOpeSectorId)) {
|
||||
|
||||
// ✅ APRÈS
|
||||
if (!$this->verifyUserSectorAssociation($newOperationId, $newOpeUserId, $newOpeSectorId)) {
|
||||
```
|
||||
|
||||
#### 2.3 Tester la migration complète
|
||||
|
||||
- [ ] **Sur dva_geo** : Vider les données d'une entité et relancer la migration
|
||||
```bash
|
||||
php php/migrate_from_backup.php --mode=entity --entity-id=5
|
||||
```
|
||||
|
||||
- [ ] **Vérifier** dans la base que :
|
||||
- `ope_users_sectors.fk_user` contient des IDs de `ope_users.id`
|
||||
- `ope_pass.fk_user` contient des IDs de `ope_users.id`
|
||||
- Les valeurs correspondent bien au mapping
|
||||
|
||||
- [ ] **Vérifier** qu'on peut supprimer une opération et que tout part avec (CASCADE)
|
||||
```sql
|
||||
DELETE FROM operations WHERE id = 850;
|
||||
-- Doit supprimer automatiquement :
|
||||
-- - ope_users (ON DELETE CASCADE depuis operations)
|
||||
-- - ope_users_sectors (ON DELETE CASCADE depuis ope_users)
|
||||
-- - ope_pass (ON DELETE CASCADE depuis ope_users)
|
||||
-- - ope_sectors (ON DELETE CASCADE depuis operations)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Tâche 3 : Vérifications API
|
||||
|
||||
### Impact sur les endpoints API
|
||||
|
||||
#### 3.1 Vérifier les requêtes utilisant `ope_pass.fk_user`
|
||||
|
||||
- [ ] **Rechercher** tous les endpoints qui lisent `ope_pass.fk_user`
|
||||
```bash
|
||||
grep -r "ope_pass.*fk_user" src/Controllers/
|
||||
grep -r "fk_user.*ope_pass" src/Controllers/
|
||||
```
|
||||
|
||||
- [ ] **Vérifier** que ces endpoints :
|
||||
- Font-ils des JOIN avec `users` via `ope_pass.fk_user` ?
|
||||
- Si OUI : Ajouter un JOIN via `ope_users` :
|
||||
```sql
|
||||
-- ❌ AVANT
|
||||
SELECT op.*, u.encrypted_name
|
||||
FROM ope_pass op
|
||||
JOIN users u ON op.fk_user = u.id
|
||||
|
||||
-- ✅ APRÈS
|
||||
SELECT op.*, u.encrypted_name
|
||||
FROM ope_pass op
|
||||
JOIN ope_users ou ON op.fk_user = ou.id
|
||||
JOIN users u ON ou.fk_user = u.id
|
||||
```
|
||||
|
||||
#### 3.2 Vérifier les requêtes utilisant `ope_users_sectors.fk_user`
|
||||
|
||||
- [ ] **Rechercher** tous les endpoints qui lisent `ope_users_sectors.fk_user`
|
||||
```bash
|
||||
grep -r "ope_users_sectors.*fk_user" src/Controllers/
|
||||
```
|
||||
|
||||
- [ ] **Vérifier** la même chose : si JOIN avec `users`, ajouter passage par `ope_users`
|
||||
|
||||
#### 3.3 Endpoints probablement concernés
|
||||
|
||||
À vérifier :
|
||||
- [ ] `OperationController` - Liste des utilisateurs d'une opération
|
||||
- [ ] `PassageController` - Liste/détails des passages
|
||||
- [ ] `SectorController` - Liste des secteurs avec utilisateurs affectés
|
||||
- [ ] Tout endpoint retournant des statistiques par utilisateur
|
||||
|
||||
---
|
||||
|
||||
## ✅ Tâche 4 : Corrections API - Response JSON Login
|
||||
|
||||
### Impact sur la réponse JSON du login
|
||||
|
||||
#### 4.1 Groupe `users_sectors` - Ajouter `ope_user_id`
|
||||
|
||||
**Problème identifié** : Flutter reçoit `users_sectors` avec `id` (users.id) mais les `passages` ont `fk_user` (ope_users.id). Le mapping est impossible.
|
||||
|
||||
**Solution** : Modifier la requête dans `LoginController.php` (lignes 426 et 1181) pour retourner les deux IDs :
|
||||
|
||||
```sql
|
||||
-- ✅ APRÈS
|
||||
SELECT DISTINCT
|
||||
u.id as user_id, -- users.id (table centrale, pour gestion membres)
|
||||
ou.id as ope_user_id, -- ope_users.id (pour lier avec passages/sectors)
|
||||
ou.first_name,
|
||||
u.encrypted_name,
|
||||
u.sect_name,
|
||||
us.fk_sector
|
||||
FROM users u
|
||||
JOIN ope_users ou ON u.id = ou.fk_user
|
||||
JOIN ope_users_sectors us ON ou.id = us.fk_user AND ou.fk_operation = us.fk_operation
|
||||
WHERE us.fk_sector IN ($sectorIdsString)
|
||||
AND us.fk_operation = ?
|
||||
AND us.chk_active = 1
|
||||
AND u.chk_active = 1
|
||||
AND u.id != ?
|
||||
```
|
||||
|
||||
**Résultat JSON attendu** :
|
||||
```json
|
||||
{
|
||||
"user_id": 123, // users.id (pour gestion des membres dans l'interface)
|
||||
"ope_user_id": 50, // ope_users.id (pour lier avec passages.fk_user et sectors)
|
||||
"first_name": "Jane",
|
||||
"name": "Jane Smith",
|
||||
"sect_name": "Smith",
|
||||
"fk_sector": 456
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Flutter** :
|
||||
```dart
|
||||
// Trouver les passages d'un utilisateur
|
||||
passages.where((p) => p.fkUser == usersSectors[i].opeUserId) // ✅ OK
|
||||
```
|
||||
|
||||
- [ ] **Modifier** `LoginController.php` ligne 426 (méthode `login()`)
|
||||
- [ ] **Modifier** `LoginController.php` ligne 1181 (méthode `checkSession()`)
|
||||
- [ ] **Tester** la réponse JSON du login en mode admin
|
||||
|
||||
---
|
||||
|
||||
## ✅ Tâche 5 : Vérifications Flutter - Gestion des IDs
|
||||
|
||||
### Impact sur l'application mobile
|
||||
|
||||
#### 5.1 Modèles de données
|
||||
|
||||
- [ ] **Vérifier** le modèle `UserSector` (ou équivalent)
|
||||
- Ajouter le champ `opeUserId` (int) pour stocker `ope_users.id`
|
||||
- Conserver `userId` (int) pour stocker `users.id`
|
||||
|
||||
- [ ] **Vérifier** le modèle `Passage` (ou équivalent)
|
||||
- Le champ `fkUser` pointe maintenant vers `ope_users.id`
|
||||
|
||||
#### 5.2 Gestion des secteurs (Mode Admin)
|
||||
|
||||
- [ ] **Création de secteur**
|
||||
- L'API crée dans `ope_sectors`
|
||||
- Attribution des users : utiliser `ope_user_id` (pas `user_id`)
|
||||
- Endpoint : `POST /api/sectors`
|
||||
- Body : `{ ..., users: [50, 51, 52] }` ← IDs de `ope_users`
|
||||
|
||||
- [ ] **Modification de secteur**
|
||||
- Attribution des users : utiliser `ope_user_id`
|
||||
- Endpoint : `PUT /api/sectors/:id`
|
||||
- Body : `{ ..., users: [50, 51, 52] }` ← IDs de `ope_users`
|
||||
|
||||
- [ ] **Suppression de secteur**
|
||||
- L'API supprime dans `ope_pass`, `ope_users_sectors` et `ope_sectors`
|
||||
- CASCADE gère automatiquement les dépendances
|
||||
- Endpoint : `DELETE /api/sectors/:id`
|
||||
|
||||
#### 5.3 Gestion des membres (Mode Admin)
|
||||
|
||||
- [ ] **Création de membre**
|
||||
- L'API crée dans `users` (table centrale)
|
||||
- L'API crée aussi dans `ope_users` pour l'opération active
|
||||
- **Réponse attendue** :
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"user": {
|
||||
"id": 123, // users.id
|
||||
"ope_user_id": 50, // ope_users.id (nouveau)
|
||||
"first_name": "John",
|
||||
"name": "John Doe",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
- Endpoint : `POST /api/users`
|
||||
- Flutter stocke les 2 IDs : `userId` et `opeUserId`
|
||||
|
||||
- [ ] **Modification de membre**
|
||||
- L'API met à jour `users` (table centrale)
|
||||
- L'API met à jour aussi `ope_users` pour l'opération active
|
||||
- Endpoint : `PUT /api/users/:id`
|
||||
|
||||
- [ ] **Suppression de membre**
|
||||
- L'API supprime de `ope_users` (opération active)
|
||||
- L'API supprime de `users` (table centrale)
|
||||
- CASCADE supprime automatiquement `ope_users_sectors` et `ope_pass`
|
||||
- Endpoint : `DELETE /api/users/:id?transfer_to=XX`
|
||||
|
||||
#### 5.4 Gestion des passages (Mode Admin & User)
|
||||
|
||||
- [ ] **Création de passage**
|
||||
- Attribution automatique du `ope_sectors.id` le plus proche
|
||||
- Attribution du `ope_users.id` (utilisateur connecté ou sélectionné)
|
||||
- Endpoint : `POST /api/passages`
|
||||
- Body : `{ ..., fk_user: 50, fk_sector: 456 }` ← IDs de `ope_users` et `ope_sectors`
|
||||
|
||||
- [ ] **Modification de passage**
|
||||
- Attribution du `ope_users.id` si changement d'utilisateur
|
||||
- Endpoint : `PUT /api/passages/:id`
|
||||
- Body : `{ ..., fk_user: 50 }` ← ID de `ope_users`
|
||||
|
||||
- [ ] **Suppression de passage**
|
||||
- L'API supprime dans `ope_pass`
|
||||
- Endpoint : `DELETE /api/passages/:id`
|
||||
|
||||
#### 5.5 Interface Flutter - Mapping des IDs
|
||||
|
||||
**Scénarios à gérer** :
|
||||
|
||||
1. **Affichage des secteurs avec utilisateurs affectés** :
|
||||
```dart
|
||||
// Utiliser usersSectors[i].opeUserId pour lier avec passages
|
||||
final userPassages = passages.where((p) =>
|
||||
p.fkUser == usersSectors[i].opeUserId &&
|
||||
p.fkSector == sector.id
|
||||
).toList();
|
||||
```
|
||||
|
||||
2. **Attribution d'un passage à un utilisateur** :
|
||||
```dart
|
||||
// Envoyer ope_user_id dans la requête API
|
||||
await apiService.createPassage({
|
||||
...passageData,
|
||||
'fk_user': userSector.opeUserId, // ope_users.id
|
||||
'fk_sector': sector.id
|
||||
});
|
||||
```
|
||||
|
||||
3. **Affichage du nom d'un utilisateur depuis un passage** :
|
||||
```dart
|
||||
// Chercher dans usersSectors avec ope_user_id
|
||||
final userSector = usersSectors.firstWhere(
|
||||
(us) => us.opeUserId == passage.fkUser,
|
||||
orElse: () => null
|
||||
);
|
||||
final userName = userSector?.name ?? 'Inconnu';
|
||||
```
|
||||
|
||||
4. **Gestion des membres** :
|
||||
```dart
|
||||
// Conserver les 2 IDs lors de la création
|
||||
final newMember = await apiService.createUser(userData);
|
||||
membres.add(Member(
|
||||
userId: newMember['id'], // users.id
|
||||
opeUserId: newMember['ope_user_id'], // ope_users.id
|
||||
...
|
||||
));
|
||||
```
|
||||
|
||||
#### 5.6 Tests d'affichage
|
||||
|
||||
- [ ] Tester l'affichage des passages avec noms d'utilisateurs
|
||||
- [ ] Tester l'affichage des secteurs avec utilisateurs affectés
|
||||
- [ ] Tester la création d'un membre (vérifier que les 2 IDs sont reçus)
|
||||
- [ ] Tester la suppression d'un membre (vérifier le transfert de passages)
|
||||
- [ ] Tester la création d'un secteur avec attribution d'utilisateurs
|
||||
- [ ] Tester la création d'un passage avec attribution d'utilisateur
|
||||
- [ ] Tester la suppression d'une opération (doit tout nettoyer)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Ordre d'exécution recommandé
|
||||
|
||||
1. ✅ **Corriger le code de migration2** (PHP)
|
||||
2. ✅ **Tester sur dva_geo** avec schéma modifié
|
||||
3. ✅ **Vérifier l'API** sur dva_geo
|
||||
4. ✅ **Vérifier Flutter** avec dva_geo
|
||||
5. 🚀 **Déployer le schéma SQL** sur rca_geo
|
||||
6. 🚀 **Déployer le code** sur rca_geo
|
||||
7. ✅ **Tester en recette**
|
||||
8. 🚀 **Déployer en production** (pra_geo)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Requêtes SQL utiles pour vérification
|
||||
|
||||
### Vérifier les contraintes FK actuelles
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND (TABLE_NAME = 'ope_pass' OR TABLE_NAME = 'ope_users_sectors')
|
||||
AND COLUMN_NAME = 'fk_user';
|
||||
```
|
||||
|
||||
### Vérifier l'intégrité des données après migration
|
||||
|
||||
```sql
|
||||
-- Vérifier que tous les fk_user de ope_pass existent dans ope_users
|
||||
SELECT COUNT(*) as orphans
|
||||
FROM ope_pass op
|
||||
LEFT JOIN ope_users ou ON op.fk_user = ou.id
|
||||
WHERE ou.id IS NULL;
|
||||
-- Résultat attendu : 0
|
||||
|
||||
-- Vérifier que tous les fk_user de ope_users_sectors existent dans ope_users
|
||||
SELECT COUNT(*) as orphans
|
||||
FROM ope_users_sectors ous
|
||||
LEFT JOIN ope_users ou ON ous.fk_user = ou.id
|
||||
WHERE ou.id IS NULL;
|
||||
-- Résultat attendu : 0
|
||||
```
|
||||
|
||||
### Tester la suppression en cascade
|
||||
|
||||
```sql
|
||||
-- Compter avant suppression
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM ope_users WHERE fk_operation = 850) as ope_users_count,
|
||||
(SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = 850) as ope_users_sectors_count,
|
||||
(SELECT COUNT(*) FROM ope_pass WHERE fk_operation = 850) as ope_pass_count,
|
||||
(SELECT COUNT(*) FROM ope_sectors WHERE fk_operation = 850) as ope_sectors_count;
|
||||
|
||||
-- Supprimer l'opération
|
||||
DELETE FROM operations WHERE id = 850;
|
||||
|
||||
-- Vérifier que tout a été supprimé (doit retourner 0 partout)
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM ope_users WHERE fk_operation = 850) as ope_users_count,
|
||||
(SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = 850) as ope_users_sectors_count,
|
||||
(SELECT COUNT(*) FROM ope_pass WHERE fk_operation = 850) as ope_pass_count,
|
||||
(SELECT COUNT(*) FROM ope_sectors WHERE fk_operation = 850) as ope_sectors_count;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes importantes
|
||||
|
||||
### Avantages de cette architecture
|
||||
|
||||
✅ **Isolation complète** : Supprimer une opération supprime tout (ope_users, secteurs, passages)
|
||||
✅ **Performance** : Pas de jointures complexes avec la table centrale `users`
|
||||
✅ **Historique** : Les données d'une opération sont figées dans le temps
|
||||
✅ **Simplicité** : Requêtes plus simples, moins de risques d'incohérences
|
||||
|
||||
### Implications
|
||||
|
||||
⚠️ **Duplication** : Un utilisateur travaillant sur 3 opérations aura 3 entrées dans `ope_users`
|
||||
⚠️ **Taille** : La table `ope_users` sera plus volumineuse
|
||||
⚠️ **Jointures** : Pour remonter aux infos de la table `users`, il faut passer par `ope_users.fk_user`
|
||||
|
||||
### Rétrocompatibilité
|
||||
|
||||
❌ Ce changement **CASSE** la compatibilité avec les données existantes
|
||||
✅ Nécessite une **re-migration complète** de toutes les entités après modification du schéma
|
||||
✅ Ou bien : script de transformation des données existantes (plus complexe)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Statut
|
||||
|
||||
- [ ] Schéma SQL modifié sur dva_geo
|
||||
- [ ] Code migration2 corrigé
|
||||
- [ ] API vérifiée et corrigée
|
||||
- [ ] Flutter vérifié et corrigé
|
||||
- [ ] Tests complets sur dva_geo
|
||||
- [ ] Déploiement rca_geo
|
||||
- [ ] Déploiement pra_geo
|
||||
65
api/scripts/orga/fix_fk_constraints.sql
Normal file
65
api/scripts/orga/fix_fk_constraints.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- ================================================================================
|
||||
-- Script de migration : Correction des contraintes FK pour isolation par opération
|
||||
-- ================================================================================
|
||||
--
|
||||
-- Ce script modifie les contraintes de clés étrangères pour que :
|
||||
-- - ope_users_sectors.fk_user → pointe vers ope_users.id (au lieu de users.id)
|
||||
-- - ope_pass.fk_user → pointe vers ope_users.id (au lieu de users.id)
|
||||
--
|
||||
-- Cela permet une isolation complète des opérations : supprimer une opération
|
||||
-- supprime automatiquement tous ses ope_users, ope_sectors, ope_users_sectors et ope_pass.
|
||||
--
|
||||
-- ORDRE D'EXÉCUTION :
|
||||
-- 1. dva_geo (DEV) - test
|
||||
-- 2. rca_geo (RECETTE)
|
||||
-- 3. pra_geo (PRODUCTION)
|
||||
--
|
||||
-- ================================================================================
|
||||
|
||||
USE dva_geo; -- Adapter selon l'environnement (dva_geo, rca_geo, pra_geo)
|
||||
|
||||
-- ================================================================================
|
||||
-- 1. Modification de ope_users_sectors.fk_user
|
||||
-- ================================================================================
|
||||
|
||||
-- Supprimer l'ancienne contrainte FK
|
||||
ALTER TABLE ope_users_sectors
|
||||
DROP FOREIGN KEY ope_users_sectors_ibfk_2;
|
||||
|
||||
-- Recréer la contrainte FK vers ope_users.id
|
||||
ALTER TABLE ope_users_sectors
|
||||
ADD CONSTRAINT ope_users_sectors_ibfk_2
|
||||
FOREIGN KEY (fk_user) REFERENCES ope_users (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ================================================================================
|
||||
-- 2. Modification de ope_pass.fk_user
|
||||
-- ================================================================================
|
||||
|
||||
-- Supprimer l'ancienne contrainte FK
|
||||
ALTER TABLE ope_pass
|
||||
DROP FOREIGN KEY ope_pass_ibfk_3;
|
||||
|
||||
-- Recréer la contrainte FK vers ope_users.id
|
||||
ALTER TABLE ope_pass
|
||||
ADD CONSTRAINT ope_pass_ibfk_3
|
||||
FOREIGN KEY (fk_user) REFERENCES ope_users (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ================================================================================
|
||||
-- Vérification finale
|
||||
-- ================================================================================
|
||||
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME IN ('ope_users_sectors', 'ope_pass')
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
-- Résultat attendu :
|
||||
-- ope_pass | fk_user | ope_pass_ibfk_3 | ope_users | id
|
||||
-- ope_users_sectors | fk_user | ope_users_sectors_ibfk_2 | ope_users | id
|
||||
121
api/scripts/orga/fix_fk_constraints_safe.sql
Normal file
121
api/scripts/orga/fix_fk_constraints_safe.sql
Normal file
@@ -0,0 +1,121 @@
|
||||
-- ================================================================================
|
||||
-- Script de migration SÉCURISÉ : Correction des contraintes FK pour isolation par opération
|
||||
-- ================================================================================
|
||||
--
|
||||
-- Ce script modifie les contraintes de clés étrangères pour que :
|
||||
-- - ope_users_sectors.fk_user → pointe vers ope_users.id (au lieu de users.id)
|
||||
-- - ope_pass.fk_user → pointe vers ope_users.id (au lieu de users.id)
|
||||
--
|
||||
-- Version SÉCURISÉE : Vérifie l'existence des contraintes avant de les supprimer
|
||||
--
|
||||
-- ================================================================================
|
||||
|
||||
USE dva_geo;
|
||||
|
||||
-- ================================================================================
|
||||
-- Afficher les contraintes FK actuelles
|
||||
-- ================================================================================
|
||||
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME IN ('ope_users_sectors', 'ope_pass')
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
-- ================================================================================
|
||||
-- 1. Modification de ope_users_sectors.fk_user
|
||||
-- ================================================================================
|
||||
|
||||
-- Supprimer l'ancienne contrainte FK si elle existe
|
||||
SET @constraint_exists = (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME = 'ope_users_sectors'
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
AND CONSTRAINT_NAME LIKE '%ibfk%'
|
||||
);
|
||||
|
||||
SET @sql = IF(@constraint_exists > 0,
|
||||
CONCAT('ALTER TABLE ope_users_sectors DROP FOREIGN KEY ',
|
||||
(SELECT CONSTRAINT_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME = 'ope_users_sectors'
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
AND CONSTRAINT_NAME LIKE '%ibfk%'
|
||||
LIMIT 1)),
|
||||
'SELECT "Aucune contrainte FK à supprimer sur ope_users_sectors" AS message'
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Recréer la contrainte FK vers ope_users.id
|
||||
ALTER TABLE ope_users_sectors
|
||||
ADD CONSTRAINT ope_users_sectors_ibfk_2
|
||||
FOREIGN KEY (fk_user) REFERENCES ope_users (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ================================================================================
|
||||
-- 2. Modification de ope_pass.fk_user
|
||||
-- ================================================================================
|
||||
|
||||
-- Supprimer l'ancienne contrainte FK si elle existe
|
||||
SET @constraint_exists = (
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME = 'ope_pass'
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
AND CONSTRAINT_NAME LIKE '%ibfk%'
|
||||
);
|
||||
|
||||
SET @sql = IF(@constraint_exists > 0,
|
||||
CONCAT('ALTER TABLE ope_pass DROP FOREIGN KEY ',
|
||||
(SELECT CONSTRAINT_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME = 'ope_pass'
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
AND CONSTRAINT_NAME LIKE '%ibfk%'
|
||||
LIMIT 1)),
|
||||
'SELECT "Aucune contrainte FK à supprimer sur ope_pass" AS message'
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- Recréer la contrainte FK vers ope_users.id
|
||||
ALTER TABLE ope_pass
|
||||
ADD CONSTRAINT ope_pass_ibfk_3
|
||||
FOREIGN KEY (fk_user) REFERENCES ope_users (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ================================================================================
|
||||
-- Vérification finale
|
||||
-- ================================================================================
|
||||
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME IN ('ope_users_sectors', 'ope_pass')
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
-- Résultat attendu :
|
||||
-- ope_pass | fk_user | ope_pass_ibfk_3 | ope_users | id
|
||||
-- ope_users_sectors | fk_user | ope_users_sectors_ibfk_2 | ope_users | id
|
||||
|
||||
SELECT '✓ Contraintes FK modifiées avec succès !' AS status;
|
||||
93
api/scripts/orga/truncate_all_tables.sql
Normal file
93
api/scripts/orga/truncate_all_tables.sql
Normal file
@@ -0,0 +1,93 @@
|
||||
-- ================================================================================
|
||||
-- Script de nettoyage complet des tables - DVA_GEO
|
||||
-- ================================================================================
|
||||
--
|
||||
-- Ce script vide toutes les tables pour repartir à zéro.
|
||||
-- ATTENTION : Toutes les données seront perdues !
|
||||
--
|
||||
-- Usage : À exécuter sur dva_geo UNIQUEMENT (environnement de développement)
|
||||
--
|
||||
-- ================================================================================
|
||||
|
||||
USE dva_geo;
|
||||
|
||||
-- Désactiver temporairement les vérifications de clés étrangères
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ================================================================================
|
||||
-- 1. Tables dépendantes (dans l'ordre des dépendances)
|
||||
-- ================================================================================
|
||||
|
||||
TRUNCATE TABLE ope_pass_histo;
|
||||
TRUNCATE TABLE ope_pass;
|
||||
TRUNCATE TABLE ope_users_sectors;
|
||||
TRUNCATE TABLE sectors_adresses;
|
||||
TRUNCATE TABLE ope_sectors;
|
||||
TRUNCATE TABLE ope_users;
|
||||
TRUNCATE TABLE medias;
|
||||
TRUNCATE TABLE operations;
|
||||
|
||||
-- ================================================================================
|
||||
-- 2. Tables liées aux utilisateurs
|
||||
-- ================================================================================
|
||||
|
||||
TRUNCATE TABLE user_devices;
|
||||
|
||||
-- ================================================================================
|
||||
-- 3. Tables de chat
|
||||
-- ================================================================================
|
||||
|
||||
TRUNCATE TABLE chat_messages;
|
||||
TRUNCATE TABLE chat_participants;
|
||||
TRUNCATE TABLE chat_read_receipts;
|
||||
TRUNCATE TABLE chat_rooms;
|
||||
|
||||
-- ================================================================================
|
||||
-- 4. Tables principales
|
||||
-- ================================================================================
|
||||
|
||||
TRUNCATE TABLE users;
|
||||
TRUNCATE TABLE entites;
|
||||
|
||||
-- Réactiver les vérifications de clés étrangères
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ================================================================================
|
||||
-- Vérification : Compter les lignes restantes
|
||||
-- ================================================================================
|
||||
|
||||
SELECT
|
||||
'ope_pass_histo' AS table_name, COUNT(*) AS rows_count FROM ope_pass_histo
|
||||
UNION ALL
|
||||
SELECT 'ope_pass', COUNT(*) FROM ope_pass
|
||||
UNION ALL
|
||||
SELECT 'ope_users_sectors', COUNT(*) FROM ope_users_sectors
|
||||
UNION ALL
|
||||
SELECT 'sectors_adresses', COUNT(*) FROM sectors_adresses
|
||||
UNION ALL
|
||||
SELECT 'ope_sectors', COUNT(*) FROM ope_sectors
|
||||
UNION ALL
|
||||
SELECT 'ope_users', COUNT(*) FROM ope_users
|
||||
UNION ALL
|
||||
SELECT 'medias', COUNT(*) FROM medias
|
||||
UNION ALL
|
||||
SELECT 'operations', COUNT(*) FROM operations
|
||||
UNION ALL
|
||||
SELECT 'user_devices', COUNT(*) FROM user_devices
|
||||
UNION ALL
|
||||
SELECT 'chat_messages', COUNT(*) FROM chat_messages
|
||||
UNION ALL
|
||||
SELECT 'chat_participants', COUNT(*) FROM chat_participants
|
||||
UNION ALL
|
||||
SELECT 'chat_read_receipts', COUNT(*) FROM chat_read_receipts
|
||||
UNION ALL
|
||||
SELECT 'chat_rooms', COUNT(*) FROM chat_rooms
|
||||
UNION ALL
|
||||
SELECT 'users', COUNT(*) FROM users
|
||||
UNION ALL
|
||||
SELECT 'entites', COUNT(*) FROM entites
|
||||
ORDER BY table_name;
|
||||
|
||||
-- Résultat attendu : 0 partout
|
||||
|
||||
SELECT '✓ Toutes les tables ont été vidées avec succès !' AS status;
|
||||
150
api/scripts/orga/verify_isolation.sql
Normal file
150
api/scripts/orga/verify_isolation.sql
Normal file
@@ -0,0 +1,150 @@
|
||||
-- ================================================================================
|
||||
-- Script de vérification : Isolation complète des opérations
|
||||
-- ================================================================================
|
||||
--
|
||||
-- Ce script vérifie que l'isolation par opération fonctionne correctement
|
||||
--
|
||||
-- ================================================================================
|
||||
|
||||
USE dva_geo;
|
||||
|
||||
-- ================================================================================
|
||||
-- 1. Vérifier les contraintes FK
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== VÉRIFICATION DES CONTRAINTES FK ===' AS '';
|
||||
|
||||
SELECT
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = 'dva_geo'
|
||||
AND TABLE_NAME IN ('ope_users_sectors', 'ope_pass')
|
||||
AND COLUMN_NAME = 'fk_user'
|
||||
ORDER BY TABLE_NAME;
|
||||
|
||||
-- Résultat attendu :
|
||||
-- ope_pass | fk_user | ope_pass_ibfk_3 | ope_users | id
|
||||
-- ope_users_sectors | fk_user | ope_users_sectors_ibfk_2 | ope_users | id
|
||||
|
||||
-- ================================================================================
|
||||
-- 2. Vérifier l'intégrité des données (pas d'orphelins)
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== VÉRIFICATION INTÉGRITÉ DES DONNÉES ===' AS '';
|
||||
|
||||
-- Vérifier que tous les fk_user de ope_pass existent dans ope_users
|
||||
SELECT
|
||||
'ope_pass → ope_users' AS verification,
|
||||
COUNT(*) as orphelins
|
||||
FROM ope_pass op
|
||||
LEFT JOIN ope_users ou ON op.fk_user = ou.id
|
||||
WHERE ou.id IS NULL;
|
||||
-- Résultat attendu : 0
|
||||
|
||||
-- Vérifier que tous les fk_user de ope_users_sectors existent dans ope_users
|
||||
SELECT
|
||||
'ope_users_sectors → ope_users' AS verification,
|
||||
COUNT(*) as orphelins
|
||||
FROM ope_users_sectors ous
|
||||
LEFT JOIN ope_users ou ON ous.fk_user = ou.id
|
||||
WHERE ou.id IS NULL;
|
||||
-- Résultat attendu : 0
|
||||
|
||||
-- ================================================================================
|
||||
-- 3. Statistiques de migration
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== STATISTIQUES DE MIGRATION ===' AS '';
|
||||
|
||||
-- Nombre d'entités
|
||||
SELECT 'Entités' AS table_name, COUNT(*) AS count FROM entites
|
||||
UNION ALL
|
||||
-- Nombre d'opérations
|
||||
SELECT 'Opérations' AS table_name, COUNT(*) AS count FROM operations
|
||||
UNION ALL
|
||||
-- Nombre d'utilisateurs dans la table centrale
|
||||
SELECT 'Users (centrale)' AS table_name, COUNT(*) AS count FROM users
|
||||
UNION ALL
|
||||
-- Nombre d'utilisateurs dans les opérations
|
||||
SELECT 'ope_users' AS table_name, COUNT(*) AS count FROM ope_users
|
||||
UNION ALL
|
||||
-- Nombre de secteurs
|
||||
SELECT 'ope_sectors' AS table_name, COUNT(*) AS count FROM ope_sectors
|
||||
UNION ALL
|
||||
-- Nombre d'associations user-secteur
|
||||
SELECT 'ope_users_sectors' AS table_name, COUNT(*) AS count FROM ope_users_sectors
|
||||
UNION ALL
|
||||
-- Nombre de passages
|
||||
SELECT 'ope_pass' AS table_name, COUNT(*) AS count FROM ope_pass
|
||||
UNION ALL
|
||||
-- Nombre d'historiques de passage
|
||||
SELECT 'ope_pass_histo' AS table_name, COUNT(*) AS count FROM ope_pass_histo;
|
||||
|
||||
-- ================================================================================
|
||||
-- 4. Détail par opération
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== DÉTAIL PAR OPÉRATION ===' AS '';
|
||||
|
||||
SELECT
|
||||
o.id AS operation_id,
|
||||
o.libelle AS operation_name,
|
||||
(SELECT COUNT(*) FROM ope_users WHERE fk_operation = o.id) AS nb_users,
|
||||
(SELECT COUNT(*) FROM ope_sectors WHERE fk_operation = o.id) AS nb_sectors,
|
||||
(SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = o.id) AS nb_user_sector_links,
|
||||
(SELECT COUNT(*) FROM ope_pass WHERE fk_operation = o.id) AS nb_passages
|
||||
FROM operations o
|
||||
ORDER BY o.id;
|
||||
|
||||
-- ================================================================================
|
||||
-- 5. Vérifier la relation users → ope_users
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== RELATION users → ope_users ===' AS '';
|
||||
|
||||
SELECT
|
||||
u.id AS user_id,
|
||||
u.first_name,
|
||||
u.sect_name,
|
||||
COUNT(DISTINCT ou.fk_operation) AS nb_operations,
|
||||
GROUP_CONCAT(DISTINCT ou.fk_operation ORDER BY ou.fk_operation) AS operations_ids
|
||||
FROM users u
|
||||
LEFT JOIN ope_users ou ON u.id = ou.fk_user
|
||||
GROUP BY u.id, u.first_name, u.sect_name
|
||||
ORDER BY u.id;
|
||||
|
||||
-- ================================================================================
|
||||
-- 6. TEST DE SUPPRESSION (commenté pour sécurité)
|
||||
-- ================================================================================
|
||||
|
||||
SELECT '=== INSTRUCTIONS POUR TEST DE SUPPRESSION ===' AS '';
|
||||
SELECT 'Pour tester la suppression en CASCADE, décommentez la section ci-dessous' AS instruction;
|
||||
|
||||
-- Compter avant suppression (remplacer [ID_OPERATION] par un ID réel)
|
||||
/*
|
||||
SET @operation_id = [ID_OPERATION];
|
||||
|
||||
SELECT
|
||||
CONCAT('Opération ID: ', @operation_id) AS info,
|
||||
(SELECT COUNT(*) FROM ope_users WHERE fk_operation = @operation_id) as ope_users_count,
|
||||
(SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = @operation_id) as ope_users_sectors_count,
|
||||
(SELECT COUNT(*) FROM ope_pass WHERE fk_operation = @operation_id) as ope_pass_count,
|
||||
(SELECT COUNT(*) FROM ope_sectors WHERE fk_operation = @operation_id) as ope_sectors_count;
|
||||
|
||||
-- Supprimer l'opération
|
||||
DELETE FROM operations WHERE id = @operation_id;
|
||||
|
||||
-- Vérifier que tout a été supprimé (doit retourner 0 partout)
|
||||
SELECT
|
||||
CONCAT('Après suppression de l''opération ID: ', @operation_id) AS info,
|
||||
(SELECT COUNT(*) FROM ope_users WHERE fk_operation = @operation_id) as ope_users_count,
|
||||
(SELECT COUNT(*) FROM ope_users_sectors WHERE fk_operation = @operation_id) as ope_users_sectors_count,
|
||||
(SELECT COUNT(*) FROM ope_pass WHERE fk_operation = @operation_id) as ope_pass_count,
|
||||
(SELECT COUNT(*) FROM ope_sectors WHERE fk_operation = @operation_id) as ope_sectors_count;
|
||||
*/
|
||||
|
||||
SELECT '✓ Vérifications terminées avec succès !' AS status;
|
||||
Reference in New Issue
Block a user