Initialisation du projet geosector complet (web + flutter)

This commit is contained in:
d6soft
2025-05-01 18:59:27 +02:00
commit b5aafc424b
244 changed files with 37296 additions and 0 deletions

214
docs/CDC.md Normal file
View File

@@ -0,0 +1,214 @@
# CAHIER DES CHARGES GEOSECTOR
Geosector est entièrement développé en Flutter
Il utilise les dépendances suivantes
- Hive pour le stockage des données sur mobile en cas déconnexion du réseau
- Stripe pour le paiement en ligne
- MapBox pour laffichage des cartes et la gestion des secteurs (polygones) et des passages (markers)
- Fl_chart pour les graphiques
Lapplication sera accessible via lurl https://app.geosector.fr
Elle utilisera une API FulRest modulaire développée en Full PHP8.3 et connectée à une base de données centrale MariaDB10.11
LAPI sera accessible via lurl https://app.geosector.fr/api/geo/…
Les requêtes authentifiées passeront par le PHP session_id.
Lapplication Flutter utilise des adresses tirées de la base nationale des adresses Open Data via lAPI.
Cette base adresses est importée chaque semaine par un script bash dans une base MariaDB
La base de données centrale geosector_app devra être initialisée et des scripts sql devront être créés pour importer les données d'une autre base avec une autre structure.
Lapplication Flutter GEOSECTOR se compose de trois parties : partie publique, partie admin et partie utilisateur.
# PARTIE PUBLIQUE
2 pages.
## PAGE PUBLIQUE
- Cette page présente la solution
- Elle donne un lien vers l'App Store et Play Store pour télécharger l'application mobile
- Elle présente des captures d'écran de l'application mobile et de l'interface administrateur.
- Elle donne un lien pour se connecter et suivant son e-mail et son mot de passe, on ira dans linterface admin ou utilisateur.
- Elle donne un lien pour s'inscrire et créer son amicale en tant que administrateur.
- Elle donne des statistiques de connexion sur l'admin et le mobile sur les 2 derniers mois et sur les 2 dernières années.
- Elle donne le nombre de clients inscrits et autres infos sur 3 cards
Au niveau du footer on a ladresse de Geosector avec le lien Facebook, les liens de cette page et le formulaire de contacts
- ne pas oublier les pages mentions légales et conditions d'utilisation.
Mettre aussi la modale pour la gestion des cookies
## LOGIN / REGISTER
- La connexion se fait par un username et un userpswd (mot de passe).
- Un lien "mot de passe oublié" permet de saisir son email pour récupérer un nouveau mot de passe.
- Un lien "s'inscrire" permet de saisir son e-mail, son nom et prénom, le nom de l'amicale, son code postal et sa commune pour recevoir un userame et un mot de passe par email.
# PARTIE UTILISATEUR
je voudrais commencer à voir l'interface UI de @user_dashboard_page.dart avec 5 pages qu'il faudra nommer user_xxx_page et qui contiendront des widgets communs à toute l'application.
Le design doit être soigné, clair, espacé, très lisible avec un jeu d'élévations et d'ombres et en tenant compte de @app_theme.dart
En version Web le menu se trouvera dans une SideBar à gauche avec des icones et le contenu à droite
En version mobile, le menu se trouvera en bas des pages avec les mêmes icones
## PAGE PRINCIPALE - Dashboard
- synthèse des passages de lutilisateur et le montant collecté par type de règlement (espèce, chèque, carte bancaire).
- graphique des passages réalisés par jour depuis deux semaines
- Bouton de création dun nouveau passage
## PAGE STATISTIQUES
- Graphiques au choix par jour, semaine, mois du nombre de passages et des sommes collectées
## PAGE HISTORIQUE
- Liste des passages par type, par date avec la possibilité de faire des recherches et de consulter le reçu au format PDF et les éventuelles erreurs détectées par retour d'email
## PAGE COMMUNICATION
- Permet de communiquer au sein de léquipe par chat
- Permet de répondre à un mail dun client
## PAGE CARTE
- Visualiser ses secteurs dactivité via MapBox
- Visualiser ces passages
- Sélectionner des passages près de sa position
- Cliquer sur un passage pour ouvrir le formulaire passage
- Cliquer sur la carte pour créer un passage à la position du clic
## FORMULAIRE PASSAGE
- Saisir les informations de passage et permettre de régler en ligne par carte bancaire via Stripe, et denvoyer par mail ou SMS, le reçu au format PDF.
Il faudrait créer des widgets communs :
1. pour la carte MapBox qui aura certaines fonctionnalités suivant le role du user
2. pour le formulaire de passage qui sera utilisé à plusieurs endroits dans l'appli
3. historique des passages : liste des passages avec des critères de filtres et de tri paramétrable suivant le rôle du user
4. Statistiques : 3 types de graphiques avec critères de sélection paramétrables suivant le rôle du user
# PARTIE ADMIN
En version Web, le menu se trouvera dans une Sidebar à gauche.
En version mobile, le menu se trouvera en bas des pages.
La partie admin est différente suivant le rôle de lutilisateur : super admin ou admin dune amicale.
## ADMIN DUNE AMICALE
8 pages
### PAGE PRINCIPALE
- Synthèse des passages par secteur et par utilisateur et le montant collecté sur lopération en cours
- Graphique des passages réalisés par jour depuis deux semaines
### PAGE AMICALE
- Saisie des informations et options de lamicale
- Upload du logo
- Gestion des abonnements avec paiement en ligne STRIPE en fonction du nombre de calendriers distribués.
- Gestion des SMS avec paiement en ligne STRIPE de pack de 200 à 2000 SMS.
### PAGE MEMBRES
- Gérer les membres de lamicale
- Upload des badges des membres
- Demande de réinitialisation de mot de passe
- Importer/Exporter une liste de membres
### PAGE COMMUNICATION
- Communiquer par chat au sein de léquipe et auprès de Geosector
### PAGE CONNEXIONS
- Consulter les dernières connexions de léquipe des 15 derniers jours
- Graphique des connexions sur 5 mois glissants
### PAGE CARTE
- Voir les secteurs dactivité et les passages avec des filtres sur des secteurs ou des utilisateurs
### PAGE OPERATIONS
- Gérer ses opérations et opération active présélectionnée
- Gérer les secteurs de lopération : couleur, titre, membres
- Tracer les secteurs sur une carte
- Affichage des passages en fonction de lhistorique et des adresses récupérées de la base adresses
- Affichage de la liste des membres actifs avec leurs données de stats par type de passage
- Exporter les données de lopération au format Excel
- Exporter les données dun membre
### PAGE STATISTIQUES
- Afficher des graphiques dactivité par secteur, par membre, et sur des périodes sélectionnées
## ADMIN GEOSECTOR
Ladmin des super administrateurs GEOSECTOR a 1 page en plus
### PAGE CLIENTS
- Affiche la liste des amicales créées actives ou en démo avec une recherche sur le nom de l'amicale, un code postal, une commune, un nom de membre
- gestion des amicales en mode démo (inscription en ligne)
- Création dune amicale en récupérant le formulaire de la page AMICALE
- Suppression dune amicale
- Consulter le nombre de membres, de passages réalisés sur la dernière opération de chaque amicale
- Gérer les secteurs de son opération avec possibilité de suppression ou de restauration
- Gérer les opérations avec possibilité de suppression, création
- Gérer les abonnements en fonction du nombre de passages réalisés et denvoyer par mail une facture au format PDF
# WIDGETS COMMUNS
Des widgets communs doivent être développés pour être utilisés dans plusieurs pages et être appelés avec des paramètres.
- Widget Formulaire de passage
- Widget Carte avec des actions sur les markers (ajout, modification, suppression) et sur les secteurs (ajout, modification, suppression) suivant le rôle de l'utilisateur
- Widget Graphiques de connexions suivant le rôle Admin ou Super Admin
- Widget Graphiques de statistiques de passages d'un membre
- Widget Graphiques de statistiques d'un secteur
- Widget Graphiques de statistiques d'une opération
- Widget Formulaire d'une amicale
- Widget Formulaire d'un membre
- Widget Formulaire d'une opération
- Widget Formulaire d'un secteur
# CHIFFREMENT
Chaque mot de passe doit être chiffré avec l'algorithme Argon2
Des données sensibles seront à chiffer avec l'algorithme AES-256 dans la base de données. Ces champs seront nommées avec le préfixe `encrypted_`
Le chiffrement sera utilisé avec IV identique pour les emails, les adresses car elles sont utilisées dans les recherches.
# EMAILS
Les emails seront envoyés via l'API vers le serveur SMTP de geosector.fr avec les adresses noreply et contact@geosector.fr
Une gestion de queue des emails sera développée par l'API pour éviter d'envoyer trop d'emails par heure (limite 1500 emails/heure).
Un script externe en PHP sera développé pour nettoyer la queue et envoyer les emails stockés en base de données.
Un script externe en PHP sera développé pour contrôler les éventuels retours d'emails non réceptionnés (erreur email) et qui renverra l'information d'erreur dans la table ope_pass des passages pour que l'utilisateur soit alerté et qu'il puisse mettre à jour l'email et effectuer un renvoi du reçu au format PDF.
# SMS
Un SMS peut être envoyé sur un passage à l'habitant pour lui confirmer le passage et la somme collectée.
Seules les amicales qui ont accepté cette fonctionnalité dans l'interface admin pourront envoyer des SMS.
Les SMS seront envoyés via l'API et via le serveur SMS OVH.
Une gestion de règlement sera développée pour que l'amicale puisse régler le paiement des SMS envoyés, par pack de 200, 500, 1000, 2000 SMS.
# BASES DE DONNEES EXTERNES OPEN DATA
Des scripts PHP au niveau de l'API seront développés pour importer hebdomadairement la base ADRESSES Open Data.
Ces données seront stockées dans une base de données centrale MariaDB.
Des scripts PHP au niveau de l'API seront développés pour importer hebdomadairement la base SIRENE Open Data.
Ces données seront stockées dans une base de données centrale MariaDB.
Des scripts PHP au niveau de l'API seront développés pour importer hebdomadairement la base BATIMENTS Open Data.
Ces données seront stockées dans une base de données centrale MariaDB.
Des scripts PHP au niveau de l'API seront développés pour importer hebdomadairement la base OpenStreetMap Open Data.
Ces données seront stockées dans une base de données centrale MariaDB.
Des points d'entrées de l'API seront développés pour récupérer les données des bases externes à destination de GEOSECTOR.

292
docs/DB-diagram.md Normal file
View File

@@ -0,0 +1,292 @@
erDiagram
users ||--o{ ope_pass : "fk_user"
users ||--o{ ope_users : "fk_user"
users ||--o{ ope_users_sectors : "fk_user"
users ||--o{ ope_users_suivis : "fk_user"
users ||--o{ ope_pass_histo : "fk_user"
users ||--o{ medias : "fk_user_creat/fk_user_modif"
users }o--|| users_entites : "fk_entite"
users }o--|| x_users_roles : "fk_role"
users }o--|| x_users_categories : "fk_categorie"
users }o--|| x_users_sous_categories : "fk_sous_categorie"
users }o--|| x_users_grades : "fk_grade"
operations ||--o{ ope_pass : "fk_operation"
operations ||--o{ ope_users : "fk_operation"
operations ||--o{ ope_sectors : "fk_operation"
operations ||--o{ ope_users_sectors : "fk_operation"
operations ||--o{ ope_users_suivis : "fk_operation"
operations }o--|| users_entites : "fk_entite"
sectors ||--o{ ope_users_sectors : "fk_sector"
sectors ||--o{ sectors_adresses : "fk_sector"
sectors ||--o{ sectors_streets : "fk_sector"
ope_sectors ||--o{ ope_users_sectors : "fk_sector"
ope_sectors ||--o{ ope_pass : "fk_sector"
ope_pass ||--o{ ope_pass_histo : "fk_pass"
ope_pass ||--o{ ope_pass_recus : "fk_pass"
ope_pass ||--o{ email_queue : "rowid"
ope_pass }o--|| x_types_reglements : "fk_type_reglement"
x_users_categories ||--o{ x_users_sous_categories : "fk_user_categorie"
x_pays ||--o{ x_regions : "fk_pays"
x_regions ||--o{ x_departements : "fk_region"
x_departements ||--o{ x_villes : "fk_departement"
x_pays }o--|| x_devises : "fk_devise"
users_entites }o--|| x_regions : "fk_region"
users_entites }o--|| x_entites_types : "fk_type"
email_counter {
int id PK
timestamp hour_start
int count
}
email_queue {
int id PK
int rowid "ope_pass.rowid"
varchar to_email
varchar subject
text body
enum status
}
medias {
int rowid PK
varchar support
int support_rowid
varchar fichier
varchar type_fichier
varchar description
datetime date_creat
int fk_user_creat FK
datetime date_modif
int fk_user_modif FK
}
ope_pass {
int rowid PK
int fk_operation FK
int fk_sector FK
int fk_user FK
varchar fk_adresse
datetime date_eve
int fk_type
varchar numero
varchar rue
varchar ville
int fk_habitat
decimal montant
int fk_type_reglement FK
}
ope_pass_histo {
int rowid PK
int fk_pass FK
int fk_user FK
datetime date_histo
varchar sujet
varchar remarque
}
ope_pass_recus {
int rowid PK
int fk_pass FK
varchar chemin
varchar nom_recu
datetime date_recu
}
ope_sectors {
int rowid PK
int fk_operation FK
varchar libelle
text sector
varchar color
}
ope_users {
int rowid PK
int fk_operation FK
int fk_user FK
tinyint active
}
ope_users_sectors {
int rowid PK
int fk_operation FK
int fk_user FK
int fk_sector FK
tinyint active
}
ope_users_suivis {
int rowid PK
int fk_operation FK
int fk_user FK
datetime date_suivi
varchar latitude
varchar longitude
}
operations {
int rowid PK
int fk_entite FK
varchar libelle
date date_deb
date date_fin
tinyint active
}
sectors {
int rowid PK
varchar libelle
text sector
varchar color
tinyint active
}
sectors_adresses {
int rowid PK
varchar fk_adresse
int fk_sector FK
varchar numero
varchar rue
varchar cp
varchar ville
varchar gps_lat
varchar gps_lng
}
sectors_streets {
int rowid PK
int fk_sector FK
varchar fk_adresse
varchar osm_lat
varchar osm_lng
varchar osm_name
varchar osm_street
varchar osm_city
}
users {
int rowid PK
int fk_entite FK
int fk_titre
varchar libelle
varchar prenom
varchar username
varchar userpass
varchar email
int fk_role FK
int fk_categorie FK
int fk_sous_categorie FK
int fk_grade FK
tinyint active
}
users_entites {
int rowid PK
varchar libelle
varchar adresse1
varchar cp
varchar ville
int fk_region FK
int fk_type FK
varchar email
tinyint active
}
x_departements {
int rowid PK
varchar code
int fk_region FK
varchar libelle
}
x_devises {
int rowid PK
varchar code
varchar symbole
varchar libelle
}
x_entites_types {
int rowid PK
varchar libelle
tinyint active
}
x_pays {
int rowid PK
varchar code
int fk_continent
int fk_devise FK
varchar libelle
}
x_regions {
int rowid PK
int fk_pays FK
varchar libelle
varchar libelle_long
}
x_types_passages {
int rowid PK
varchar libelle
varchar color_button
varchar color_mark
}
x_types_reglements {
int rowid PK
varchar libelle
tinyint active
}
x_users_categories {
int rowid PK
varchar libelle
tinyint active
}
x_users_grades {
int rowid PK
varchar libelle
tinyint active
}
x_users_roles {
int rowid PK
varchar libelle
tinyint active
}
x_users_sous_categories {
int rowid PK
int fk_user_categorie FK
varchar libelle
tinyint active
}
x_villes {
int rowid PK
int fk_departement FK
varchar libelle
varchar cp
varchar code_insee
}
z_sessions {
text sid
int fk_user FK
varchar role
timestamp date_modified
varchar ip
varchar browser
}

678
docs/api_endpoints.md Normal file
View File

@@ -0,0 +1,678 @@
# API Endpoints de GEOSECTOR
## Description générale
GEOSECTOR utilise une API REST modulaire développée en PHP 8.3 pour communiquer avec le backend. Cette API permet la gestion des utilisateurs, des opérations, des secteurs et des passages. Ce document décrit tous les endpoints disponibles, leurs paramètres et leurs réponses.
## Configuration de base
- **URL de base**: `https://app.geosector.fr/api/geo`
- **Authentification**: Session PHP avec token Bearer
- **Format des réponses**: JSON
- **Timeouts**:
- Connexion: 5 secondes
- Réception: 30 secondes
## Headers par défaut
```
Content-Type: application/json
X-App-Identifier: app.geosector.fr
X-Client-Type: web/mobile (détecté automatiquement)
Accept: application/json
```
## Authentification
### Login
Permet à un utilisateur de se connecter et d'obtenir un ID de session.
- **URL**: `/login`
- **Méthode**: `POST`
- **Authentification requise**: Non
- **Paramètres**:
| Paramètre | Type | Description |
|-----------|--------|--------------------------------------------|
| username | string | Nom d'utilisateur |
| password | string | Mot de passe |
| type | string | Type de connexion ('admin' ou 'user') |
- **Réponse réussie**:
```json
{
"status": "success",
"message": "Connexion réussie",
"session_id": "session_token_here",
"user": {
"id": 123,
"email": "user@example.com",
"name": "Nom Utilisateur",
"username": "username",
"first_name": "Prénom",
"sect_name": "Nom section",
"fk_role": 1,
"interface": "user"
},
"operations": [...],
"sectors": [...],
"passages": [...]
}
```
- **Réponse d'erreur**:
```json
{
"status": "error",
"message": "Identifiants incorrects"
}
```
### Logout
Déconnecte l'utilisateur en invalidant sa session.
- **URL**: `/logout`
- **Méthode**: `POST`
- **Authentification requise**: Oui
- **Paramètres**: Aucun
- **Réponse réussie**:
```json
{
"status": "success",
"message": "Déconnexion réussie"
}
```
### Register
Enregistre un nouvel administrateur d'amicale.
- **URL**: `/register`
- **Méthode**: `POST`
- **Authentification requise**: Non
- **Paramètres**:
| Paramètre | Type | Description |
|---------------|--------|----------------------------|
| email | string | Email |
| name | string | Nom |
| amicale_name | string | Nom de l'amicale |
| postal_code | string | Code postal |
| city_name | string | Nom de la ville |
- **Réponse réussie**:
```json
{
"status": "success",
"message": "Inscription réussie",
"user_id": 123,
"session_id": "session_token_here",
"session_expiry": "2025-04-20T12:00:00Z"
}
```
## Gestion des utilisateurs
### Récupérer tous les utilisateurs
- **URL**: `/users`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: Aucun
- **Réponse**:
```json
[
{
"id": 123,
"email": "user@example.com",
"name": "Nom Utilisateur",
"role": 1,
"isActive": true
},
...
]
```
### Récupérer un utilisateur par ID
- **URL**: `/users/{id}`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: ID dans l'URL
- **Réponse**:
```json
{
"id": 123,
"email": "user@example.com",
"name": "Nom Utilisateur",
"role": 1,
"isActive": true
}
```
### Créer un utilisateur
- **URL**: `/users`
- **Méthode**: `POST`
- **Authentification requise**: Oui (Admin)
- **Paramètres**:
| Paramètre | Type | Description |
|-----------|---------|------------------------------|
| email | string | Email de l'utilisateur |
| name | string | Nom de l'utilisateur |
| role | integer | Rôle (1=user, 2/4/9=admin) |
- **Réponse**:
```json
{
"id": 123,
"email": "user@example.com",
"name": "Nom Utilisateur",
"role": 1,
"isActive": true
}
```
### Mettre à jour un utilisateur
- **URL**: `/users/{id}`
- **Méthode**: `PUT`
- **Authentification requise**: Oui (Admin ou propriétaire du compte)
- **Paramètres**: ID dans l'URL + corps de la requête
| Paramètre | Type | Description |
|-----------|---------|----------------------------------|
| email | string | Email de l'utilisateur |
| name | string | Nom de l'utilisateur |
| role | integer | Rôle (1=user, 2/4/9=admin) |
| isActive | boolean | Statut de l'utilisateur |
- **Réponse**:
```json
{
"id": 123,
"email": "user@example.com",
"name": "Nom Utilisateur",
"role": 1,
"isActive": true
}
```
### Supprimer un utilisateur
- **URL**: `/users/{id}`
- **Méthode**: `DELETE`
- **Authentification requise**: Oui (Admin)
- **Paramètres**: ID dans l'URL
- **Réponse**:
```json
{
"status": "success",
"message": "Utilisateur supprimé avec succès"
}
```
## Gestion des opérations
### Récupérer toutes les opérations
- **URL**: `/operations`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Filtres optionnels**:
| Paramètre | Type | Description |
|-----------|---------|----------------------------------------|
| active | boolean | Filtrer par statut actif/inactif |
- **Réponse**:
```json
[
{
"id": 456,
"libelle": "Opération 2025",
"date_deb": "2025-01-01",
"date_fin": "2025-12-31",
"active": true
},
...
]
```
### Récupérer une opération par ID
- **URL**: `/operations/{id}`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: ID dans l'URL
- **Réponse**:
```json
{
"id": 456,
"libelle": "Opération 2025",
"date_deb": "2025-01-01",
"date_fin": "2025-12-31",
"active": true,
"sectors": [
{
"id": 789,
"libelle": "Secteur Nord",
"color": "#FF5733",
"sector": "POLYGON((...))"
},
...
]
}
```
### Créer une opération
- **URL**: `/operations`
- **Méthode**: `POST`
- **Authentification requise**: Oui (Admin)
- **Paramètres**:
| Paramètre | Type | Description |
|-----------|---------|----------------------------------|
| libelle | string | Nom de l'opération |
| date_deb | string | Date de début (YYYY-MM-DD) |
| date_fin | string | Date de fin (YYYY-MM-DD) |
| active | boolean | Statut de l'opération |
- **Réponse**:
```json
{
"id": 456,
"libelle": "Opération 2025",
"date_deb": "2025-01-01",
"date_fin": "2025-12-31",
"active": true
}
```
### Mettre à jour une opération
- **URL**: `/operations/{id}`
- **Méthode**: `PUT`
- **Authentification requise**: Oui (Admin)
- **Paramètres**: ID dans l'URL + corps de la requête
| Paramètre | Type | Description |
|-----------|---------|----------------------------------|
| libelle | string | Nom de l'opération |
| date_deb | string | Date de début (YYYY-MM-DD) |
| date_fin | string | Date de fin (YYYY-MM-DD) |
| active | boolean | Statut de l'opération |
- **Réponse**:
```json
{
"id": 456,
"libelle": "Opération 2025",
"date_deb": "2025-01-01",
"date_fin": "2025-12-31",
"active": true
}
```
## Gestion des secteurs
### Récupérer tous les secteurs
- **URL**: `/sectors`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Filtres optionnels**:
| Paramètre | Type | Description |
|--------------|---------|----------------------------------------|
| operation_id | integer | Filtrer par ID d'opération |
- **Réponse**:
```json
[
{
"id": 789,
"libelle": "Secteur Nord",
"color": "#FF5733",
"sector": "POLYGON((...))"
},
...
]
```
### Récupérer un secteur par ID
- **URL**: `/sectors/{id}`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: ID dans l'URL
- **Réponse**:
```json
{
"id": 789,
"libelle": "Secteur Nord",
"color": "#FF5733",
"sector": "POLYGON((...))",
"adresses": [
{
"id": 101,
"numero": "12",
"rue": "Rue des Lilas",
"cp": "75001",
"ville": "Paris",
"gps_lat": "48.8566",
"gps_lng": "2.3522"
},
...
]
}
```
### Créer un secteur
- **URL**: `/sectors`
- **Méthode**: `POST`
- **Authentification requise**: Oui (Admin)
- **Paramètres**:
| Paramètre | Type | Description |
|--------------|---------|----------------------------------|
| libelle | string | Nom du secteur |
| color | string | Couleur au format hexadécimal |
| sector | string | Coordonnées WKT du polygone |
| operation_id | integer | ID de l'opération associée |
- **Réponse**:
```json
{
"id": 789,
"libelle": "Secteur Nord",
"color": "#FF5733",
"sector": "POLYGON((...))"
}
```
### Mettre à jour un secteur
- **URL**: `/sectors/{id}`
- **Méthode**: `PUT`
- **Authentification requise**: Oui (Admin)
- **Paramètres**: ID dans l'URL + corps de la requête
| Paramètre | Type | Description |
|--------------|---------|----------------------------------|
| libelle | string | Nom du secteur |
| color | string | Couleur au format hexadécimal |
| sector | string | Coordonnées WKT du polygone |
- **Réponse**:
```json
{
"id": 789,
"libelle": "Secteur Nord",
"color": "#FF5733",
"sector": "POLYGON((...))"
}
```
## Gestion des passages
### Récupérer tous les passages
- **URL**: `/passages`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Filtres optionnels**:
| Paramètre | Type | Description |
|--------------|---------|----------------------------------------|
| operation_id | integer | Filtrer par ID d'opération |
| sector_id | integer | Filtrer par ID de secteur |
| user_id | integer | Filtrer par ID d'utilisateur |
| date_start | string | Date de début (YYYY-MM-DD) |
| date_end | string | Date de fin (YYYY-MM-DD) |
- **Réponse**:
```json
[
{
"id": 1001,
"fk_operation": 456,
"fk_sector": 789,
"fk_user": 123,
"date_eve": "2025-01-15T14:30:00Z",
"montant": 25.50,
"fk_type": 1,
"fk_type_reglement": 2,
"numero": "12",
"rue": "Rue des Lilas",
"ville": "Paris"
},
...
]
```
### Récupérer un passage par ID
- **URL**: `/passages/{id}`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: ID dans l'URL
- **Réponse**:
```json
{
"id": 1001,
"fk_operation": 456,
"fk_sector": 789,
"fk_user": 123,
"date_eve": "2025-01-15T14:30:00Z",
"montant": 25.50,
"fk_type": 1,
"fk_type_reglement": 2,
"numero": "12",
"rue": "Rue des Lilas",
"ville": "Paris",
"historique": [
{
"date_histo": "2025-01-15T14:30:00Z",
"sujet": "Création",
"remarque": "Passage créé"
},
...
],
"recus": [
{
"chemin": "/recus/2025/...",
"nom_recu": "recu_20250115_1001.pdf",
"date_recu": "2025-01-15T14:35:00Z"
},
...
]
}
```
### Créer un passage
- **URL**: `/passages`
- **Méthode**: `POST`
- **Authentification requise**: Oui
- **Paramètres**:
| Paramètre | Type | Description |
|-------------------|---------|----------------------------------|
| fk_operation | integer | ID de l'opération |
| fk_sector | integer | ID du secteur |
| date_eve | string | Date du passage (ISO 8601) |
| montant | number | Montant collecté |
| fk_type | integer | Type de passage (1-6) |
| fk_type_reglement | integer | Type de règlement (0-3) |
| numero | string | Numéro de rue |
| rue | string | Nom de la rue |
| ville | string | Ville |
| send_email | boolean | Envoyer un reçu par email |
| email | string | Email pour l'envoi du reçu |
| send_sms | boolean | Envoyer un SMS de confirmation |
| telephone | string | Numéro pour l'envoi du SMS |
- **Réponse**:
```json
{
"id": 1001,
"fk_operation": 456,
"fk_sector": 789,
"fk_user": 123,
"date_eve": "2025-01-15T14:30:00Z",
"montant": 25.50,
"fk_type": 1,
"fk_type_reglement": 2,
"numero": "12",
"rue": "Rue des Lilas",
"ville": "Paris",
"recu_url": "/api/geo/recus/2025/recu_20250115_1001.pdf"
}
```
### Mettre à jour un passage
- **URL**: `/passages/{id}`
- **Méthode**: `PUT`
- **Authentification requise**: Oui
- **Paramètres**: ID dans l'URL + corps de la requête
| Paramètre | Type | Description |
|-------------------|---------|----------------------------------|
| fk_type | integer | Type de passage (1-6) |
| fk_type_reglement | integer | Type de règlement (0-3) |
| montant | number | Montant collecté |
| remarque | string | Remarque sur la modification |
- **Réponse**:
```json
{
"id": 1001,
"fk_operation": 456,
"fk_sector": 789,
"fk_user": 123,
"date_eve": "2025-01-15T14:30:00Z",
"montant": 30.00,
"fk_type": 1,
"fk_type_reglement": 2,
"numero": "12",
"rue": "Rue des Lilas",
"ville": "Paris"
}
```
## Synchronisation des données
### Synchronisation générale
Permet de synchroniser plusieurs types de données en une seule requête.
- **URL**: `/data/sync`
- **Méthode**: `POST`
- **Authentification requise**: Oui
- **Paramètres**:
| Paramètre | Type | Description |
|------------|-------|------------------------------------------|
| users | array | Liste des utilisateurs à synchroniser |
| operations | array | Liste des opérations à synchroniser |
| sectors | array | Liste des secteurs à synchroniser |
| passages | array | Liste des passages à synchroniser |
- **Réponse**:
```json
{
"status": "success",
"synced": {
"users": 5,
"operations": 2,
"sectors": 3,
"passages": 10
},
"errors": []
}
```
## Services géographiques
### Recherche d'adresses
Recherche des adresses à partir de la base nationale des adresses.
- **URL**: `/geo/addresses/search`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**:
| Paramètre | Type | Description |
|-----------|--------|--------------------------------------------|
| q | string | Texte de recherche (rue, code postal...) |
| limit | integer| Nombre maximum de résultats (défaut: 10) |
- **Réponse**:
```json
[
{
"id": "ADDRESS-ID",
"numero": "12",
"rue": "Rue des Lilas",
"cp": "75001",
"ville": "Paris",
"latitude": 48.8566,
"longitude": 2.3522
},
...
]
```
### Récupérer les rues dans un secteur
- **URL**: `/geo/sectors/{id}/streets`
- **Méthode**: `GET`
- **Authentification requise**: Oui
- **Paramètres**: ID du secteur dans l'URL
- **Réponse**:
```json
[
{
"id": "STREET-ID",
"name": "Rue des Lilas",
"city": "Paris",
"osm_lat": 48.8566,
"osm_lng": 2.3522
},
...
]
```
## Codes d'erreur
| Code | Description |
|------|--------------------------------------------|
| 400 | Requête invalide (paramètres manquants) |
| 401 | Non authentifié |
| 403 | Non autorisé (droits insuffisants) |
| 404 | Ressource introuvable |
| 409 | Conflit (ex: email déjà utilisé) |
| 422 | Erreur de validation des données |
| 500 | Erreur serveur |
## Notes d'utilisation
1. **Authentification**: Après connexion, l'ID de session doit être fourni dans l'en-tête `Authorization` sous forme de `Bearer {session_id}` pour toutes les requêtes authentifiées.
2. **Filtrage**: La plupart des endpoints GET supportent des paramètres de filtrage additionnels.
3. **Pagination**: Les endpoints retournant des listes importantes supportent la pagination via les paramètres `page` et `limit`.
4. **Synchronisation**: La synchronisation des données permet de travailler hors ligne et de synchroniser lors du retour en ligne.
5. **Reçus PDF**: Les passages créés peuvent générer automatiquement des reçus PDF qui peuvent être envoyés par email ou SMS.
6. **Données géographiques**: Les secteurs sont stockés au format WKT (Well-Known Text) pour les polygones.

262
docs/architecture.md Normal file
View File

@@ -0,0 +1,262 @@
# Architecture de GEOSECTOR
## Description générale
GEOSECTOR est une application Flutter conçue pour la gestion de secteurs géographiques et de passages. L'application suit une architecture modulaire qui sépare clairement les préoccupations et permet une maintenance facilitée. Elle utilise un pattern de conception proche du MVVM (Model-View-ViewModel) avec des instances globales pour la gestion d'état et l'accès aux services.
## Structure du projet
L'application est organisée selon une architecture en couches avec une séparation claire des responsabilités :
```
lib/
├── app.dart # Point d'entrée de l'application
├── main.dart # Configuration initiale
├── core/ # Fonctionnalités communes et services de base
│ ├── constants/ # Constantes de l'application
│ ├── data/ # Modèles de données
│ │ └── models/ # Définitions des modèles pour Hive
│ ├── providers/ # Providers pour l'injection de dépendances
│ ├── repositories/ # Gestion des données et logique métier
│ ├── routes/ # Configuration du routage
│ ├── services/ # Services d'infrastructure
│ ├── theme/ # Thème de l'application
│ └── widgets/ # Widgets communs réutilisables
├── presentation/ # Interface utilisateur par module
│ ├── admin/ # Écrans d'administration
│ ├── auth/ # Écrans d'authentification
│ ├── public/ # Écrans publics
│ ├── user/ # Écrans utilisateur
│ └── widgets/ # Widgets partagés pour l'UI
└── shared/ # Ressources partagées
├── app_theme.dart # Configuration du thème
└── widgets/ # Widgets partagés entre modules
```
## Couches d'architecture
### 1. Couche de présentation (Presentation Layer)
La couche de présentation est responsable de l'interface utilisateur et est divisée en modules fonctionnels :
- **admin/** : Pages du tableau de bord administrateur
- **auth/** : Pages d'authentification (login, register)
- **public/** : Pages accessibles sans authentification
- **user/** : Pages du tableau de bord utilisateur
- **widgets/** : Composants UI partagés entre les modules
Chaque module de présentation suit une structure cohérente avec des pages distinctes pour chaque fonctionnalité principale :
```
user/
├── user_dashboard_page.dart # Page principale avec navigation
├── user_dashboard_home_page.dart # Accueil du tableau de bord
├── user_map_page.dart # Carte et secteurs
├── user_history_page.dart # Historique des passages
├── user_statistics_page.dart # Statistiques et graphiques
└── user_communication_page.dart # Communication interne
```
De même, le module admin suit une structure similaire avec des pages spécifiques :
```
admin/
├── admin_dashboard_page.dart # Page principale avec navigation
├── admin_dashboard_home_page.dart # Accueil du tableau de bord admin
├── admin_map_page.dart # Gestion des cartes et secteurs
├── admin_history_page.dart # Historique global des passages
├── admin_statistics_page.dart # Statistiques avancées
├── admin_communication_page.dart # Gestion des communications
└── admin_entite.dart # Gestion des amicales et membres
```
### 2. Couche de données (Data Layer)
La couche de données est responsable de la gestion des données et comprend :
- **models/** : Modèles de données avec adaptateurs Hive pour la persistance locale
- `user_model.dart` : Données utilisateur et authentification
- `operation_model.dart` : Opérations et campagnes
- `sector_model.dart` : Secteurs géographiques
- `passage_model.dart` : Données des passages
- `membre_model.dart` : Données des membres pour l'interface admin
- **repositories/** : Gestionnaires de données pour chaque domaine
- `user_repository.dart` : Gestion des utilisateurs et authentification
- `operation_repository.dart` : Gestion des opérations
- `passage_repository.dart` : Gestion des passages
- `sector_repository.dart` : Gestion des secteurs
- `membre_repository.dart` : Gestion des membres pour l'interface admin
### 3. Couche de services (Services Layer)
La couche de services fournit des fonctionnalités d'infrastructure et d'intégration :
- `api_service.dart` : Communication avec l'API backend
- `auth_service.dart` : Gestion de l'authentification
- `connectivity_service.dart` : Surveillance de la connectivité réseau
- `location_service.dart` : Services de géolocalisation
- `passage_data_service.dart` : Traitement des données de passage
- `sync_service.dart` : Synchronisation des données locales/serveur
## Gestion d'état et injection de dépendances
L'application utilise des instances globales pour la gestion d'état et l'accès aux services. Ces instances sont définies dans le fichier `app.dart` :
```dart
// Instances globales des services et repositories
final apiService = ApiService();
final operationRepository = OperationRepository(apiService);
final passageRepository = PassageRepository(apiService);
final userRepository = UserRepository(apiService);
final sectorRepository = SectorRepository(apiService);
final membreRepository = MembreRepository(apiService);
final syncService = SyncService(userRepository: userRepository);
final connectivityService = ConnectivityService();
```
Le widget `AppProviders` a été maintenu pour la compatibilité, mais il retourne simplement l'enfant sans utiliser Provider :
```dart
class AppProviders extends StatelessWidget {
final Widget child;
const AppProviders({
Key? key,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// Les instances globales sont maintenant définies dans app.dart
// Cette classe est maintenue pour la compatibilité
return child;
}
}
```
Cette approche permet :
1. De simplifier l'architecture en éliminant la dépendance à Provider
2. D'accéder directement aux services et repositories depuis n'importe quel widget
3. De réduire la complexité du code et d'améliorer les performances
4. De maintenir une séparation claire des responsabilités
## Routage et navigation
L'application utilise `go_router` pour la gestion des routes et de la navigation :
- **AppRouter** : Configuration centralisée des routes de l'application
- **Redirections conditionnelles** : Contrôle d'accès basé sur l'état d'authentification
- **Persistance de parcours** : Sauvegarde du dernier chemin de l'utilisateur
Le système de routage implémente :
- Redirection basée sur les rôles (admin vs utilisateur)
- Gestion des sessions persistantes
- Navigation entre les différentes sections de l'application
## Persistance des données
L'application utilise Hive pour la persistance locale des données :
- **Initialisation sélective** : Ouverture des boîtes Hive à la demande
- **Gestion efficace de la mémoire** : Optimisation de l'utilisation des ressources
- **Mode hors ligne** : Fonctionnalité complète même sans connexion Internet
La gestion des boîtes Hive est optimisée selon ces principes :
- Ouverture des boîtes essentielles au démarrage (`users`, `settings`)
- Ouverture des autres boîtes (`operations`, `sectors`, `passages`, `membres`) après connexion
- Nettoyage et recréation des boîtes sans les fermer lors de la déconnexion
## Intégrations externes
L'application intègre plusieurs services externes :
- **Mapbox** : Affichage des cartes et gestion des secteurs géographiques
- **Stripe** : Traitement des paiements en ligne
- **API FulRest PHP** : Communication avec le backend
- **Base de données MariaDB** : Stockage centralisé des données
## Sécurité
L'application implémente plusieurs mesures de sécurité :
- **Chiffrement Argon2** pour les mots de passe
- **Chiffrement AES-256** pour les données sensibles
- **Session PHP** pour l'authentification API
- **Mécanismes de contrôle d'accès** basés sur les rôles
## Flux d'authentification
Le flux d'authentification suit ce processus :
1. Vérification initiale de session persistante (Hive)
2. Redirection vers Login/Register si nécessaire
3. Authentification via API Service
4. Stockage sécurisé des informations de session
5. Redirection vers l'interface appropriée (admin vs utilisateur)
## Widgets communs
L'application utilise plusieurs widgets communs pour maintenir une cohérence d'interface :
1. **Widget Carte MapBox** : Affichage/édition de secteurs et marqueurs
2. **Widget Formulaire de passage** : Saisie des données de passage
3. **Widget Historique** : Liste des passages avec filtres et tri
- Filtrage par type de passage (avec possibilité d'exclure certains types)
- Filtrage par utilisateur (pour les administrateurs)
- Filtrage par secteur (pour les administrateurs)
- Filtrage par période (derniers 15 jours, dernière semaine, dernier mois, personnalisé)
- Recherche textuelle (adresse, nom, notes)
- Interface adaptative (compacte pour desktop, étendue pour mobile)
4. **Widget Statistiques** : Visualisation graphique des données
### Widget PassagesListWidget
Le widget `PassagesListWidget` est un composant réutilisable qui permet d'afficher une liste de passages avec des fonctionnalités avancées de filtrage :
```dart
PassagesListWidget(
passages: formattedPassages,
showFilters: true,
showSearch: true,
showActions: true,
initialSearchQuery: searchQuery,
initialTypeFilter: selectedType,
initialPaymentFilter: selectedPaymentMethod,
// Filtres avancés
excludePassageTypes: [2], // Exclure les passages "À finaliser"
filterByUserId: selectedUserId, // Filtrer par utilisateur
filterBySectorId: selectedSectorId, // Filtrer par secteur
periodFilter: 'lastMonth', // Période par défaut
dateRange: selectedDateRange, // Plage de dates personnalisée
// Callbacks
onPassageSelected: (passage) => _showDetailsDialog(context, passage),
onReceiptView: (passage) => _showReceiptDialog(context, passage),
onDetailsView: (passage) => _showDetailsDialog(context, passage),
onPassageEdit: (passage) => _editPassage(passage),
)
```
Ce widget est utilisé dans plusieurs pages de l'application :
- `user_dashboard_home_page.dart` : Affiche les derniers passages de l'utilisateur courant
- `user_history_page.dart` : Affiche l'historique complet des passages de l'utilisateur courant
- `admin_history_page.dart` : Affiche l'historique global de tous les passages avec des filtres avancés
## Relations avec d'autres composants
- **Backend API** : Communication via ApiService pour toutes les opérations CRUD
- **Stockage local** : Utilisation de Hive pour la persistance des données
- **Services externes** : Intégration avec Mapbox, Stripe et autres services tiers
## Bonnes pratiques implémentées
1. **Séparation des préoccupations** : Découpage clair entre UI, logique métier et données
2. **Accès simplifié aux services** : Utilisation d'instances globales pour un accès direct aux services
3. **Mode hors ligne** : Fonctionnalité complète même sans connexion Internet
4. **Thème cohérent** : Application d'un thème unifié via AppTheme
5. **Routage centralisé** : Gestion des redirections et autorisations d'accès

622
docs/chat.md Normal file
View File

@@ -0,0 +1,622 @@
# Solution de Chat pour Applications Flutter
## Présentation générale
Cette solution propose un système de chat personnalisé et autonome pour des applications Flutter, avec possibilité d'intégration web. Elle est conçue pour fonctionner dans deux contextes différents :
1. **Chat entre utilisateurs authentifiés** (cas Geosector) : communications one-to-one ou en groupe entre utilisateurs déjà enregistrés dans la base de données.
2. **Chat entre professionnels et visiteurs anonymes** (cas Resalice) : communications initiées par des visiteurs anonymes qui peuvent ensuite être convertis en clients référencés.
## Architecture technique
### 1. Structure générale
La solution s'articule autour de trois composants principaux :
- **Module Flutter** : Widgets et logique pour l'interface utilisateur mobile
- **Module Web** : Composants pour l'intégration web (compatible avec Flutter Web ou sites traditionnels)
- **API Backend** : Endpoints REST pour la gestion des messages et la synchronisation
### 2. Modèle de données
#### Entités principales
```
Conversation
├── id : Identifiant unique
├── type : Type de conversation (one_to_one, group, anonymous, broadcast, announcement)
├── title : Titre facultatif pour les groupes et obligatoire pour les annonces
├── reply_permission : Niveau de permission pour répondre (all, admins_only, sender_only, none)
├── created_at : Date de création
├── updated_at : Dernière mise à jour
├── is_pinned : Indique si la conversation est épinglée (pour annonces importantes)
├── expiry_date : Date d'expiration optionnelle (pour annonces temporaires)
└── participants : Liste des participants
Message
├── id : Identifiant unique
├── conversation_id : ID de la conversation
├── sender_id : ID de l'expéditeur (null pour anonyme)
├── sender_type : Type d'expéditeur (user, anonymous, system)
├── content : Contenu du message
├── content_type : Type de contenu (text, image, file)
├── created_at : Date d'envoi
├── delivered_at : Date de réception
├── read_at : Date de lecture
├── status : Statut du message (sent, delivered, read, error)
└── is_announcement : Indique s'il s'agit d'une annonce officielle
Participant
├── id : Identifiant unique
├── conversation_id : ID de la conversation
├── user_id : ID de l'utilisateur (si authentifié)
├── anonymous_id : ID anonyme (pour Resalice)
├── role : Rôle (admin, member, read_only)
├── joined_at : Date d'ajout à la conversation
├── via_target : Indique si l'utilisateur est inclus via un AudienceTarget
├── can_reply : Possibilité explicite de répondre (override de reply_permission)
└── last_read_message_id : ID du dernier message lu
AudienceTarget
├── id : Identifiant unique
├── conversation_id : ID de la conversation
├── target_type : Type de cible (role, entity, all, combined)
├── target_id : ID du rôle ou de l'entité ciblée (pour compatibility)
├── role_filter : Filtre de rôle pour le ciblage combiné ('all', '1', '2', etc.)
├── entity_filter : Filtre d'entité pour le ciblage combiné ('all', 'id_entité')
└── created_at : Date de création
AnonymousUser (pour Resalice)
├── id : Identifiant unique
├── device_id : Identifiant du dispositif
├── name : Nom temporaire (si fourni)
├── email : Email (si fourni)
├── created_at : Date de création
├── converted_to_user_id : ID utilisateur après conversion
└── metadata : Informations supplémentaires
```
#### Adaptations pour Hive
Ces modèles seront adaptés pour Hive avec leurs adaptateurs respectifs :
```dart
@HiveType(typeId: 20)
class ConversationModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String type;
@HiveField(2)
final String? title;
@HiveField(3)
final DateTime createdAt;
@HiveField(4)
final DateTime updatedAt;
@HiveField(5)
final List<ParticipantModel> participants;
@HiveField(6)
final bool isSynced;
@HiveField(7)
final String replyPermission;
@HiveField(8)
final bool isPinned;
@HiveField(9)
final DateTime? expiryDate;
// ... autres propriétés et méthodes
}
@HiveType(typeId: 21)
class MessageModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String conversationId;
@HiveField(2)
final String? senderId;
@HiveField(3)
final String senderType;
@HiveField(4)
final String content;
@HiveField(5)
final String contentType;
@HiveField(6)
final DateTime createdAt;
@HiveField(7)
final DateTime? deliveredAt;
@HiveField(8)
final DateTime? readAt;
@HiveField(9)
final String status;
@HiveField(10)
final bool isAnnouncement;
// ... autres propriétés et méthodes
}
@HiveType(typeId: 22)
class ParticipantModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String conversationId;
@HiveField(2)
final String? userId;
@HiveField(3)
final String? anonymousId;
@HiveField(4)
final String role;
@HiveField(5)
final DateTime joinedAt;
@HiveField(6)
final String? lastReadMessageId;
@HiveField(7)
final bool viaTarget;
@HiveField(8)
final bool? canReply;
// ... autres propriétés et méthodes
}
@HiveType(typeId: 23)
class AudienceTargetModel extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
final String conversationId;
@HiveField(2)
final String targetType;
@HiveField(3)
final String? targetId;
@HiveField(4)
final DateTime createdAt;
@HiveField(5)
final String? roleFilter; // 'all' ou ID de rôle
@HiveField(6)
final String? entityFilter; // 'all' ou ID d'entité
// ... autres propriétés et méthodes
}
```
### 3. Backend et API
#### Structure de l'API
L'API sera développée en PHP 8.3 pour s'intégrer avec vos systèmes existants :
```
/api/chat/conversations
GET - Liste des conversations de l'utilisateur
POST - Créer une nouvelle conversation
/api/chat/conversations/{id}
GET - Détails d'une conversation
PUT - Mettre à jour une conversation
DELETE - Supprimer une conversation
/api/chat/conversations/{id}/messages
GET - Messages d'une conversation (pagination)
POST - Envoyer un message
/api/chat/conversations/{id}/participants
GET - Liste des participants
POST - Ajouter un participant
DELETE - Retirer un participant
/api/chat/messages/{id}
PUT - Mettre à jour un message (ex: marquer comme lu)
DELETE - Supprimer un message
/api/chat/anonymous
POST - Démarrer une conversation anonyme
# Nouveaux endpoints pour les annonces
/api/chat/announcements
GET - Liste des annonces pour l'utilisateur
POST - Créer une nouvelle annonce
/api/chat/announcements/{id}/stats
GET - Obtenir les statistiques de lecture (qui a lu/non lu)
/api/chat/audience-targets
GET - Obtenir les cibles disponibles pour l'utilisateur actuel
/api/chat/conversations/{id}/pin
PUT - Épingler/désépingler une conversation
/api/chat/conversations/{id}/reply-permission
PUT - Modifier les permissions de réponse
```
#### Synchronisation
Le système supportera :
- Synchronisation en temps réel via WebSockets (optionnel)
- Synchronisation par polling avec gestion des messages non lus
- Enregistrement local des messages avec Hive pour le fonctionnement hors ligne
### 4. Widgets Flutter
#### Widgets principaux
1. **ChatScreen** : Écran principal d'une conversation
```dart
ChatScreen({
required String conversationId,
String? title,
Widget? header,
Widget? footer,
bool enableAttachments = true,
bool showTypingIndicator = true,
bool enableReadReceipts = true,
bool isAnnouncement = false,
bool canReply = true,
})
```
2. **ConversationsList** : Liste des conversations
```dart
ConversationsList({
List<ConversationModel>? conversations,
bool loadFromHive = true,
Function(ConversationModel)? onConversationSelected,
bool showLastMessage = true,
bool showUnreadCount = true,
bool showAnnouncementBadge = true,
bool showPinnedFirst = true,
Widget? emptyStateWidget,
})
```
3. **MessageBubble** : Bulle de message
```dart
MessageBubble({
required MessageModel message,
bool showSenderInfo = true,
bool showTimestamp = true,
bool showStatus = true,
bool isAnnouncement = false,
double maxWidth = 300,
})
```
4. **ChatInput** : Zone de saisie de message
```dart
ChatInput({
required Function(String) onSendText,
Function(File)? onSendFile,
Function(File)? onSendImage,
bool enableAttachments = true,
bool enabled = true,
String hintText = 'Saisissez votre message...',
String? disabledMessage = 'Vous ne pouvez pas répondre à cette annonce',
int? maxLength,
})
```
5. **AnonymousChatStarter** : Widget pour démarrer un chat anonyme (Resalice)
```dart
AnonymousChatStarter({
required Function(String?) onChatStarted,
bool requireName = false,
bool requireEmail = false,
String buttonLabel = 'Démarrer une conversation',
Widget? customForm,
})
```
6. **AnnouncementComposer** : Widget pour créer des annonces (Geosector uniquement)
```dart
AnnouncementComposer({
required Function(Map<String, dynamic>) onSend,
List<Map<String, dynamic>>? availableTargets,
String? initialTitle,
String? initialMessage,
bool allowAttachments = true,
bool allowPinning = true,
List<String> replyPermissionOptions = const ['all', 'admins_only', 'sender_only', 'none'],
String defaultReplyPermission = 'none',
DateTime? expiryDate,
bool isGeosector = true, // Active la sélection des destinataires
})
```
7. **AnnouncementTargetSelector** : Sélecteur de destinataires pour annonces (Geosector uniquement)
```dart
AnnouncementTargetSelector({
required Function(AudienceTargetModel) onTargetSelected,
required List<EntityModel> availableEntities,
bool showRoleFilter = true,
bool showEntityFilter = true,
String defaultRole = 'all',
String defaultEntity = 'all',
})
```
8. **AnnouncementBanner** : Bannière pour afficher une annonce importante
```dart
AnnouncementBanner({
required MessageModel announcement,
required Function() onView,
Function()? onDismiss,
bool isDismissible = true,
Duration? autoDismissAfter,
Color? backgroundColor,
Widget? icon,
})
```
#### Fonctionnalités des widgets
- Design adaptatif (mobile/web)
- Support des thèmes clairs/sombres
- Gestion des messages non lus
- Indicateurs de frappe
- Accusés de réception et de lecture
- Support des pièces jointes (fichiers, images)
- Recherche dans les conversations
- Conversion d'utilisateurs anonymes en clients (Resalice)
### 5. Gestion des données locales (Hive)
#### Organisation des boîtes Hive
```dart
// Noms des boîtes Hive
static const String conversationsBoxName = 'chat_conversations';
static const String messagesBoxName = 'chat_messages';
static const String participantsBoxName = 'chat_participants';
static const String anonymousUsersBoxName = 'chat_anonymous_users';
```
#### Stratégie de synchronisation
1. **Ouverture sélective** : Ouverture des boîtes à la demande
2. **Gestion de conflit** : Stratégie pour résoudre les conflits entre données locales et serveur
3. **Nettoyage intelligent** : Suppression des messages anciens selon des règles configurables
4. **Marqueurs de synchronisation** : Tracking des messages synchronisés/non-synchronisés
## Implémentation technique
### 1. Structure des repositories
```dart
class ChatRepository {
// Gestion des conversations
Future<List<ConversationModel>> getConversations({bool forceRefresh = false});
Future<ConversationModel> getConversation(String id);
Future<ConversationModel> createConversation(Map<String, dynamic> data);
Future<void> deleteConversation(String id);
Future<void> pinConversation(String id, bool isPinned);
Future<void> updateReplyPermission(String id, String replyPermission);
// Gestion des messages
Future<List<MessageModel>> getMessages(String conversationId, {int page = 1, int limit = 50});
Future<MessageModel> sendMessage(String conversationId, Map<String, dynamic> messageData);
Future<void> markMessageAsRead(String messageId);
// Gestion des participants
Future<void> addParticipant(String conversationId, Map<String, dynamic> participantData);
Future<void> removeParticipant(String conversationId, String participantId);
// Gestion des utilisateurs anonymes (Resalice)
Future<String> createAnonymousUser({String? name, String? email});
Future<void> convertAnonymousToUser(String anonymousId, String userId);
// Gestion des annonces
Future<List<ConversationModel>> getAnnouncements({bool forceRefresh = false});
Future<ConversationModel> createAnnouncement(Map<String, dynamic> data);
Future<Map<String, dynamic>> getAnnouncementStats(String conversationId);
// Gestion des cibles d'audience
Future<List<Map<String, dynamic>>> getAvailableAudienceTargets();
Future<void> addAudienceTarget(String conversationId, Map<String, dynamic> targetData);
Future<void> removeAudienceTarget(String conversationId, String targetId);
}
```
### 2. Intégration avec l'API
```dart
class ChatApiService {
final String baseUrl;
final String? authToken;
// Constructeur avec paramètres pour l'URL et l'authentification
ChatApiService({
required this.baseUrl,
this.authToken,
});
// Méthodes HTTP pour communiquer avec l'API
Future<Map<String, dynamic>> fetchConversations();
Future<Map<String, dynamic>> fetchMessages(String conversationId, {int page = 1, int limit = 50});
Future<Map<String, dynamic>> createConversation(Map<String, dynamic> data);
Future<Map<String, dynamic>> sendMessage(String conversationId, Map<String, dynamic> messageData);
// ...autres méthodes
}
```
### 3. Gestion hors ligne
```dart
class OfflineQueueService {
// Ajouter des opérations en attente
Future<void> addPendingOperation(String operationType, Map<String, dynamic> data);
// Traiter les opérations en attente
Future<void> processPendingOperations();
// Écouter les changements de connectivité
void listenToConnectivityChanges();
}
```
### 4. Stockage des fichiers
Le système supportera le téléchargement et le partage de fichiers :
1. **Côté serveur** : Stockage dans un répertoire sécurisé avec restriction d'accès
2. **Côté client** : Mise en cache des fichiers pour éviter des téléchargements redondants
3. **Types supportés** : Images, documents, autres fichiers selon configuration
## Cas d'utilisation spécifiques
### 1. Geosector
- **Utilisateurs authentifiés uniquement**
- **Groupes par équipe** avec administrateurs pour les communications internes
- **Historique complet** des conversations
- **Intégration avec la structure existante** des amicales et équipes
- **Annonces et broadcasts**:
- Super admin → tous les admins d'entités
- Admin d'entité → tous les utilisateurs de son entité
- Communications descendantes sans possibilité de réponse
- Statistiques de lecture des annonces importantes
- **Ciblage flexible des destinataires** :
- Par entité (toutes ou une spécifique)
- Par rôle (tous, membres, administrateurs)
- Combinaison entité + rôle (ex: admins de l'entité 5)
- Sélection via le widget `AnnouncementTargetSelector`
### 2. Resalice
- **Chats initiés par des anonymes**
- **Conversation one-to-one uniquement** entre professionnel et client/prospect
- **Conversion client** : Processus pour transformer un utilisateur anonyme en client référencé
- **Conservation des historiques** après conversion
- **Interface professionnelle** adaptée aux échanges client/professionnel
- **Pas de fonctionnalité d'annonce** - uniquement des conversations directes
- **Annonces non pertinentes** pour ce cas d'usage (pas de widget `AnnouncementTargetSelector`)
### Adaptations par projet
La solution de chat doit être adaptable selon le contexte :
1. **Configuration globale** : Un système de configuration permet de définir quelles fonctionnalités sont activées
```dart
// Configuration pour Geosector
const chatConfig = ChatConfig(
enableAnnouncements: true,
enableTargetSelection: true,
showAnnouncementStats: true,
defaultReplyPermission: 'none',
);
// Configuration pour Resalice
const chatConfig = ChatConfig(
enableAnnouncements: false,
enableTargetSelection: false,
showAnnouncementStats: false,
defaultReplyPermission: 'all',
);
```
2. **Interfaces conditionnelles** : Les widgets adaptent leur affichage selon la configuration
```dart
// Dans AnnouncementComposer
if (config.enableTargetSelection) {
children.add(AnnouncementTargetSelector(...));
}
```
3. **Types de conversation limités** : La création de certains types de conversation est restreinte
```dart
// Dans Resalice, seuls les types one_to_one et anonymous sont autorisés
if (!config.enableAnnouncements && type == 'announcement') {
throw UnsupportedConversationType();
}
```
## Adaptabilité et extensibilité
### 1. Options de personnalisation
- **Thèmes** : Adaptation aux couleurs et styles de l'application
- **Fonctionnalités** : Activation/désactivation de certaines fonctionnalités
- **Comportements** : Configuration des notifications, comportement hors ligne, etc.
### 2. Extensions possibles
- **Chatbot** : Possibilité d'intégrer des réponses automatiques
- **Transfert** : Transfert de conversations entre professionnels
- **Intégration CRM** : Liaison avec des systèmes CRM pour le suivi client
- **Analyse** : Statistiques sur les conversations, temps de réponse, etc.
## Étapes d'implémentation suggérées
1. **Phase 1 : Base du système** (3-4 semaines)
- Modèles de données et adaptateurs Hive
- Configuration de l'API backend
- Widgets de base pour affichage/envoi de messages
- Structure de base pour les annonces et broadcasts
2. **Phase 2 : Fonctionnalités avancées** (2-3 semaines)
- Gestion hors ligne et synchronisation
- Support des fichiers et images
- Indicateurs de lecture et d'écriture
- Système de ciblage d'audience pour les annonces
3. **Phase 3 : Cas spécifiques** (2-3 semaines)
- Support des conversations anonymes (Resalice)
- Groupes et permissions avancées (Geosector)
- Statistiques de lecture des annonces
- Interface administrateur pour les annonces globales
- Intégration web complète
Le temps total d'implémentation pour Geosector est estimé à 6-9 semaines pour un développeur expérimenté en Flutter et PHP. L'adaptation ultérieure à Resalice devrait prendre environ 2-3 semaines supplémentaires grâce à la conception modulaire du système.
## Conclusion
Cette solution de chat personnalisée offre un équilibre entre robustesse et simplicité d'intégration. Elle répond aux besoins spécifiques de vos applications tout en restant suffisamment flexible pour s'adapter à d'autres contextes.
Le système prend en charge non seulement les conversations classiques (one-to-one, groupes) mais aussi les communications de type annonce/broadcast où un administrateur peut communiquer des informations importantes à des groupes d'utilisateurs définis par rôle ou entité, avec ou sans possibilité de réponse. Cette fonctionnalité est particulièrement adaptée aux cas d'usage mentionnés pour Geosector, où l'admin général souhaite communiquer avec tous les admins d'entités, ou un admin d'entité avec tous les utilisateurs de son entité.
En développant cette solution en interne, vous gardez un contrôle total sur les fonctionnalités et l'expérience utilisateur, tout en assurant une cohérence avec le reste de vos applications. La conception modulaire et réutilisable permettra également un déploiement efficace sur vos différentes plateformes et applications.

View File

@@ -0,0 +1,200 @@
# Diagramme Relationnel de la Base de Données Geosector
```mermaid
erDiagram
%% Tables de référence (x_*)
x_devises ||--o{ x_pays : "fk_devise"
x_pays ||--o{ x_regions : "fk_pays"
x_regions ||--o{ x_departements : "fk_region"
x_regions ||--o{ entites : "fk_region"
x_entites_types ||--o{ entites : "fk_type"
x_departements ||--o{ x_villes : "fk_departement"
%% Utilisateurs et entités
entites ||--o{ users : "fk_entite"
entites ||--o{ operations : "fk_entite"
x_users_roles ||--o{ users : "fk_role"
x_users_titres ||--o{ users : "fk_titre"
%% Opérations et secteurs
operations ||--o{ ope_sectors : "fk_operation"
operations ||--o{ ope_users : "fk_operation"
operations ||--o{ ope_users_sectors : "fk_operation"
operations ||--o{ ope_pass : "fk_operation"
users ||--o{ ope_users : "fk_user"
users ||--o{ ope_users_sectors : "fk_user"
users ||--o{ ope_pass : "fk_user"
users ||--o{ ope_pass_histo : "fk_user"
ope_sectors ||--o{ ope_users_sectors : "fk_sector"
ope_sectors ||--o{ sectors_adresses : "fk_sector"
ope_sectors ||--o{ ope_pass : "fk_sector"
ope_pass ||--o{ ope_pass_histo : "fk_pass"
x_types_reglements ||--o{ ope_pass : "fk_type_reglement"
%% Système de chat
chat_rooms ||--o{ chat_participants : "id_room"
chat_rooms ||--o{ chat_messages : "fk_room"
chat_rooms ||--o{ chat_listes_diffusion : "fk_room"
chat_rooms ||--o{ chat_notifications : "fk_room"
users ||--o{ chat_rooms : "fk_user"
users ||--o{ chat_participants : "id_user"
users ||--o{ chat_messages : "fk_user"
users ||--o{ chat_listes_diffusion : "fk_user"
users ||--o{ chat_read_messages : "fk_user"
users ||--o{ chat_notifications : "fk_user"
chat_messages ||--o{ chat_read_messages : "fk_message"
chat_messages ||--o{ chat_notifications : "fk_message"
%% Définition des entités avec leurs attributs principaux
x_devises {
int_unsigned id PK
string code
string symbole
string libelle
tinyint_unsigned chk_active
}
x_pays {
int_unsigned id PK
int_unsigned fk_continent FK
int_unsigned fk_devise FK
string libelle
tinyint_unsigned chk_active
}
x_regions {
int_unsigned id PK
int_unsigned fk_pays FK
string libelle
tinyint_unsigned chk_active
}
x_departements {
int_unsigned id PK
string code
int_unsigned fk_region FK
string libelle
tinyint_unsigned chk_active
}
x_villes {
int_unsigned id PK
int_unsigned fk_departement FK
string libelle
string cp
tinyint_unsigned chk_active
}
entites {
int_unsigned id PK
string libelle
int_unsigned fk_region FK
int_unsigned fk_type FK
tinyint_unsigned chk_demo
tinyint_unsigned chk_active
}
users {
int_unsigned id PK
int_unsigned fk_entite FK
int_unsigned fk_role FK
int_unsigned fk_titre FK
string encrypted_name
string encrypt_user_name
string encrypt_password
tinyint_unsigned chk_active
}
operations {
int_unsigned id PK
int_unsigned fk_entite FK
string libelle
date date_deb
date date_fin
tinyint_unsigned chk_active
}
ope_sectors {
int_unsigned id PK
int_unsigned fk_operation FK
string libelle
tinyint_unsigned chk_active
}
ope_users {
int_unsigned id PK
int_unsigned fk_operation FK
int_unsigned fk_user FK
tinyint_unsigned chk_active
}
ope_users_sectors {
int_unsigned id PK
int_unsigned fk_operation FK
int_unsigned fk_user FK
int_unsigned fk_sector FK
tinyint_unsigned chk_active
}
sectors_adresses {
int_unsigned id PK
string fk_adresse
int_unsigned osm_id
int_unsigned fk_sector FK
string rue
string cp
string ville
}
ope_pass {
int_unsigned id PK
int_unsigned fk_operation FK
int_unsigned fk_sector FK
int_unsigned fk_user FK
int_unsigned fk_type_reglement FK
timestamp passed_at
tinyint_unsigned chk_active
}
ope_pass_histo {
int_unsigned id PK
int_unsigned fk_pass FK
int_unsigned fk_user FK
}
chat_rooms {
int_unsigned id PK
string name
enum type
int_unsigned fk_user FK
int_unsigned fk_entite FK
}
chat_messages {
int_unsigned id PK
int_unsigned fk_room FK
int_unsigned fk_user FK
text content
enum statut
}
chat_read_messages {
bigint_unsigned id PK
int_unsigned fk_message FK
int_unsigned fk_user FK
timestamp date_read
}
chat_notifications {
bigint_unsigned id PK
int_unsigned fk_user FK
int_unsigned fk_message FK
int_unsigned fk_room FK
string type
}
```

623
docs/geosector-db.sql Normal file
View File

@@ -0,0 +1,623 @@
-- Création de la base de données geo_app si elle n'existe pas
DROP DATABASE IF EXISTS `geo_app`;
CREATE DATABASE IF NOT EXISTS `geo_app` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- Création de l'utilisateur et attribution des droits
CREATE USER IF NOT EXISTS 'geo_app_user'@'localhost' IDENTIFIED BY 'QO:96df*?k{4W6m';
GRANT SELECT, INSERT, UPDATE, DELETE ON `geo_app`.* TO 'geo_app_user'@'localhost';
FLUSH PRIVILEGES;
USE geo_app;
--
-- Table structure for table `email_counter`
--
DROP TABLE IF EXISTS `email_counter`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `email_counter` (
`id` int unsigned NOT NULL DEFAULT '1',
`hour_start` timestamp NULL DEFAULT NULL,
`count` int unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `x_devises`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_devises` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`code` varchar(3) DEFAULT NULL,
`symbole` varchar(6) DEFAULT NULL,
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `x_entites_types`
--
DROP TABLE IF EXISTS `x_entites_types`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_entites_types` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `x_types_passages`
--
DROP TABLE IF EXISTS `x_types_passages`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_types_passages` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`color_button` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`color_mark` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`color_table` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `x_types_reglements`
--
DROP TABLE IF EXISTS `x_types_reglements`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_types_reglements` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `x_users_roles`
--
DROP TABLE IF EXISTS `x_users_roles`;
CREATE TABLE `x_users_roles` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Les différents rôles des utilisateurs';
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `x_users_titres`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_users_titres` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Les différents titres des utilisateurs';
DROP TABLE IF EXISTS `x_pays`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_pays` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`code` varchar(3) DEFAULT NULL,
`fk_continent` int unsigned DEFAULT NULL,
`fk_devise` int unsigned DEFAULT '1',
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
CONSTRAINT `x_pays_ibfk_1` FOREIGN KEY (`fk_devise`) REFERENCES `x_devises` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Table des pays avec leurs codes';
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `x_regions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_regions` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_pays` int unsigned DEFAULT '1',
`libelle` varchar(45) DEFAULT NULL,
`libelle_long` varchar(45) DEFAULT NULL,
`table_osm` varchar(45) DEFAULT NULL,
`departements` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
CONSTRAINT `x_regions_ibfk_1` FOREIGN KEY (`fk_pays`) REFERENCES `x_pays` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `x_departements`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_departements` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`code` varchar(3) DEFAULT NULL,
`fk_region` int unsigned DEFAULT '1',
`libelle` varchar(45) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
CONSTRAINT `x_departements_ibfk_1` FOREIGN KEY (`fk_region`) REFERENCES `x_regions` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `entites`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `entites` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`encrypted_name` varchar(255) DEFAULT NULL,
`adresse1` varchar(45) DEFAULT '',
`adresse2` varchar(45) DEFAULT '',
`cp` varchar(5) DEFAULT '',
`ville` varchar(45) DEFAULT '',
`fk_region` int unsigned DEFAULT NULL,
`fk_type` int unsigned DEFAULT '1',
`encrypted_phone` varchar(128) DEFAULT '',
`encrypted_mobile` varchar(128) DEFAULT '',
`encrypted_email` varchar(255) DEFAULT '',
`gps_lat` varchar(20) NOT NULL DEFAULT '',
`gps_lng` varchar(20) NOT NULL DEFAULT '',
`encrypted_stripe_id` varchar(255) DEFAULT '',
`iban` varchar(30) DEFAULT '',
`bic` varchar(15) DEFAULT '',
`chk_demo` tinyint(1) unsigned DEFAULT '1',
`chk_mdp_manuel` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT 'Gestion des mots de passe manuelle O/N',
`chk_copie_mail_recu` tinyint(1) unsigned NOT NULL DEFAULT '0',
`chk_accept_sms` tinyint(1) unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
CONSTRAINT `entites_ibfk_1` FOREIGN KEY (`fk_region`) REFERENCES `x_regions` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `entites_ibfk_2` FOREIGN KEY (`fk_type`) REFERENCES `x_entites_types` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `x_villes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_villes` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_departement` int unsigned DEFAULT '1',
`libelle` varchar(65) DEFAULT NULL,
`cp` varchar(5) DEFAULT NULL,
`code_insee` varchar(5) DEFAULT NULL,
`departement` varchar(65) DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
CONSTRAINT `x_villes_ibfk_1` FOREIGN KEY (`fk_departement`) REFERENCES `x_departements` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=38950 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_entite` int unsigned DEFAULT '1',
`fk_role` int unsigned DEFAULT '1',
`fk_titre` int unsigned DEFAULT '1',
`num_adherent` int unsigned NOT NULL DEFAULT '0',
`encrypted_name` varchar(255) DEFAULT NULL,
`first_name` varchar(45) DEFAULT NULL,
`sect_name` varchar(60) DEFAULT '',
`encrypt_user_name` varchar(128) DEFAULT '',
`user_pswd` varchar(60) DEFAULT NULL,
`encrypt_phone` varchar(128) DEFAULT NULL,
`encrypt_mobile` varchar(128) DEFAULT NULL,
`encrypt_email` varchar(255) DEFAULT '',
`infos` varchar(200) NOT NULL DEFAULT '',
`chk_alert_email` tinyint(1) unsigned DEFAULT '1',
`chk_suivi` tinyint(1) unsigned DEFAULT '0',
`date_naissance` date DEFAULT NULL,
`date_embauche` date DEFAULT NULL,
`anciennete` varchar(20) DEFAULT '-',
`matricule` varchar(10) NOT NULL DEFAULT '',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
KEY `fk_entite` (`fk_entite`),
KEY `username` (`encrypt_user_name`),
CONSTRAINT `users_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `users_ibfk_2` FOREIGN KEY (`fk_role`) REFERENCES `x_users_roles` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `users_ibfk_3` FOREIGN KEY (`fk_titre`) REFERENCES `x_users_titres` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `operations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `operations` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_entite` int unsigned NOT NULL DEFAULT '1',
`libelle` varchar(75) NOT NULL DEFAULT '',
`date_deb` date NOT NULL DEFAULT '0000-00-00',
`date_fin` date NOT NULL DEFAULT '0000-00-00',
`chk_distinct_sectors` tinyint(1) unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned NOT NULL DEFAULT '0',
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `fk_entite` (`fk_entite`),
KEY `date_deb` (`date_deb`),
CONSTRAINT `operations_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `ope_sectors`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_sectors` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_operation` int unsigned NOT NULL DEFAULT '0',
`libelle` varchar(75) NOT NULL DEFAULT '',
`sector` text NOT NULL DEFAULT '',
`color` varchar(7) NOT NULL DEFAULT '#4B77BE',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned NOT NULL DEFAULT '0',
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `fk_operation` (`fk_operation`),
CONSTRAINT `ope_sectors_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `ope_users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_users` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_operation` int unsigned NOT NULL DEFAULT '0',
`fk_user` int unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned DEFAULT NULL,
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
CONSTRAINT `ope_users_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_users_ibfk_2` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `email_queue`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `email_queue` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_pass` int unsigned NOT NULL DEFAULT '0',
`to_email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`subject` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`body` text COLLATE utf8mb4_unicode_ci,
`headers` text COLLATE utf8mb4_unicode_ci,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`status` enum('pending','sent','failed') COLLATE utf8mb4_unicode_ci DEFAULT 'pending',
`attempts` int unsigned DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `ope_users_sectors`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_users_sectors` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_operation` int unsigned NOT NULL DEFAULT '0',
`fk_user` int unsigned NOT NULL DEFAULT '0',
`fk_sector` int unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned DEFAULT NULL,
`chk_active` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `fk_operation` (`fk_operation`),
KEY `fk_user` (`fk_user`),
KEY `fk_sector` (`fk_sector`),
CONSTRAINT `ope_users_sectors_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_users_sectors_ibfk_2` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_users_sectors_ibfk_3` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `ope_users_suivis`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_users_suivis` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_operation` int unsigned NOT NULL DEFAULT '0',
`fk_user` int unsigned NOT NULL DEFAULT '0',
`date_suivi` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date du suivi',
`gps_lat` varchar(20) NOT NULL DEFAULT '',
`gps_lng` varchar(20) NOT NULL DEFAULT '',
`vitesse` varchar(20) NOT NULL DEFAULT '',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `sectors_adresses`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `sectors_adresses` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_adresse` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'adresses.cp??.id',
`osm_id` int unsigned NOT NULL DEFAULT '0',
`fk_sector` int unsigned NOT NULL DEFAULT '0',
`osm_name` varchar(50) NOT NULL DEFAULT '',
`numero` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`rue_bis` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`rue` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`cp` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`ville` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`gps_lat` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`gps_lng` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`osm_date_creat` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
PRIMARY KEY (`id`),
KEY `sectors_adresses_fk_sector_index` (`fk_sector`),
KEY `sectors_adresses_numero_index` (`numero`),
KEY `sectors_adresses_rue_index` (`rue`),
KEY `sectors_adresses_ville_index` (`ville`),
CONSTRAINT `sectors_adresses_ibfk_1` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `ope_pass`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_pass` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_operation` int unsigned NOT NULL DEFAULT '0',
`fk_sector` int unsigned DEFAULT '0',
`fk_user` int unsigned NOT NULL DEFAULT '0',
`fk_adresse` varchar(25) DEFAULT '' COMMENT 'adresses.cp??.id',
`passed_at` timestamp NULL DEFAULT NULL COMMENT 'Date du passage',
`fk_type` int unsigned DEFAULT '0',
`numero` varchar(10) NOT NULL DEFAULT '',
`rue` varchar(75) NOT NULL DEFAULT '',
`rue_bis` varchar(1) NOT NULL DEFAULT '',
`ville` varchar(75) NOT NULL DEFAULT '',
`fk_habitat` int unsigned DEFAULT '1',
`appt` varchar(5) DEFAULT '',
`niveau` varchar(5) DEFAULT '',
`residence` varchar(75) DEFAULT '',
`gps_lat` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`gps_lng` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`libelle` varchar(45) NOT NULL DEFAULT '',
`montant` decimal(7,2) NOT NULL DEFAULT '0.00',
`fk_type_reglement` int unsigned DEFAULT '1',
`remarque` text DEFAULT '',
`email` varchar(75) DEFAULT '',
`nom_recu` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`date_recu` timestamp NULL DEFAULT NULL COMMENT 'Date de réception',
`date_creat_recu` timestamp NULL DEFAULT NULL COMMENT 'Date de création du reçu',
`date_sent_recu` timestamp NULL DEFAULT NULL COMMENT 'Date envoi du reçu',
`email_erreur` varchar(30) DEFAULT '',
`chk_email_sent` tinyint(1) unsigned NOT NULL DEFAULT '0',
`phone` varchar(15) NOT NULL DEFAULT '',
`docremis` tinyint(1) unsigned DEFAULT '0',
`date_repasser` timestamp NULL DEFAULT NULL COMMENT 'Date prévue pour repasser',
`nb_passages` int DEFAULT '1' COMMENT 'Nb passages pour les a repasser',
`chk_gps_maj` tinyint(1) unsigned DEFAULT '0',
`chk_map_create` tinyint(1) unsigned DEFAULT '0',
`chk_mobile` tinyint(1) unsigned DEFAULT '0',
`chk_synchro` tinyint(1) unsigned DEFAULT '1' COMMENT 'chk synchro entre web et appli',
`chk_api_adresse` tinyint(1) unsigned DEFAULT '0',
`chk_maj_adresse` tinyint(1) unsigned DEFAULT '0',
`anomalie` tinyint(1) unsigned DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
`fk_user_creat` int unsigned DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date de modification',
`fk_user_modif` int unsigned DEFAULT NULL,
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `fk_operation` (`fk_operation`),
KEY `fk_sector` (`fk_sector`),
KEY `fk_user` (`fk_user`),
KEY `fk_type` (`fk_type`),
KEY `fk_type_reglement` (`fk_type_reglement`),
KEY `email` (`email`),
CONSTRAINT `ope_pass_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_pass_ibfk_2` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_pass_ibfk_3` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT `ope_pass_ibfk_4` FOREIGN KEY (`fk_type_reglement`) REFERENCES `x_types_reglements` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `ope_pass_histo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `ope_pass_histo` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`fk_pass` int unsigned NOT NULL DEFAULT '0',
`fk_user` int unsigned NOT NULL DEFAULT '0',
`date_histo` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date historique',
`sujet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`remarque` varchar(250) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `ope_pass_histo_fk_pass_IDX` (`fk_pass`) USING BTREE,
KEY `ope_pass_histo_date_histo_IDX` (`date_histo`) USING BTREE,
CONSTRAINT `ope_pass_histo_ibfk_1` FOREIGN KEY (`fk_pass`) REFERENCES `ope_pass` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `ope_pass_histo_ibfk_2` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `medias`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `medias` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`support` varchar(45) NOT NULL DEFAULT '',
`support_id` int unsigned NOT NULL DEFAULT '0',
`fichier` varchar(250) NOT NULL DEFAULT '',
`description` varchar(100) NOT NULL DEFAULT '',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`fk_user_creat` int unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`fk_user_modif` int unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-- Création des tables pour le système de chat
DROP TABLE IF EXISTS `chat_rooms`;
-- Table des salles de discussion
CREATE TABLE chat_rooms (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
type ENUM('privee', 'groupe', 'liste_diffusion') NOT NULL,
date_creation timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
fk_user INT UNSIGNED NOT NULL,
fk_entite INT UNSIGNED,
statut ENUM('active', 'archive') NOT NULL DEFAULT 'active',
description TEXT,
INDEX idx_user (fk_user),
INDEX idx_entite (fk_entite)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `chat_participants`;
-- Table des participants aux salles de discussion
CREATE TABLE chat_participants (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
id_room INT UNSIGNED NOT NULL,
id_user INT UNSIGNED NOT NULL,
role ENUM('administrateur', 'participant', 'en_lecture_seule') NOT NULL DEFAULT 'participant',
date_ajout timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date ajout',
notification_activee BOOLEAN NOT NULL DEFAULT TRUE,
INDEX idx_room (id_room),
INDEX idx_user (id_user),
CONSTRAINT uc_room_user UNIQUE (id_room, id_user),
FOREIGN KEY (id_room) REFERENCES chat_rooms(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `chat_messages`;
-- Table des messages
CREATE TABLE chat_messages (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
fk_room INT UNSIGNED NOT NULL,
fk_user INT UNSIGNED NOT NULL,
content TEXT,
date_sent timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date envoi',
type ENUM('texte', 'media', 'systeme') NOT NULL DEFAULT 'texte',
statut ENUM('envoye', 'livre', 'lu') NOT NULL DEFAULT 'envoye',
INDEX idx_room (fk_room),
INDEX idx_user (fk_user),
INDEX idx_date (date_sent),
FOREIGN KEY (fk_room) REFERENCES chat_rooms(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `chat_listes_diffusion`;
-- Table des listes de diffusion
CREATE TABLE chat_listes_diffusion (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
fk_room INT UNSIGNED NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
fk_user INT UNSIGNED NOT NULL,
date_creation timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
INDEX idx_room (fk_room),
INDEX idx_user (fk_user),
FOREIGN KEY (fk_room) REFERENCES chat_rooms(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `chat_read_messages`;
-- Table pour suivre la lecture des messages
CREATE TABLE chat_read_messages (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
fk_message INT UNSIGNED NOT NULL,
fk_user INT UNSIGNED NOT NULL,
date_read timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de lecture',
INDEX idx_message (fk_message),
INDEX idx_user (fk_user),
CONSTRAINT uc_message_user UNIQUE (fk_message, fk_user),
FOREIGN KEY (fk_message) REFERENCES chat_messages(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `chat_notifications`;
-- Table des notifications
CREATE TABLE chat_notifications (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
fk_user INT UNSIGNED NOT NULL,
fk_message INT UNSIGNED,
fk_room INT UNSIGNED,
type VARCHAR(50) NOT NULL,
contenu TEXT,
date_creation timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date de création',
date_lecture timestamp NULL DEFAULT NULL COMMENT 'Date de lecture',
statut ENUM('non_lue', 'lue') NOT NULL DEFAULT 'non_lue',
INDEX idx_user (fk_user),
INDEX idx_message (fk_message),
INDEX idx_room (fk_room),
FOREIGN KEY (fk_message) REFERENCES chat_messages(id) ON DELETE SET NULL,
FOREIGN KEY (fk_room) REFERENCES chat_rooms(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `z_params`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `params` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`libelle` varchar(35) NOT NULL DEFAULT '',
`valeur` varchar(255) NOT NULL DEFAULT '',
`aide` varchar(150) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `z_sessions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `z_sessions` (
`sid` text NOT NULL,
`fk_user` int NOT NULL,
`role` varchar(10) DEFAULT NULL,
`date_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`ip` varchar(50) NOT NULL,
`browser` varchar(150) NOT NULL,
`data` mediumtext
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

280
docs/gestion_hive_boxes.md Normal file
View File

@@ -0,0 +1,280 @@
# Guide de Gestion des Boîtes Hive dans GeoSector
Ce document explique comment les boîtes Hive sont gérées dans l'application GeoSector, particulièrement pendant les processus de connexion et déconnexion.
## Table des matières
1. [Introduction](#introduction)
2. [Boîtes Hive utilisées](#boîtes-hive-utilisées)
3. [Initialisation des boîtes Hive](#initialisation-des-boîtes-hive)
4. [Services et repositories impliqués](#services-et-repositories-impliqués)
5. [Processus de connexion (login)](#processus-de-connexion-login)
6. [Processus de déconnexion (logout)](#processus-de-déconnexion-logout)
7. [Problèmes connus et solutions](#problèmes-connus-et-solutions)
8. [Bonnes pratiques](#bonnes-pratiques)
## Introduction
Hive est une base de données NoSQL légère et rapide utilisée dans GeoSector pour stocker les données localement. Les données sont organisées en "boîtes" (boxes) qui peuvent être typées pour stocker des modèles spécifiques.
Dans cette application, Hive est utilisé pour :
- Stocker les données utilisateur et maintenir les sessions
- Conserver les données des opérations, secteurs et passages
- Permettre l'utilisation de l'application en mode hors ligne
## Boîtes Hive utilisées
Les boîtes Hive sont définies dans `lib/core/constants/app_keys.dart` :
```dart
// Noms des boîtes Hive
static const String usersBoxName = 'users';
static const String operationsBoxName = 'operations';
static const String sectorsBoxName = 'sectors';
static const String passagesBoxName = 'passages';
static const String settingsBoxName = 'settings';
```
Chaque boîte stocke un type spécifique de données :
- **users** : Stocke les informations des utilisateurs (`UserModel`)
- **operations** : Stocke les opérations (`OperationModel`)
- **sectors** : Stocke les secteurs (`SectorModel`)
- **passages** : Stocke les passages (`PassageModel`)
- **settings** : Stocke les préférences utilisateur (non typée)
## Initialisation des boîtes Hive
Actuellement, les boîtes Hive sont initialisées dès le démarrage de l'application dans `main.dart` :
```dart
// Initialiser Hive
await Hive.initFlutter();
// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());
// Ouvrir les boîtes Hive
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
await Hive.openBox<OperationModel>(AppKeys.operationsBoxName);
await Hive.openBox<SectorModel>(AppKeys.sectorsBoxName);
await Hive.openBox<PassageModel>(AppKeys.passagesBoxName);
await Hive.openBox(AppKeys.settingsBoxName);
```
### Problème d'initialisation précoce
Cette approche ouvre toutes les boîtes Hive dès le démarrage de l'application, même sur les pages publiques comme `LandingPage` où elles ne sont pas nécessaires. Cela explique pourquoi vous voyez les messages suivants dans la console :
```
Got object store box in database users.
Got object store box in database operations.
Got object store box in database sectors.
Got object store box in database passages.
Got object store box in database settings.
```
### Solution recommandée
Pour optimiser l'initialisation des boîtes Hive, il est recommandé de :
1. N'initialiser que la boîte `users` au démarrage (pour vérifier si un utilisateur est déjà connecté)
2. Initialiser les autres boîtes uniquement après une connexion réussie
Modification suggérée pour `main.dart` :
```dart
// Initialiser Hive
await Hive.initFlutter();
// Enregistrer les adaptateurs Hive
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(OperationModelAdapter());
Hive.registerAdapter(SectorModelAdapter());
Hive.registerAdapter(PassageModelAdapter());
// N'ouvrir que la boîte des utilisateurs au démarrage
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
await Hive.openBox(AppKeys.settingsBoxName); // Préférences générales
// Les autres boîtes seront ouvertes après connexion dans UserRepository.login()
```
## Services et repositories impliqués
### UserRepository
Le `UserRepository` est le principal gestionnaire des boîtes Hive. Il est responsable de :
- L'initialisation des boîtes au démarrage de l'application
- La gestion des boîtes pendant les processus de connexion et déconnexion
- Le nettoyage et la recréation des boîtes lorsque nécessaire
### Autres repositories spécialisés
- **OperationRepository** : Gère la boîte `operations`
- **SectorRepository** : Gère la boîte `sectors`
- **PassageRepository** : Gère la boîte `passages`
Ces repositories sont injectés dans le `UserRepository` pour traiter les données spécifiques à chaque modèle.
## Processus de connexion (login)
Le processus de connexion dans `UserRepository.login()` suit ces étapes :
1. **Nettoyage initial** :
- Suppression des boîtes non référencées (`auth`, `locations`, `messages`)
- Nettoyage adapté à la plateforme (Web, iOS, Android)
2. **Préparation des boîtes** :
- Appel à `_clearAndRecreateBoxes()` pour vider et recréer les boîtes sans les fermer
- Utilisation de `_ensureBoxIsOpen()` pour garantir que les boîtes sont ouvertes
3. **Appel API et traitement des données** :
- Connexion via l'API
- Vérification que toutes les boîtes sont ouvertes avant le traitement
- Traitement des données reçues (opérations, secteurs, passages)
4. **Gestion des erreurs** :
- Tentatives de récupération en cas d'erreur
- Réouverture des boîtes si nécessaire
### Code clé pour la connexion
```dart
// S'assurer que les boîtes sont ouvertes
await _ensureBoxIsOpen(AppKeys.operationsBoxName);
await _ensureBoxIsOpen(AppKeys.sectorsBoxName);
await _ensureBoxIsOpen(AppKeys.passagesBoxName);
// Traiter les données
await _processOperations(operationsData);
await _processSectors(sectorsData);
await _processPassages(passagesData);
```
## Processus de déconnexion (logout)
Le processus de déconnexion dans `UserRepository.logout()` suit ces étapes :
1. **Préparation** :
- S'assurer que la boîte des utilisateurs est ouverte
- Suppression des boîtes non référencées
2. **Gestion de l'utilisateur** :
- Récupération de l'utilisateur actuel avant nettoyage
- Déconnexion de la session API
- Mise à jour de l'utilisateur pour effacer les données de session
3. **Nettoyage des données** :
- Nettoyage adapté à la plateforme (Web, iOS, Android)
- Appel à `_clearAndRecreateBoxes()` pour vider les boîtes sans les fermer
### Code clé pour la déconnexion
```dart
// S'assurer que la boîte des utilisateurs est ouverte
await _ensureBoxIsOpen(AppKeys.usersBoxName);
// Récupérer l'utilisateur et effacer sa session
final updatedUser = currentUser.copyWith(
sessionId: null,
sessionExpiry: null,
lastPath: null
);
await saveUser(updatedUser);
// Vider les boîtes sans les fermer
await _clearAndRecreateBoxes();
```
## Problèmes connus et solutions
### 1. Initialisation précoce des boîtes Hive
**Problème** : Toutes les boîtes Hive sont ouvertes dès le démarrage de l'application, même sur les pages publiques où elles ne sont pas nécessaires.
**Solution** : Modifier `main.dart` pour n'ouvrir que les boîtes essentielles au démarrage (users et settings) et initialiser les autres boîtes uniquement après connexion.
### 2. Erreur "Box has already been closed"
**Problème** : Des erreurs se produisent lorsqu'on tente d'accéder à une boîte qui a été fermée prématurément.
**Solution** :
- Utiliser la méthode `_ensureBoxIsOpen()` avant d'accéder à une boîte
- Éviter de fermer les boîtes qui pourraient être utilisées plus tard
- Préférer `box.clear()` à `box.close()` pour vider les données sans fermer la boîte
### 3. Persistance indésirable des données entre sessions
**Problème** : Les données peuvent persister entre les sessions utilisateur, créant des conflits ou des fuites de données.
**Solution** : Utiliser `_clearAndRecreateBoxes()` lors de la déconnexion pour vider correctement toutes les boîtes sauf `users`.
## Bonnes pratiques
### Initialisation à la demande
1. **Initialiser les boîtes uniquement lorsqu'elles sont nécessaires** :
- N'ouvrir que les boîtes `users` et `settings` au démarrage
- Initialiser les autres boîtes après connexion réussie
- Utiliser `_ensureBoxIsOpen()` avant chaque accès à une boîte
2. **Centraliser la gestion des boîtes** :
- Créer un service dédié à la gestion des boîtes Hive
- Utiliser des méthodes comme `openRequiredBoxes()` et `clearAllBoxes()`
3. **Optimiser pour les différentes plateformes** :
- Adapter le nettoyage selon la plateforme (Web, iOS, Android)
- Utiliser des méthodes spécifiques comme `_clearIndexedDB()` pour le web
### Éviter l'erreur "Box has already been closed"
1. **Ne jamais fermer une boîte qui pourrait être utilisée plus tard** :
- Utiliser `_ensureBoxIsOpen()` au lieu de fermer et rouvrir les boîtes
- Vider les boîtes avec `box.clear()` au lieu de les fermer
2. **Vérifier qu'une boîte est ouverte avant de l'utiliser** :
```dart
if (!Hive.isBoxOpen(boxName)) {
await Hive.openBox<T>(boxName);
}
```
3. **Gestion des erreurs robuste** :
- Toujours entourer les opérations Hive de blocs try/catch
- Prévoir des mécanismes de récupération en cas d'erreur
### Méthode utilitaire _ensureBoxIsOpen
Cette méthode est cruciale pour garantir qu'une boîte est ouverte avant de l'utiliser :
```dart
Future<void> _ensureBoxIsOpen(String boxName) async {
try {
if (!Hive.isBoxOpen(boxName)) {
debugPrint('Ouverture de la boîte $boxName...');
if (boxName == AppKeys.passagesBoxName) {
await Hive.openBox<PassageModel>(boxName);
} else if (boxName == AppKeys.operationsBoxName) {
await Hive.openBox<OperationModel>(boxName);
} else if (boxName == AppKeys.sectorsBoxName) {
await Hive.openBox<SectorModel>(boxName);
} else if (boxName == AppKeys.usersBoxName) {
await Hive.openBox<UserModel>(boxName);
} else {
await Hive.openBox(boxName);
}
debugPrint('Boîte $boxName ouverte avec succès');
}
} catch (e) {
debugPrint('Erreur lors de l\'ouverture de la boîte $boxName: $e');
throw Exception('Impossible d\'ouvrir la boîte $boxName: $e');
}
}
```
---
Ce guide devrait aider à comprendre et maintenir la gestion des boîtes Hive dans l'application GeoSector. Pour toute question ou problème, consultez la documentation de Hive ou contactez l'équipe de développement.

356
docs/model_definitions.md Normal file
View File

@@ -0,0 +1,356 @@
# Modèles de données GEOSECTOR
## Description générale
GEOSECTOR utilise plusieurs modèles de données pour représenter les entités principales de l'application. Ces modèles sont utilisés à la fois pour la persistance locale via Hive et pour la communication avec l'API backend. Ce document décrit en détail chaque modèle, ses propriétés et ses méthodes.
## Intégration avec Hive
Tous les modèles sont annotés pour être utilisés avec Hive, une base de données NoSQL légère:
- Chaque modèle a un `typeId` unique pour Hive
- Les propriétés sont annotées avec `@HiveField` et un index unique
- Les modèles étendent `HiveObject` pour accéder aux fonctionnalités de persistance
## Modèle Utilisateur (UserModel)
**Description**: Représente un utilisateur de l'application, avec ses informations personnelles et de session.
### Propriétés
| Propriété | Type | Description | Hive Index |
| ------------- | --------- | ----------------------------------------- | ---------- |
| id | int | Identifiant unique | 0 |
| email | String | Adresse email | 1 |
| name | String? | Nom de l'utilisateur | 2 |
| username | String? | Nom d'utilisateur pour connexion | 11 |
| firstName | String? | Prénom de l'utilisateur | 10 |
| role | int | Rôle/niveau d'accès (1=user, 2/4/9=admin) | 3 |
| createdAt | DateTime | Date de création du compte | 4 |
| lastSyncedAt | DateTime | Dernière synchronisation avec le serveur | 5 |
| isActive | bool | Statut actif/inactif | 6 |
| isSynced | bool | Indique si synchronisé avec le serveur | 7 |
| sessionId | String? | Identifiant de session pour l'API | 8 |
| sessionExpiry | DateTime? | Date d'expiration de la session | 9 |
| lastPath | String? | Dernier chemin visité dans l'app | 12 |
| sectName | String? | Nom de la section/département | 13 |
| interface | String? | Type d'interface ('admin' ou 'user') | 14 |
### Méthodes
- **fromJson**: Convertit un objet JSON en UserModel
- **toJson**: Convertit un UserModel en objet JSON
- **copyWith**: Crée une copie avec des valeurs modifiées
- **hasValidSession**: Vérifie si la session est valide
- **clearSession**: Efface les données de session
### Exemple d'utilisation
```dart
// Créer un utilisateur
final user = UserModel(
id: 123,
email: "user@example.com",
name: "John Doe",
username: "johndoe",
role: 1,
createdAt: DateTime.now(),
lastSyncedAt: DateTime.now(),
isActive: true,
);
// Vérifier la validité de la session
if (user.hasValidSession) {
// Utiliser la session...
}
// Créer une version modifiée
final updatedUser = user.copyWith(
name: "John Smith",
isActive: false,
);
```
## Modèle Opération (OperationModel)
**Description**: Représente une opération de collecte avec ses dates et son statut.
### Propriétés
| Propriété | Type | Description | Hive Index |
| ------------ | -------- | ---------------------------------------- | ---------- |
| id | int | Identifiant unique | 0 |
| name | String | Nom de l'opération | 1 |
| dateDebut | DateTime | Date de début de l'opération | 2 |
| dateFin | DateTime | Date de fin de l'opération | 3 |
| lastSyncedAt | DateTime | Dernière synchronisation avec le serveur | 4 |
| isActive | bool | Statut actif/inactif | 5 |
| isSynced | bool | Indique si synchronisé avec le serveur | 6 |
### Méthodes
- **fromJson**: Convertit un objet JSON en OperationModel
- **toJson**: Convertit un OperationModel en objet JSON
- **copyWith**: Crée une copie avec des valeurs modifiées
### Exemple d'utilisation
```dart
// Créer une opération
final operation = OperationModel(
id: 456,
name: "Opération 2025",
dateDebut: DateTime(2025, 1, 1),
dateFin: DateTime(2025, 12, 31),
lastSyncedAt: DateTime.now(),
isActive: true,
);
// Créer une version modifiée
final updatedOperation = operation.copyWith(
name: "Opération 2025 - Printemps",
dateDebut: DateTime(2025, 3, 1),
dateFin: DateTime(2025, 6, 30),
);
```
## Modèle Secteur (SectorModel)
**Description**: Représente un secteur géographique avec ses coordonnées et son style.
### Propriétés
| Propriété | Type | Description | Hive Index |
| --------- | ------ | -------------------------------------------- | ---------- |
| id | int | Identifiant unique | 0 |
| libelle | String | Nom du secteur | 1 |
| color | String | Couleur au format hexadécimal (#RRGGBB) | 2 |
| sector | String | Coordonnées du polygone au format spécifique | 3 |
### Méthodes
- **fromJson**: Convertit un objet JSON en SectorModel
- **toJson**: Convertit un SectorModel en objet JSON
- **copyWith**: Crée une copie avec des valeurs modifiées
- **getCoordinates**: Extrait les coordonnées du polygone sous forme de liste
### Format des coordonnées
Le champ `sector` stocke les coordonnées du polygone dans un format spécifique:
```
lat1/lng1#lat2/lng2#lat3/lng3#...
```
Par exemple:
```
48.8566/2.3522#48.8567/2.3520#48.8565/2.3518#48.8564/2.3521#48.8566/2.3522
```
### Exemple d'utilisation
```dart
// Créer un secteur
final sector = SectorModel(
id: 789,
libelle: "Secteur Nord",
color: "#FF5733",
sector: "48.8566/2.3522#48.8567/2.3520#48.8565/2.3518#48.8564/2.3521#48.8566/2.3522",
);
// Obtenir les coordonnées du secteur
final coordinates = sector.getCoordinates();
// Résultat: [[48.8566, 2.3522], [48.8567, 2.3520], [48.8565, 2.3518], ...]
```
## Modèle Membre (MembreModel)
**Description**: Représente un membre de l'organisation, utilisé uniquement dans l'interface admin.
### Propriétés
| Propriété | Type | Description | Hive Index |
| ------------- | --------- | -------------------------------- | ---------- |
| id | int | Identifiant unique | 0 |
| fkRole | int | ID du rôle du membre | 1 |
| fkTitre | int | ID du titre (civilité) du membre | 2 |
| firstName | String | Prénom du membre | 3 |
| sectName | String? | Nom de la section/département | 4 |
| dateNaissance | DateTime? | Date de naissance | 5 |
| dateEmbauche | DateTime? | Date d'embauche | 6 |
| chkActive | int | Statut actif (1) ou inactif (0) | 7 |
| name | String | Nom de famille du membre | 8 |
| username | String | Nom d'utilisateur pour connexion | 9 |
| email | String | Adresse email | 10 |
### Méthodes
- **fromJson**: Convertit un objet JSON en MembreModel
- **toJson**: Convertit un MembreModel en objet JSON
- **copyWith**: Crée une copie avec des valeurs modifiées
### Exemple d'utilisation
```dart
// Créer un membre
final membre = MembreModel(
id: 9999979,
fkRole: 1,
fkTitre: 1,
firstName: "Pierre",
sectName: "",
dateNaissance: DateTime.parse("1966-04-24"),
dateEmbauche: DateTime.parse("2017-12-01"),
chkActive: 0,
name: "VAISSAIRE",
username: "pv_mobile",
email: "pierre.vaissaire@d6soft.fr",
);
// Créer une version modifiée
final updatedMembre = membre.copyWith(
chkActive: 1,
sectName: "Section A",
);
```
## Modèle Passage (PassageModel)
**Description**: Représente un passage effectué chez un habitant avec toutes les informations associées.
### Propriétés
| Propriété | Type | Description | Hive Index |
| --------------- | -------- | --------------------------------------------- | ---------- |
| id | int | Identifiant unique | 0 |
| fkOperation | int | ID de l'opération associée | 1 |
| fkSector | int | ID du secteur | 2 |
| fkUser | int | ID de l'utilisateur qui a effectué le passage | 3 |
| fkType | int | Type de passage (1-6) | 4 |
| fkAdresse | String | Identifiant de l'adresse | 5 |
| passedAt | DateTime | Date et heure du passage | 6 |
| numero | String | Numéro de rue | 7 |
| rue | String | Nom de la rue | 8 |
| rueBis | String | Complément de rue | 9 |
| ville | String | Ville | 10 |
| residence | String | Nom de la résidence | 11 |
| fkHabitat | int | Type d'habitat | 12 |
| appt | String | Numéro d'appartement | 13 |
| niveau | String | Niveau/étage | 14 |
| gpsLat | String | Latitude GPS | 15 |
| gpsLng | String | Longitude GPS | 16 |
| nomRecu | String | Nom du fichier de reçu | 17 |
| remarque | String | Remarques/commentaires | 18 |
| montant | String | Montant collecté | 19 |
| fkTypeReglement | int | Type de règlement (0-3) | 20 |
| emailErreur | String | Message d'erreur pour l'envoi par email | 21 |
| nbPassages | int | Nombre de passages à cette adresse | 22 |
| name | String | Nom de l'habitant | 23 |
| email | String | Email de l'habitant | 24 |
| phone | String | Téléphone de l'habitant | 25 |
| lastSyncedAt | DateTime | Dernière synchronisation avec le serveur | 26 |
| isActive | bool | Statut actif/inactif | 27 |
| isSynced | bool | Indique si synchronisé avec le serveur | 28 |
### Types de passages
| ID | Description | Couleur |
| --- | ----------- | ---------- |
| 1 | Effectué | Vert |
| 2 | À finaliser | Orange |
| 3 | Refusé | Rouge |
| 4 | Don | Bleu ciel |
| 5 | Lot | Bleu foncé |
| 6 | Maison vide | Gris |
### Types de règlements
| ID | Description | Couleur |
| --- | ---------------- | ------- |
| 0 | Pas de règlement | Gris |
| 1 | Espèce | Jaune |
| 2 | Chèque | Vert |
| 3 | CB | Bleu |
### Méthodes
- **fromJson**: Convertit un objet JSON en PassageModel
- **toJson**: Convertit un PassageModel en objet JSON
- **copyWith**: Crée une copie avec des valeurs modifiées
- **toString**: Représentation textuelle pour débogage
### Exemple d'utilisation
```dart
// Créer un passage
final passage = PassageModel(
id: 1001,
fkOperation: 456,
fkSector: 789,
fkUser: 123,
fkType: 1, // Effectué
fkAdresse: "ADRESSE-123",
passedAt: DateTime.now(),
numero: "12",
rue: "Rue des Lilas",
ville: "Paris",
gpsLat: "48.8566",
gpsLng: "2.3522",
montant: "25.50",
fkTypeReglement: 2, // Chèque
nbPassages: 1,
name: "Dupont",
lastSyncedAt: DateTime.now(),
);
// Créer une version modifiée
final updatedPassage = passage.copyWith(
montant: "30.00",
remarque: "Client fidèle",
);
```
## Relations entre les modèles
Les modèles sont reliés entre eux par des clés étrangères:
1. **PassageModel**:
- `fkOperation``OperationModel.id`
- `fkSector``SectorModel.id`
- `fkUser``UserModel.id`
2. **SectorModel**:
- Lié aux opérations via les passages
3. **OperationModel**:
- Contient des secteurs et des passages
4. **UserModel**:
- Possède des passages
## Gestion de la synchronisation
Tous les modèles principaux possèdent les propriétés de synchronisation:
- `isSynced`: Indique si l'objet a été synchronisé avec le serveur
- `lastSyncedAt`: Date de dernière synchronisation
Cette approche permet le travail hors ligne et la synchronisation ultérieure des modifications.
## Stockage Hive
Les modèles sont stockés dans des "boxes" Hive distinctes:
| Modèle | Nom de la box | Type ID |
| -------------- | ------------- | ------- |
| UserModel | users | 0 |
| OperationModel | operations | 1 |
| SectorModel | sectors | 3 |
| PassageModel | passages | 4 |
| MembreModel | membres | 5 |
Les boxes sont initialisées au démarrage de l'application ou lors de la connexion d'un utilisateur.

10
docs/planning-client.csv Normal file
View File

@@ -0,0 +1,10 @@
Description GEOSECTOR 2025,Livraison prévue
1. Mise en place de l'infrastructure technique et configuration initiale,01/04/25
2. Développement de la partie publique et système d'authentification,14/04/25
3. Développement des fonctionnalités principales de l'interface utilisateur,28/04/25
4. Intégration des paiements et gestion des documents dématérialisés,12/05/25
5. Développement des fonctionnalités d'administration pour les amicales,26/05/25
6. Développement des outils de cartographie et gestion des opérations,09/06/25
7. Développement des fonctionnalités super admin et gestion commerciale,23/06/25
"8. Tests, déploiement et mise en production de l'application",07/07/25
"9. Documentation, formation et support au lancement",21/07/25
1 Description GEOSECTOR 2025 Livraison prévue
2 1. Mise en place de l'infrastructure technique et configuration initiale 01/04/25
3 2. Développement de la partie publique et système d'authentification 14/04/25
4 3. Développement des fonctionnalités principales de l'interface utilisateur 28/04/25
5 4. Intégration des paiements et gestion des documents dématérialisés 12/05/25
6 5. Développement des fonctionnalités d'administration pour les amicales 26/05/25
7 6. Développement des outils de cartographie et gestion des opérations 09/06/25
8 7. Développement des fonctionnalités super admin et gestion commerciale 23/06/25
9 8. Tests, déploiement et mise en production de l'application 07/07/25
10 9. Documentation, formation et support au lancement 21/07/25

View File

@@ -0,0 +1,32 @@
Subject,Start Date,Start Time,End Date,End Time,All Day Event,Description,Location,Private
"GEO - Développement de la page Communication pour les utilisateurs",01/05/2025,08:30,01/05/2025,12:30,FALSE,"Implémentation du widget de chat pour la communication d'équipe. Création de l'interface pour répondre aux mails clients. Intégration avec les repositories pour la gestion des données.","Bureau D6SOFT",FALSE
"GEO - Finalisation Widget Carte MapBox (partie utilisateur)",03/05/2025,08:30,03/05/2025,12:30,FALSE,"Développement des fonctionnalités de visualisation des secteurs d'activité, visualisation des passages, sélection de passages près de la position et création de passage sur clic. Implémentation de la détection de la position utilisateur.","Bureau D6SOFT",FALSE
"GEO - Formulaire de passage avec intégration Stripe (partie 1)",05/05/2025,08:30,05/05/2025,12:30,FALSE,"Conception du widget Formulaire de passage. Implémentation des champs et validations. Mise en place de la logique de collecte des données. Préparation pour l'intégration de Stripe.","Bureau D6SOFT",FALSE
"GEO - Formulaire de passage avec intégration Stripe (partie 2)",07/05/2025,08:30,07/05/2025,12:30,FALSE,"Intégration de Stripe pour le paiement en ligne. Configuration du client Stripe dans Flutter. Gestion des paiements et des erreurs. Tests des transactions.","Bureau D6SOFT",FALSE
"GEO - Développement du système d'envoi de reçus PDF par email et SMS",09/05/2025,08:30,09/05/2025,12:30,FALSE,"Mise en place de la génération de reçu au format PDF. Intégration avec le service d'emails. Configuration de l'envoi de SMS via l'API OVH. Tests des envois.","Bureau D6SOFT",FALSE
"GEO - Implémentation des widgets statistiques communs",11/05/2025,08:30,11/05/2025,12:30,FALSE,"Développement des widgets de graphiques (passages, règlements). Implémentation du filtrage par période (jour/semaine/mois). Configuration de l'affichage responsive.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Principale",13/05/2025,08:30,13/05/2025,12:30,FALSE,"Création de la page principale d'administration avec synthèse des passages par secteur et utilisateur. Implémentation du graphique des passages des deux dernières semaines.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Amicale",15/05/2025,08:30,15/05/2025,12:30,FALSE,"Implémentation du formulaire d'informations de l'amicale. Upload de logo. Gestion des abonnements avec l'intégration STRIPE. Configuration des packs SMS.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Membres",17/05/2025,08:30,17/05/2025,12:30,FALSE,"Création de l'interface de gestion des membres. Upload des badges. Fonctionnalités d'import/export de listes. Gestion de réinitialisation des mots de passe.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Communication",19/05/2025,08:30,19/05/2025,12:30,FALSE,"Implémentation du système de chat pour l'équipe. Intégration avec l'API pour la communication avec Geosector. Tests de communication.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Connexions",21/05/2025,08:30,21/05/2025,12:30,FALSE,"Création de l'interface de consultation des connexions. Implémentation du graphique sur 5 mois. Filtrage par membre. Optimisation des requêtes API.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Opérations (partie 1)",23/05/2025,08:30,23/05/2025,12:30,FALSE,"Conception de l'interface de gestion des opérations. Implémentation de la sélection de l'opération active. Gestion des secteurs (couleurs, titres, membres).","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Opérations (partie 2)",25/05/2025,08:30,25/05/2025,12:30,FALSE,"Développement de l'interface pour tracer les secteurs sur la carte. Affichage des passages selon l'historique. Intégration avec les modules existants.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Opérations (partie 3)",27/05/2025,08:30,27/05/2025,12:30,FALSE,"Implémentation de l'affichage des membres actifs avec leurs statistiques. Exportation des données au format Excel. Tests d'intégration complets.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Statistiques",29/05/2025,08:30,29/05/2025,12:30,FALSE,"Création des graphiques d'activité par secteur, par membre et par période. Implémentation des filtres dynamiques. Tests et optimisation des performances.","Bureau D6SOFT",FALSE
"GEO - Développement de la page Admin - Clients (Super Admin)",31/05/2025,08:30,31/05/2025,12:30,FALSE,"Implémentation de la liste des amicales avec recherche. Gestion des amicales en démo. Interface de création/suppression d'amicales. Consultation des statistiques.","Bureau D6SOFT",FALSE
"GEO - Développement des scripts d'importation de données Open Data (partie 1)",02/06/2025,08:30,02/06/2025,12:30,FALSE,"Conception et développement des scripts PHP pour l'importation hebdomadaire de la base ADRESSES et SIRENE. Configuration des tâches planifiées. Tests d'importation.","Bureau D6SOFT",FALSE
"GEO - Développement des scripts d'importation de données Open Data (partie 2)",04/06/2025,08:30,04/06/2025,12:30,FALSE,"Conception et développement des scripts PHP pour l'importation hebdomadaire de la base BATIMENTS et OpenStreetMap. Optimisation des requêtes SQL. Tests d'intégration.","Bureau D6SOFT",FALSE
"GEO - Implémentation du système de chiffrement des données sensibles",06/06/2025,08:30,06/06/2025,12:30,FALSE,"Configuration du chiffrement des mots de passe avec Argon2. Mise en place du chiffrement AES-256 pour les données sensibles. Tests de sécurité.","Bureau D6SOFT",FALSE
"GEO - Développement du système de gestion des emails et file d'attente",08/06/2025,08:30,08/06/2025,12:30,FALSE,"Implémentation de la queue des emails en base de données. Création du script de traitement de la queue. Développement du système de gestion des retours d'emails.","Bureau D6SOFT",FALSE
"GEO - Développement du système de gestion des SMS via OVH",10/06/2025,08:30,10/06/2025,12:30,FALSE,"Configuration de l'intégration avec l'API SMS OVH. Implémentation de la gestion des packs SMS. Tests d'envoi et de réception de SMS.","Bureau D6SOFT",FALSE
"GEO - Création du site vitrine Svelte (partie 1)",12/06/2025,08:30,12/06/2025,12:30,FALSE,"Configuration initiale du projet Svelte. Développement de la page d'accueil avec présentation de la solution. Conception des composants de base.","Bureau D6SOFT",FALSE
"GEO - Création du site vitrine Svelte (partie 2)",14/06/2025,08:30,14/06/2025,12:30,FALSE,"Développement des sections de présentation des fonctionnalités. Implémentation du lien vers l'App Store et Play Store. Intégration des captures d'écran.","Bureau D6SOFT",FALSE
"GEO - Création du site vitrine Svelte (partie 3)",16/06/2025,08:30,16/06/2025,12:30,FALSE,"Implémentation du formulaire de contact. Développement des pages légales (mentions légales, conditions d'utilisation). Mise en place de la gestion des cookies.","Bureau D6SOFT",FALSE
"GEO - Intégration de l'authentification et des liens entre site vitrine et application",18/06/2025,08:30,18/06/2025,12:30,FALSE,"Développement des liens entre le site vitrine et l'application Flutter. Configuration du formulaire de connexion et d'inscription. Tests d'intégration.","Bureau D6SOFT",FALSE
"GEO - Tests utilisateurs et débogage global (partie 1)",20/06/2025,08:30,20/06/2025,12:30,FALSE,"Procédure de tests utilisateur sur les fonctionnalités principales. Identification et correction des bugs. Améliorations de l'interface utilisateur.","Bureau D6SOFT",FALSE
"GEO - Tests utilisateurs et débogage global (partie 2)",22/06/2025,08:30,22/06/2025,12:30,FALSE,"Tests des parcours utilisateurs complexes. Vérification de la synchronisation des données. Optimisation des performances. Corrections de bugs.","Bureau D6SOFT",FALSE
"GEO - Optimisation des performances et de la taille de l'application",24/06/2025,08:30,24/06/2025,12:30,FALSE,"Analyse des performances. Optimisation du code Flutter. Réduction de la taille de l'application. Amélioration des temps de chargement.","Bureau D6SOFT",FALSE
"GEO - Documentation technique et guide utilisateur",26/06/2025,08:30,26/06/2025,12:30,FALSE,"Rédaction de la documentation technique détaillée. Création du guide utilisateur avec captures d'écran. Préparation des ressources pour la formation.","Bureau D6SOFT",FALSE
"GEO - Préparation du déploiement et configuration des environnements",28/06/2025,08:30,28/06/2025,12:30,FALSE,"Configuration des environnements de production. Préparation du déploiement sur les stores (AppStore, PlayStore). Configuration du serveur web et de la base de données.","Bureau D6SOFT",FALSE
"GEO - Finalisation et préparation au lancement",30/06/2025,08:30,30/06/2025,12:30,FALSE,"Derniers tests d'intégration. Vérification des configurations de sécurité. Préparation des scripts de déploiement. Planification du lancement.","Bureau D6SOFT",FALSE
1 Subject Start Date Start Time End Date End Time All Day Event Description Location Private
2 GEO - Développement de la page Communication pour les utilisateurs 01/05/2025 08:30 01/05/2025 12:30 FALSE Implémentation du widget de chat pour la communication d'équipe. Création de l'interface pour répondre aux mails clients. Intégration avec les repositories pour la gestion des données. Bureau D6SOFT FALSE
3 GEO - Finalisation Widget Carte MapBox (partie utilisateur) 03/05/2025 08:30 03/05/2025 12:30 FALSE Développement des fonctionnalités de visualisation des secteurs d'activité, visualisation des passages, sélection de passages près de la position et création de passage sur clic. Implémentation de la détection de la position utilisateur. Bureau D6SOFT FALSE
4 GEO - Formulaire de passage avec intégration Stripe (partie 1) 05/05/2025 08:30 05/05/2025 12:30 FALSE Conception du widget Formulaire de passage. Implémentation des champs et validations. Mise en place de la logique de collecte des données. Préparation pour l'intégration de Stripe. Bureau D6SOFT FALSE
5 GEO - Formulaire de passage avec intégration Stripe (partie 2) 07/05/2025 08:30 07/05/2025 12:30 FALSE Intégration de Stripe pour le paiement en ligne. Configuration du client Stripe dans Flutter. Gestion des paiements et des erreurs. Tests des transactions. Bureau D6SOFT FALSE
6 GEO - Développement du système d'envoi de reçus PDF par email et SMS 09/05/2025 08:30 09/05/2025 12:30 FALSE Mise en place de la génération de reçu au format PDF. Intégration avec le service d'emails. Configuration de l'envoi de SMS via l'API OVH. Tests des envois. Bureau D6SOFT FALSE
7 GEO - Implémentation des widgets statistiques communs 11/05/2025 08:30 11/05/2025 12:30 FALSE Développement des widgets de graphiques (passages, règlements). Implémentation du filtrage par période (jour/semaine/mois). Configuration de l'affichage responsive. Bureau D6SOFT FALSE
8 GEO - Développement de la page Admin - Principale 13/05/2025 08:30 13/05/2025 12:30 FALSE Création de la page principale d'administration avec synthèse des passages par secteur et utilisateur. Implémentation du graphique des passages des deux dernières semaines. Bureau D6SOFT FALSE
9 GEO - Développement de la page Admin - Amicale 15/05/2025 08:30 15/05/2025 12:30 FALSE Implémentation du formulaire d'informations de l'amicale. Upload de logo. Gestion des abonnements avec l'intégration STRIPE. Configuration des packs SMS. Bureau D6SOFT FALSE
10 GEO - Développement de la page Admin - Membres 17/05/2025 08:30 17/05/2025 12:30 FALSE Création de l'interface de gestion des membres. Upload des badges. Fonctionnalités d'import/export de listes. Gestion de réinitialisation des mots de passe. Bureau D6SOFT FALSE
11 GEO - Développement de la page Admin - Communication 19/05/2025 08:30 19/05/2025 12:30 FALSE Implémentation du système de chat pour l'équipe. Intégration avec l'API pour la communication avec Geosector. Tests de communication. Bureau D6SOFT FALSE
12 GEO - Développement de la page Admin - Connexions 21/05/2025 08:30 21/05/2025 12:30 FALSE Création de l'interface de consultation des connexions. Implémentation du graphique sur 5 mois. Filtrage par membre. Optimisation des requêtes API. Bureau D6SOFT FALSE
13 GEO - Développement de la page Admin - Opérations (partie 1) 23/05/2025 08:30 23/05/2025 12:30 FALSE Conception de l'interface de gestion des opérations. Implémentation de la sélection de l'opération active. Gestion des secteurs (couleurs, titres, membres). Bureau D6SOFT FALSE
14 GEO - Développement de la page Admin - Opérations (partie 2) 25/05/2025 08:30 25/05/2025 12:30 FALSE Développement de l'interface pour tracer les secteurs sur la carte. Affichage des passages selon l'historique. Intégration avec les modules existants. Bureau D6SOFT FALSE
15 GEO - Développement de la page Admin - Opérations (partie 3) 27/05/2025 08:30 27/05/2025 12:30 FALSE Implémentation de l'affichage des membres actifs avec leurs statistiques. Exportation des données au format Excel. Tests d'intégration complets. Bureau D6SOFT FALSE
16 GEO - Développement de la page Admin - Statistiques 29/05/2025 08:30 29/05/2025 12:30 FALSE Création des graphiques d'activité par secteur, par membre et par période. Implémentation des filtres dynamiques. Tests et optimisation des performances. Bureau D6SOFT FALSE
17 GEO - Développement de la page Admin - Clients (Super Admin) 31/05/2025 08:30 31/05/2025 12:30 FALSE Implémentation de la liste des amicales avec recherche. Gestion des amicales en démo. Interface de création/suppression d'amicales. Consultation des statistiques. Bureau D6SOFT FALSE
18 GEO - Développement des scripts d'importation de données Open Data (partie 1) 02/06/2025 08:30 02/06/2025 12:30 FALSE Conception et développement des scripts PHP pour l'importation hebdomadaire de la base ADRESSES et SIRENE. Configuration des tâches planifiées. Tests d'importation. Bureau D6SOFT FALSE
19 GEO - Développement des scripts d'importation de données Open Data (partie 2) 04/06/2025 08:30 04/06/2025 12:30 FALSE Conception et développement des scripts PHP pour l'importation hebdomadaire de la base BATIMENTS et OpenStreetMap. Optimisation des requêtes SQL. Tests d'intégration. Bureau D6SOFT FALSE
20 GEO - Implémentation du système de chiffrement des données sensibles 06/06/2025 08:30 06/06/2025 12:30 FALSE Configuration du chiffrement des mots de passe avec Argon2. Mise en place du chiffrement AES-256 pour les données sensibles. Tests de sécurité. Bureau D6SOFT FALSE
21 GEO - Développement du système de gestion des emails et file d'attente 08/06/2025 08:30 08/06/2025 12:30 FALSE Implémentation de la queue des emails en base de données. Création du script de traitement de la queue. Développement du système de gestion des retours d'emails. Bureau D6SOFT FALSE
22 GEO - Développement du système de gestion des SMS via OVH 10/06/2025 08:30 10/06/2025 12:30 FALSE Configuration de l'intégration avec l'API SMS OVH. Implémentation de la gestion des packs SMS. Tests d'envoi et de réception de SMS. Bureau D6SOFT FALSE
23 GEO - Création du site vitrine Svelte (partie 1) 12/06/2025 08:30 12/06/2025 12:30 FALSE Configuration initiale du projet Svelte. Développement de la page d'accueil avec présentation de la solution. Conception des composants de base. Bureau D6SOFT FALSE
24 GEO - Création du site vitrine Svelte (partie 2) 14/06/2025 08:30 14/06/2025 12:30 FALSE Développement des sections de présentation des fonctionnalités. Implémentation du lien vers l'App Store et Play Store. Intégration des captures d'écran. Bureau D6SOFT FALSE
25 GEO - Création du site vitrine Svelte (partie 3) 16/06/2025 08:30 16/06/2025 12:30 FALSE Implémentation du formulaire de contact. Développement des pages légales (mentions légales, conditions d'utilisation). Mise en place de la gestion des cookies. Bureau D6SOFT FALSE
26 GEO - Intégration de l'authentification et des liens entre site vitrine et application 18/06/2025 08:30 18/06/2025 12:30 FALSE Développement des liens entre le site vitrine et l'application Flutter. Configuration du formulaire de connexion et d'inscription. Tests d'intégration. Bureau D6SOFT FALSE
27 GEO - Tests utilisateurs et débogage global (partie 1) 20/06/2025 08:30 20/06/2025 12:30 FALSE Procédure de tests utilisateur sur les fonctionnalités principales. Identification et correction des bugs. Améliorations de l'interface utilisateur. Bureau D6SOFT FALSE
28 GEO - Tests utilisateurs et débogage global (partie 2) 22/06/2025 08:30 22/06/2025 12:30 FALSE Tests des parcours utilisateurs complexes. Vérification de la synchronisation des données. Optimisation des performances. Corrections de bugs. Bureau D6SOFT FALSE
29 GEO - Optimisation des performances et de la taille de l'application 24/06/2025 08:30 24/06/2025 12:30 FALSE Analyse des performances. Optimisation du code Flutter. Réduction de la taille de l'application. Amélioration des temps de chargement. Bureau D6SOFT FALSE
30 GEO - Documentation technique et guide utilisateur 26/06/2025 08:30 26/06/2025 12:30 FALSE Rédaction de la documentation technique détaillée. Création du guide utilisateur avec captures d'écran. Préparation des ressources pour la formation. Bureau D6SOFT FALSE
31 GEO - Préparation du déploiement et configuration des environnements 28/06/2025 08:30 28/06/2025 12:30 FALSE Configuration des environnements de production. Préparation du déploiement sur les stores (AppStore, PlayStore). Configuration du serveur web et de la base de données. Bureau D6SOFT FALSE
32 GEO - Finalisation et préparation au lancement 30/06/2025 08:30 30/06/2025 12:30 FALSE Derniers tests d'intégration. Vérification des configurations de sécurité. Préparation des scripts de déploiement. Planification du lancement. Bureau D6SOFT FALSE

21
docs/planning-geo.csv Normal file
View File

@@ -0,0 +1,21 @@
Description;Date de début;Date échéance
Sprint 1 - Initialisation: Environnement de développement Flutter/PHP, Structure BDD, Configuration d'API;07/04/2025;11/04/2025
Sprint 2 - Base de données: Initialisation de la BDD centrale et des scripts d'importation, Scripts SQL de migration;14/04/2025;18/04/2025
Sprint 3 - API Core: Développement des modules principaux de l'API (authentification, utilisateurs, amicales);21/04/2025;25/04/2025
Sprint 4 - Import Open Data: Scripts d'import pour bases Adresses, SIRENE, Bâtiments, OpenStreetMap;28/04/2025;02/05/2025
Sprint 5 - Widgets communs I: Formulaires (passage, amicale, membre, opération, secteur);05/05/2025;09/05/2025
Sprint 6 - Widgets communs II: Cartes MapBox avec gestion des markers et secteurs;12/05/2025;16/05/2025
Sprint 7 - Widgets communs III: Graphiques statistiques (Fl_chart) pour connexions, passages, opérations;19/05/2025;23/05/2025
Sprint 8 - Partie publique: Page d'accueil et système authentification/enregistrement;26/05/2025;30/05/2025
Sprint 9 - Partie utilisateur I: Page principale et statistiques;02/06/2025;06/06/2025
Sprint 10 - Partie utilisateur II: Historique et communication;09/06/2025;13/06/2025
Sprint 11 - Partie utilisateur III: Carte et formulaire passage;16/06/2025;20/06/2025
Sprint 12 - Partie admin I: Page principale et amicale;23/06/2025;27/06/2025
Sprint 13 - Partie admin II: Membres et communication;30/06/2025;04/07/2025
Sprint 14 - Partie admin III: Connexions et carte;07/07/2025;11/07/2025
Sprint 15 - Partie admin IV: Opérations et statistiques;14/07/2025;18/07/2025
Sprint 16 - Super admin: Page clients et fonctionnalités spécifiques;21/07/2025;25/07/2025
Sprint 17 - Intégration paiement: Stripe pour abonnements et packs SMS;28/07/2025;01/08/2025
Sprint 18 - Système communications: Emails (SMTP, queue, vérification) et SMS (OVH);04/08/2025;08/08/2025
Sprint 19 - Tests et corrections: Tests fonctionnels, corrections de bugs, optimisation;11/08/2025;15/08/2025
Sprint 20 - Finalisation: Documentation, déploiement final, préparation livraison;18/08/2025;22/08/2025
1 Description Date de début Date échéance
2 Sprint 1 - Initialisation: Environnement de développement Flutter/PHP, Structure BDD, Configuration d'API 07/04/2025 11/04/2025
3 Sprint 2 - Base de données: Initialisation de la BDD centrale et des scripts d'importation, Scripts SQL de migration 14/04/2025 18/04/2025
4 Sprint 3 - API Core: Développement des modules principaux de l'API (authentification, utilisateurs, amicales) 21/04/2025 25/04/2025
5 Sprint 4 - Import Open Data: Scripts d'import pour bases Adresses, SIRENE, Bâtiments, OpenStreetMap 28/04/2025 02/05/2025
6 Sprint 5 - Widgets communs I: Formulaires (passage, amicale, membre, opération, secteur) 05/05/2025 09/05/2025
7 Sprint 6 - Widgets communs II: Cartes MapBox avec gestion des markers et secteurs 12/05/2025 16/05/2025
8 Sprint 7 - Widgets communs III: Graphiques statistiques (Fl_chart) pour connexions, passages, opérations 19/05/2025 23/05/2025
9 Sprint 8 - Partie publique: Page d'accueil et système authentification/enregistrement 26/05/2025 30/05/2025
10 Sprint 9 - Partie utilisateur I: Page principale et statistiques 02/06/2025 06/06/2025
11 Sprint 10 - Partie utilisateur II: Historique et communication 09/06/2025 13/06/2025
12 Sprint 11 - Partie utilisateur III: Carte et formulaire passage 16/06/2025 20/06/2025
13 Sprint 12 - Partie admin I: Page principale et amicale 23/06/2025 27/06/2025
14 Sprint 13 - Partie admin II: Membres et communication 30/06/2025 04/07/2025
15 Sprint 14 - Partie admin III: Connexions et carte 07/07/2025 11/07/2025
16 Sprint 15 - Partie admin IV: Opérations et statistiques 14/07/2025 18/07/2025
17 Sprint 16 - Super admin: Page clients et fonctionnalités spécifiques 21/07/2025 25/07/2025
18 Sprint 17 - Intégration paiement: Stripe pour abonnements et packs SMS 28/07/2025 01/08/2025
19 Sprint 18 - Système communications: Emails (SMTP, queue, vérification) et SMS (OVH) 04/08/2025 08/08/2025
20 Sprint 19 - Tests et corrections: Tests fonctionnels, corrections de bugs, optimisation 11/08/2025 15/08/2025
21 Sprint 20 - Finalisation: Documentation, déploiement final, préparation livraison 18/08/2025 22/08/2025

Binary file not shown.

View File

@@ -0,0 +1,33 @@
Description,Start_Date,Due_Date
1. Configuration du projet Flutter et mise en place de l'architecture,2025-04-01,2025-04-04
2. Configuration de l'API PHP8.3 et base de données MariaDB10.11,2025-04-01,2025-04-04
3. Mise en place du script d'import de la base nationale des adresses,2025-04-01,2025-04-04
4. Développement de la page publique de présentation,2025-04-07,2025-04-11
5. Développement des pages de login/register et récupération de mot de passe,2025-04-07,2025-04-11
6. Intégration de Hive pour le stockage local des données,2025-04-14,2025-04-18
7. Développement de la page principale utilisateur,2025-04-14,2025-04-18
8. Intégration de MapBox et configuration initiale des cartes,2025-04-21,2025-04-25
9. Développement de la page statistiques utilisateur avec Fl_chart,2025-04-21,2025-04-25
10. Développement de la page historique utilisateur,2025-04-28,2025-05-02
11. Développement de la page communication utilisateur,2025-04-28,2025-05-02
12. Développement de la page carte utilisateur et visualisation des secteurs,2025-05-05,2025-05-09
13. Développement du formulaire de passage et gestion des coordonnées,2025-05-05,2025-05-09
14. Intégration de Stripe pour les paiements en ligne,2025-05-12,2025-05-16
15. Développement de la génération et envoi des reçus PDF par mail/SMS,2025-05-12,2025-05-16
16. Développement de la page principale admin amicale,2025-05-19,2025-05-23
17. Développement de la page amicale et gestion du logo,2025-05-19,2025-05-23
18. Développement de la page membres avec import/export,2025-05-26,2025-05-30
19. Développement de la page communication admin,2025-05-26,2025-05-30
20. Développement de la page connexions et graphiques,2025-06-02,2025-06-06
21. Développement de la page carte admin avec filtres,2025-06-02,2025-06-06
22. Développement de la page opérations et gestion des secteurs,2025-06-09,2025-06-13
23. Développement du traçage des secteurs sur la carte,2025-06-09,2025-06-13
24. Développement des exports au format Excel,2025-06-16,2025-06-20
25. Développement de la page statistiques admin,2025-06-16,2025-06-20
26. Développement de la page clients pour super admin Geosector,2025-06-23,2025-06-27
27. Développement de la gestion des abonnements et facturation PDF,2025-06-23,2025-06-27
28. Tests et débogage de l'application mobile,2025-06-30,2025-07-04
29. Tests et débogage de l'interface web,2025-06-30,2025-07-04
30. Finalisation et déploiement de l'application,2025-07-07,2025-07-11
31. Publication sur App Store et Play Store,2025-07-14,2025-07-18
32. Documentation et formation,2025-07-21,2025-07-25
1 Description Start_Date Due_Date
2 1. Configuration du projet Flutter et mise en place de l'architecture 2025-04-01 2025-04-04
3 2. Configuration de l'API PHP8.3 et base de données MariaDB10.11 2025-04-01 2025-04-04
4 3. Mise en place du script d'import de la base nationale des adresses 2025-04-01 2025-04-04
5 4. Développement de la page publique de présentation 2025-04-07 2025-04-11
6 5. Développement des pages de login/register et récupération de mot de passe 2025-04-07 2025-04-11
7 6. Intégration de Hive pour le stockage local des données 2025-04-14 2025-04-18
8 7. Développement de la page principale utilisateur 2025-04-14 2025-04-18
9 8. Intégration de MapBox et configuration initiale des cartes 2025-04-21 2025-04-25
10 9. Développement de la page statistiques utilisateur avec Fl_chart 2025-04-21 2025-04-25
11 10. Développement de la page historique utilisateur 2025-04-28 2025-05-02
12 11. Développement de la page communication utilisateur 2025-04-28 2025-05-02
13 12. Développement de la page carte utilisateur et visualisation des secteurs 2025-05-05 2025-05-09
14 13. Développement du formulaire de passage et gestion des coordonnées 2025-05-05 2025-05-09
15 14. Intégration de Stripe pour les paiements en ligne 2025-05-12 2025-05-16
16 15. Développement de la génération et envoi des reçus PDF par mail/SMS 2025-05-12 2025-05-16
17 16. Développement de la page principale admin amicale 2025-05-19 2025-05-23
18 17. Développement de la page amicale et gestion du logo 2025-05-19 2025-05-23
19 18. Développement de la page membres avec import/export 2025-05-26 2025-05-30
20 19. Développement de la page communication admin 2025-05-26 2025-05-30
21 20. Développement de la page connexions et graphiques 2025-06-02 2025-06-06
22 21. Développement de la page carte admin avec filtres 2025-06-02 2025-06-06
23 22. Développement de la page opérations et gestion des secteurs 2025-06-09 2025-06-13
24 23. Développement du traçage des secteurs sur la carte 2025-06-09 2025-06-13
25 24. Développement des exports au format Excel 2025-06-16 2025-06-20
26 25. Développement de la page statistiques admin 2025-06-16 2025-06-20
27 26. Développement de la page clients pour super admin Geosector 2025-06-23 2025-06-27
28 27. Développement de la gestion des abonnements et facturation PDF 2025-06-23 2025-06-27
29 28. Tests et débogage de l'application mobile 2025-06-30 2025-07-04
30 29. Tests et débogage de l'interface web 2025-06-30 2025-07-04
31 30. Finalisation et déploiement de l'application 2025-07-07 2025-07-11
32 31. Publication sur App Store et Play Store 2025-07-14 2025-07-18
33 32. Documentation et formation 2025-07-21 2025-07-25

346
docs/widgets_common.md Normal file
View File

@@ -0,0 +1,346 @@
# Widgets communs GEOSECTOR
## Description générale
GEOSECTOR utilise un ensemble de widgets communs réutilisables pour maintenir une cohérence visuelle et simplifier le développement. Ces widgets sont conçus pour s'adapter à la fois à l'interface web et mobile, et respectent les thèmes définis dans l'application. Ce document détaille les widgets principaux, leurs propriétés et leur utilisation.
## Interface utilisateur de base
### CustomButton
Un bouton stylisé et réutilisable avec gestion de l'état de chargement.
**Fichier**: `lib/presentation/widgets/custom_button.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|----------------|----------------|---------------------------------------------------|--------|
| onPressed | VoidCallback? | Fonction appelée lors du clic | Oui |
| text | String | Texte du bouton | Oui |
| icon | IconData? | Icône à afficher à gauche du texte | Non |
| isLoading | bool | Afficher un indicateur de chargement | Non |
| width | double? | Largeur personnalisée | Non |
| backgroundColor| Color? | Couleur de fond (utilise primary par défaut) | Non |
| textColor | Color? | Couleur du texte (utilise white par défaut) | Non |
**Exemple d'utilisation**:
```dart
CustomButton(
onPressed: () => saveData(),
text: 'Enregistrer',
icon: Icons.save,
isLoading: isSaving,
backgroundColor: Colors.green,
)
```
### CustomTextField
Champ de texte stylisé et réutilisable avec gestion des validateurs.
**Fichier**: `lib/presentation/widgets/custom_text_field.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|-----------------|------------------------|------------------------------------------------|--------|
| controller | TextEditingController | Contrôleur du champ | Oui |
| label | String | Libellé du champ | Oui |
| hintText | String? | Texte indicatif lorsque vide | Non |
| prefixIcon | IconData? | Icône au début du champ | Non |
| suffixIcon | Widget? | Widget à la fin du champ | Non |
| obscureText | bool | Masquer le texte (pour les mots de passe) | Non |
| keyboardType | TextInputType | Type de clavier | Non |
| validator | Function? | Fonction de validation | Non |
| maxLines | int? | Nombre maximum de lignes | Non |
| minLines | int? | Nombre minimum de lignes | Non |
| readOnly | bool | Lecture seule | Non |
| onChanged | Function? | Fonction appelée lors des modifications | Non |
| fillColor | Color? | Couleur de fond du champ | Non |
**Exemple d'utilisation**:
```dart
CustomTextField(
controller: _emailController,
label: 'Adresse email',
hintText: 'Saisissez votre email',
prefixIcon: Icons.email,
keyboardType: TextInputType.emailAddress,
validator: (value) => value.isEmpty ? 'Email requis' : null,
)
```
## Navigation et mise en page
### DashboardAppBar
Barre d'applications personnalisée pour les tableaux de bord.
**Fichier**: `lib/presentation/widgets/dashboard_app_bar.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|----------------------|--------------|--------------------------------------------------|--------|
| title | String | Titre principal de l'AppBar | Oui |
| pageTitle | String? | Titre de la page actuelle | Non |
| additionalActions | List<Widget>?| Actions supplémentaires | Non |
| showNewPassageButton | bool | Afficher le bouton "Nouveau passage" | Non |
| onNewPassagePressed | VoidCallback?| Fonction appelée pour créer un nouveau passage | Non |
| isAdmin | bool | Indique si l'utilisateur est un administrateur | Non |
**Exemple d'utilisation**:
```dart
DashboardAppBar(
title: 'GEOSECTOR',
pageTitle: 'Tableau de bord',
isAdmin: userRepository.isAdmin(),
showNewPassageButton: true,
onNewPassagePressed: () => Navigator.pushNamed(context, '/passage/new'),
)
```
## Visualisation cartographique
### MapboxMap
Widget de carte réutilisable utilisant Mapbox pour afficher des marqueurs et des polygones.
**Fichier**: `lib/presentation/widgets/mapbox_map.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|------------------|----------------------------|----------------------------------------------|--------|
| initialPosition | LatLng | Position initiale de la carte | Non |
| initialZoom | double | Niveau de zoom initial | Non |
| markers | List<Marker>? | Liste des marqueurs à afficher | Non |
| polygons | List<Polygon>? | Liste des polygones à afficher | Non |
| mapController | MapController? | Contrôleur de carte externe | Non |
| onMapEvent | Function(MapEvent)? | Callback lors des événements de carte | Non |
| showControls | bool | Afficher les boutons de contrôle | Non |
| mapStyle | String? | Style de la carte Mapbox | Non |
**Exemple d'utilisation**:
```dart
MapboxMap(
initialPosition: LatLng(48.1173, -1.6778),
initialZoom: 13.0,
markers: sectorMarkers,
polygons: [
Polygon(
points: sector.getCoordinates().map((p) => LatLng(p[0], p[1])).toList(),
color: Color(int.parse(sector.color.replaceAll('#', '0xFF'))),
borderStrokeWidth: 2,
borderColor: Colors.black,
),
],
showControls: true,
)
```
## Affichage des données
### PassagesListWidget
Widget réutilisable pour afficher une liste de passages avec filtres et actions.
**Fichier**: `lib/presentation/widgets/passages/passages_list_widget.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|--------------------|----------------------------------------|-----------------------------------------------|--------|
| passages | List<Map<String, dynamic>> | Liste des passages à afficher | Oui |
| title | String? | Titre de la section | Non |
| maxPassages | int? | Nombre maximum de passages à afficher | Non |
| showFilters | bool | Afficher les filtres | Non |
| showSearch | bool | Afficher la barre de recherche | Non |
| showActions | bool | Afficher les boutons d'action | Non |
| onPassageSelected | Function(Map<String, dynamic>)? | Callback à la sélection d'un passage | Non |
| onPassageEdit | Function(Map<String, dynamic>)? | Callback pour éditer un passage | Non |
| onReceiptView | Function(Map<String, dynamic>)? | Callback pour voir un reçu | Non |
| initialTypeFilter | String? | Filtre de type initial | Non |
| initialPaymentFilter| String? | Filtre de paiement initial | Non |
**Format attendu des passages**:
```dart
[
{
'id': 1001,
'address': '12 Rue des Lilas, Paris',
'type': 1, // Correspond à AppKeys.typesPassages
'payment': 2, // Correspond à AppKeys.typesReglements
'date': DateTime(2025, 4, 15),
'amount': 25.50,
'name': 'Martin Dupont',
'notes': 'Premier étage à droite',
'hasError': false,
'fkUser': 123 // ID de l'utilisateur qui a effectué le passage
},
// ...
]
```
**Exemple d'utilisation**:
```dart
PassagesListWidget(
passages: passagesList,
title: 'Historique des passages',
showFilters: true,
showSearch: true,
onPassageSelected: (passage) => showPassageDetails(passage),
onPassageEdit: (passage) => editPassage(passage),
onReceiptView: (passage) => viewReceipt(passage),
)
```
## Visualisation de données
### ActivityChart
Graphique d'activité affichant les passages par jour/semaine/mois.
**Fichier**: `lib/presentation/widgets/charts/activity_chart.dart`
**Propriétés principales**:
| Propriété | Type | Description | Requis |
|----------------------|-----------------------------|-----------------------------------------------|--------|
| passageData | List<Map<String, dynamic>>? | Données des passages | Non* |
| periodType | String | Type de période (Jour, Semaine, Mois) | Non |
| height | double | Hauteur du graphique | Non |
| daysToShow | int | Nombre de jours à afficher | Non |
| userId | int? | ID de l'utilisateur pour filtrer | Non |
| excludePassageTypes | List<int> | Types de passages à exclure | Non |
| loadFromHive | bool | Charger depuis Hive au lieu des données fournies | Non |
| title | String | Titre du graphique | Non |
| showDataLabels | bool | Afficher les étiquettes de valeur | Non |
| columnWidth | double | Largeur des colonnes | Non |
| columnSpacing | double | Espacement entre les colonnes | Non |
| showAllPassages | bool | Afficher tous les passages sans filtrage | Non |
\* Soit `passageData` doit être fourni, soit `loadFromHive` doit être `true`.
**Format attendu de passageData**:
```dart
[
{
'date': '2025-04-01',
'type_passage': 1,
'nb': 5
},
{
'date': '2025-04-01',
'type_passage': 3,
'nb': 2
},
// ...
]
```
**Exemple d'utilisation**:
```dart
ActivityChart(
loadFromHive: true,
periodType: 'Jour',
height: 350,
daysToShow: 15,
userId: userRepository.userId,
excludePassageTypes: [2, 6],
title: 'Activité des 15 derniers jours',
)
```
## Autres widgets
### PassagePieChart et PaymentPieChart
Graphiques circulaires affichant la répartition des passages et des paiements.
**Fichiers**:
- `lib/presentation/widgets/charts/passage_pie_chart.dart`
- `lib/presentation/widgets/charts/payment_pie_chart.dart`
Ces widgets utilisent les mêmes principes que ActivityChart mais avec une visualisation circulaire.
**Exemple d'utilisation**:
```dart
Row(
children: [
Expanded(
child: PassagePieChart(
loadFromHive: true,
title: 'Répartition par type',
height: 300,
),
),
Expanded(
child: PaymentPieChart(
loadFromHive: true,
title: 'Répartition par règlement',
height: 300,
),
),
],
)
```
## Adaptabilité et responsive design
Tous les widgets communs sont conçus pour s'adapter aux différentes tailles d'écran:
1. **Détection de la taille d'écran**:
```dart
final size = MediaQuery.of(context).size;
final isDesktop = size.width > 900;
```
2. **Layouts conditionnels**:
```dart
isDesktop
? _buildDesktopLayout()
: _buildMobileLayout()
```
3. **Flexibilité des widgets**:
- Utilisation fréquente de `Expanded` et `Flexible`
- Définition de contraintes minimales et maximales
- Ajustement du nombre de colonnes selon l'espace disponible
## Bonnes pratiques implémentées
1. **Gestion des erreurs robuste** - Chaque widget inclut une gestion d'erreurs pour éviter les plantages lors des problèmes de données.
2. **Optimisation des performances** - Évitement des rebuilds inutiles et utilisation d'animations fluides.
3. **Séparation des préoccupations** - Les widgets se concentrent sur l'affichage, laissant la logique métier aux repositories.
4. **Documentation complète** - Chaque widget comporte des commentaires de documentation détaillés.
5. **Paramétrage flexible** - La plupart des widgets peuvent être personnalisés via leurs propriétés.
## Utilisation avec les thèmes
Les widgets communs respectent le thème de l'application défini dans `app_theme.dart`. Ils utilisent systématiquement:
```dart
final theme = Theme.of(context);
// Utilisation des couleurs du thème
theme.colorScheme.primary
theme.colorScheme.onPrimary
// Utilisation des styles de texte du thème
theme.textTheme.bodyLarge
```
Cela garantit une apparence cohérente et le support des thèmes clairs et sombres.