# CSTM Enquetes

Application de collecte de donnees terrain pour la CSTM (Compagnie Senegalaise
de Transformation des Materiaux). Elle permet a des agents terrain de visiter
des boutiques, clients existants ou prospects, et de soumettre des reponses a
des questionnaires dynamiques crees par un administrateur.

Chaque soumission correspond a une visite terrain geolocalisee.

## Stack Technique

- Backend API : Laravel 13
- Authentification API : Laravel Sanctum
- Frontend SPA : Vue.js avec Vite
- Base de donnees locale : MySQL, selon `.env`
- PHP : 8.3 via `.envrc`
- Node.js / npm : 22.18.0

Le projet Laravel et le projet Vue sont deja installes. Il ne faut pas les
reinstaller pour les evolutions courantes.

## Environnement Local

Le fichier `.envrc` ajoute PHP 8.3 au `PATH` :

```sh
export PATH="/usr/local/opt/php@8.3/bin:$PATH"
```

Apres entree dans le dossier du projet, verifier que l'environnement est bien
charge :

```sh
php -v
node -v
npm -v
```

Si `direnv` est utilise, autoriser le fichier une premiere fois :

```sh
direnv allow
```

## Commandes Utiles

Installer les dependances PHP :

```sh
composer install
```

Installer les dependances JavaScript :

```sh
npm install
```

Lancer les migrations :

```sh
php artisan migrate
```

Lancer le frontend en developpement :

```sh
npm run dev
```

Verifier le formatage PHP :

```sh
php ./vendor/bin/pint --test
```

Corriger le formatage PHP :

```sh
php ./vendor/bin/pint
```

Creer ou mettre a jour l'administrateur initial :

```sh
php artisan db:seed --class=AdminUserSeeder
```

## Layout Administrateur

Toutes les routes protegees sont rendues dans `AdminLayout.vue`. Le layout
contient :

- une sidebar avec les menus filtres selon le role de l'utilisateur ;
- une navbar avec le titre de la page, le theme, le profil et la deconnexion ;
- un bouton de navigation pour reduire la sidebar aux icones sur grand ecran ;
- un tiroir de navigation avec voile et fermeture par `Echap` sur petit ecran.

L'etat de la sidebar et du theme est gere par le store Pinia `ui` et persiste
dans le navigateur. Le layout est monte comme parent des pages authentifiees et
les pages enfants sont rendues dans son `RouterView`.

Les routes de navigation actuellement disponibles sont :

- `/` : tableau de bord ;
- `/visites` : visites terrain ;
- `/points` : points de vente ;
- `/questionnaires` : questionnaires, reserve aux administrateurs ;
- `/statistiques` : statistiques ;
- `/agents` : agents, reserve aux administrateurs ;
- `/parametres` : parametres, reserve aux administrateurs.

Les modules autres que le tableau de bord utilisent provisoirement la page
`EnConstruction.vue` en attendant leur branchement sur l'API.

## Domaine Fonctionnel

L'application repose sur trois blocs principaux :

- Administration des questionnaires dynamiques.
- Collecte terrain par les agents.
- Stockage des reponses avec position GPS obligatoire.

Un questionnaire est compose de groupes de questions. Chaque groupe contient
des questions ordonnees. Selon le type de reponse, une question peut accepter du
texte, un booleen, une option unique ou plusieurs options.

Une reponse represente une visite terrain complete d'un agent dans une boutique
ou un point prospect.

## Enums

Les enums sont des backed enums PHP natifs dans `app/Enums`.

- `RoleEnum` : `admin`, `agent`
- `TypeReponseEnum` : `choix_unique`, `choix_multiple`, `texte_court`,
  `texte_long`, `oui_non`
- `TypePointEnum` : `client`, `prospect`

Les migrations utilisent des colonnes `string` pour ces valeurs. La contrainte
est applicative et les models Eloquent declarent les casts enum correspondants.

## Authentification API

L'authentification API utilise Laravel Sanctum en mode token Bearer.

Endpoints disponibles :

- `POST /api/auth/login`
- `GET /api/auth/me`
- `POST /api/auth/logout`

Payload de connexion :

```json
{
  "email": "admin@cstm.sn",
  "password": "password",
  "device_name": "web"
}
```

Reponse de connexion :

```json
{
  "token": "...",
  "token_type": "Bearer",
  "user": {}
}
```

Les requetes protegees doivent envoyer le token :

```http
Authorization: Bearer <token>
```

L'administrateur initial est cree par `AdminUserSeeder`. Les valeurs peuvent
etre surchargees via l'environnement :

- `CSTM_ADMIN_NAME`, defaut `Administrateur CSTM`
- `CSTM_ADMIN_EMAIL`, defaut `admin@cstm.sn`
- `CSTM_ADMIN_PASSWORD`, defaut `password`
- `CSTM_ADMIN_TELEPHONE`, defaut `null`

Changer le mot de passe par defaut avant une mise en production.

## Modele De Donnees

Toutes les cles primaires applicatives sont des UUID. Les models Eloquent
utilisent le trait `HasUuids`.

### users

Utilisateurs de l'application.

- `id` : UUID, cle primaire
- `name`
- `email`
- `email_verified_at`
- `password`
- `role` : `RoleEnum`, defaut `agent`
- `telephone`, nullable
- `actif`, defaut `true`
- `remember_token`
- timestamps

Relations principales :

- `questionnaires()` : questionnaires crees par l'utilisateur
- `reponses()` : visites soumises par l'agent

### questionnaires

Questionnaires dynamiques crees par l'administration.

- `id` : UUID
- `titre`
- `description`, nullable
- `actif`, defaut `false`
- `cree_par` : utilisateur createur, nullable
- timestamps

Regle metier : un seul questionnaire actif a la fois dans toute l'application.
Cette contrainte doit etre geree cote service ou controller, pas dans la
migration.

Relations principales :

- `creePar()`
- `groupesQuestions()`
- `reponses()`

### groupes_questions

Groupes ordonnes de questions dans un questionnaire.

- `id` : UUID
- `questionnaire_id`
- `titre`
- `description`, nullable
- `ordre`, defaut `0`
- timestamps

Relations principales :

- `questionnaire()`
- `questions()`

### questions

Questions rattachees a un groupe.

- `id` : UUID
- `groupe_id`
- `libelle`
- `type_reponse` : `TypeReponseEnum`
- `obligatoire`, defaut `true`
- `ordre`, defaut `0`
- timestamps

Relations principales :

- `groupe()`
- `optionsQuestion()`
- `reponseDetails()`

### options_question

Options proposees pour les questions a choix.

- `id` : UUID
- `question_id`
- `libelle`
- `ordre`, defaut `0`
- timestamps

Relations principales :

- `question()`
- `reponseDetails()`
- `selectionneeDans()`

### reponses

Soumissions terrain. Une ligne correspond a une visite d'un agent dans un point
client ou prospect.

- `id` : UUID
- `questionnaire_id`
- `agent_id`
- `nom_point`
- `type_point` : `TypePointEnum`
- `quartier`, nullable
- `commune`, nullable
- `latitude` : decimal `10,7`
- `longitude` : decimal `10,7`
- `date_soumission`
- timestamps

Index :

- `agent_id`
- `questionnaire_id`
- `type_point`

Relations principales :

- `questionnaire()`
- `agent()`
- `reponseDetails()`

### reponse_details

Valeur saisie pour une question dans une soumission.

- `id` : UUID
- `reponse_id`
- `question_id`
- `valeur_texte`, nullable
- `valeur_bool`, nullable
- `option_id`, nullable
- timestamps

Contrainte :

- unique `reponse_id`, `question_id`

Relations principales :

- `reponse()`
- `question()`
- `option()`
- `optionsSelectionnees()`

### reponse_detail_options

Table pivot pour les questions a choix multiple.

- `id` : UUID
- `reponse_detail_id`
- `option_id`
- timestamps

Contrainte :

- unique `reponse_detail_id`, `option_id`

## Conventions De Developpement

- Ne pas ajouter de controllers, routes, vues ou seeders sans besoin explicite.
- Garder les UUID partout pour les cles primaires applicatives.
- Utiliser des backed enums PHP natifs pour les valeurs enumerees.
- Declarer les casts Eloquent pour les enums, booleens, dates et decimals.
- Garder des migrations separees et ordonnees selon les dependances de cles
  etrangeres.
