# Module — Administration des boutiques

> Socle transverse (hors phasage). **Module largement existant** : création de boutiques, appartenances, RBAC par boutique et connexion base de données sont déjà en place. On documente l'existant (✅) et les compléments (⬜).
> Liens : [README modules](README.md) · [Vision](../README.md) · [Architecture](../01-architecture.md) · [Modèle de données](../02-modele-de-donnees.md) · [Sécurité](../03-securite.md) · [API](../04-api.md) · [Décisions](../notes/decisions.md) · [Architecture multi-tenant](../../portail-manager/docs/ARCHITECTURE_MULTITENANT.md).

## 0. Complément PWA — infos boutique (2026-07-24) ✅

API v1 **`GET`/`PUT /api/v1/boutique`** : consulter et modifier depuis la PWA les infos de la
boutique courante (nom, **NINEA**, **RCCM**, adresse, ville, téléphone, e-mail, site). Gating
`COMPANY_VIEW` (lecture) / `COMPANY_EDIT` (modif). Ces mentions **alimentent l'entête des factures**.
PWA : section **« Ma boutique »** dans l'onglet Profil (carte + formulaire d'édition), avec rappel
si NINEA/RCCM manquants. Test `BoutiqueApiTest`. Fichiers : `src/Controller/Api/V1/BoutiqueController.php`,
`yima-shop/.../boutique.service.ts`, `features/shell/profile.page`.

## 0 bis. Complément PWA — employés/caissiers (2026-07-25) ✅

API v1 **`/api/v1/employees`** (`EmployeeController`), gating **`COMPANY_MANAGE_EMPLOYEES`** (membre
actif **et** ROLE_MANAGER) : `GET` liste les rattachements de la boutique (`UserCompanyRepository::findByCompany`) ;
`POST` **crée un caissier** — compte `ROLE_EMPLOYER` + `UserCompany` role `cashier`, mot de passe fourni
(politique 8+/Maj/min/chiffre) **ou temporaire généré** renvoyé une fois, `mustChangePassword`/`isFirstLogin`,
e-mail de bienvenue (`employee_created.html.twig`, fail-soft) ; `POST /{id}/activate|deactivate` bascule
`UserCompany.isActive` (protège l'auto-modification et les ROLE_ADMIN/MANAGER). Réutilise le flux de
`CompanyController::employeesCreate`. PWA : écran **Employés** (`features/employees/`, liste + toggle d'accès +
création par modal, mot de passe temporaire affiché en alerte au responsable), accès **Profil→Gestion**
réservé aux managers (`isManager` d'après les rôles). Test `EmployeeApiTest` (création, connexion caissier,
unicité e-mail, activation/désactivation, gating).

## 0 ter. RBAC réel — rôles & permissions par boutique (2026-07-25, F1) ✅

`PermissionResolver` **activé** : si `UserCompany.boutiqueRole` est défini, les permissions du rôle
RBAC font autorité (sinon fallback rôles Symfony). `Role.company` nullable → **rôles personnalisés
par boutique** (unicité `(company, code)`). Rôles système seedés : Manager, Employé, **Caissier**,
**Magasinier** (`RbacSeedCommand`, permissions `boutique.*`/`catalogue.*`/`stock.*`/`pos.*`/…).
API `RoleController` (`/api/v1/roles` : liste des rôles assignables + catalogue des permissions,
création/édition/suppression des rôles **personnalisés**), gating `COMPANY_MANAGE_EMPLOYEES`.
`EmployeeController` assigne le `boutiqueRole` (défaut Caissier) et `POST /employees/{id}/role`.
PWA : écran **Rôles & permissions** (`features/roles/`, cases à cocher par catégorie) + sélecteur de
rôle dans **Employés**. ⚠️ Gating encore coarse (VIEW/EDIT/MANAGE_EMPLOYEES) ; permissions fines
seedées mais non encore mappées par endpoint. Test `RoleApiTest` (CRUD + **enforcement**).

## 1. Objectif

Administrer les **boutiques** (clients) et leurs membres : créer une boutique, y assigner un **manager**, gérer les **employés** et leurs **rôles boutique**, et configurer la **base de données** dédiée de la boutique.

- **Admin plateforme** : crée les boutiques, assigne les managers, configure la base de données cliente.
- **Manager** : gère les employés de **sa** boutique et leurs rôles/permissions, administre les ressources de sa boutique (« gestion des créations »).
- **Employé** : rattaché à une boutique, accès selon ses permissions.

## 2. Périmètre

**In**
- ✅ **Créer / éditer une boutique** (`Company`), assigner un **manager**.
- ✅ **Gérer les employés** (rattachement `UserCompany`, rôle boutique `boutiqueRole`).
- ✅ **RBAC par boutique** (`Role`/`Permission`, `PermissionResolver`, voters).
- ✅ **Configurer la base de données** de la boutique (`CompanyDatabase`) + **test de connexion**.
- ⬜ Rôle **« gestion des créations »** : administration/paramétrage des ressources d'une boutique (catalogue, taux, catégories…) — regroupement de permissions.

**Out**
- Provisioning automatique de la base cliente (`CREATE DATABASE`, migrations) — cf. [multi-tenant §5](../../portail-manager/docs/ARCHITECTURE_MULTITENANT.md) (phase 2).
- Facturation SaaS des boutiques (plan de contrôle, ultérieur).

## 3. Entités

| État | Entité | Rôle |
|---|---|---|
| ✅ | **`Company`** (boutique) | Client / tenant ; soft-delete ; NINEA/RCCM/adresse |
| ✅ | **`UserCompany`** | Appartenance user↔boutique : `role`, **`boutiqueRole`** (`Role`), `isActive`, `joinedAt`, `leftAt` |
| ✅ | **`Role`** / **`Permission`** | RBAC par boutique (portés par `boutiqueRole`) |
| ✅ | **`CompanyDatabase`** (1:1 `Company`) | Connexion chiffrée à la base cliente + statut de test |
| ⬜ | *(seed)* rôle **« Gestion des créations »** | `Role` regroupant les permissions d'administration des ressources boutique |

Rename d'affichage **Company → Boutique** (le code garde `Company`/`companies`).

## 4. Permissions (RBAC)

| Code | État | Rôle type | Usage |
|---|---|---|---|
| `boutique.view` | ⬜ (à seeder) | Manager, Employé | Consulter sa boutique |
| `boutique.edit` | ⬜ (à seeder) | Manager (sa boutique), Admin | Éditer les infos boutique |
| `boutique.employee.manage` | ⬜ (à seeder) | Manager, Admin | Ajouter/retirer employés, affecter les rôles boutique |
| `boutique.database.manage` | ⬜ (à seeder) | Admin | Configurer/tester la base cliente |
| `boutique.resource.manage` | ⬜ (à seeder) | Manager / « gestion des créations » | Administrer les ressources (catalogue, taux, catégories) |

Voters existants : ✅ **`CompanyVoter`** (`COMPANY_VIEW`/`COMPANY_EDIT`/`COMPANY_MANAGE_EMPLOYEES`) et ✅ **`PermissionVoter`** (codes fins). Les nouveaux codes viennent compléter les voters existants (rétro-compatibles, ADR-002). Seeding idempotent via `RbacSeedCommand`.

## 5. API (`/api/v1`)

| Méthode | Route | Corps / params | Permission |
|---|---|---|---|
| `GET` | `/api/v1/boutiques` | `?page=&limit=` (admin : toutes ; manager : la sienne) | `boutique.view` |
| `POST` | `/api/v1/boutiques` | `{ name, ninea?, rccm?, address? }` | (Admin) |
| `GET` | `/api/v1/boutiques/{uuid}` | — | `boutique.view` |
| `PATCH` | `/api/v1/boutiques/{uuid}` | champs éditables | `boutique.edit` |
| `GET` | `/api/v1/boutiques/{uuid}/employees` | membres + rôles | `boutique.view` |
| `POST` | `/api/v1/boutiques/{uuid}/employees` | `{ userId, boutiqueRoleId }` | `boutique.employee.manage` |
| `DELETE` | `/api/v1/boutiques/{uuid}/employees/{userId}` | désactive l'appartenance | `boutique.employee.manage` |

Enveloppe `ApiResponseFormatter` ; scoping `Company` ; validation → 422. (Le web Twig existant reste la surface d'administration principale ; l'API `/api/v1` sert la PWA.)

## 6. Écrans

**Web (Twig)** — ✅ existant
- **Admin** (`Admin/CompanyController`) : liste/CRUD des boutiques, assignation du manager, section **base de données** (`_database_section.html.twig`) + **Tester la connexion** (route ✅ `admin_companies_database_test`, test fonctionnel `admin_companies_database_test`).
- **Manager** (`Manager/ManagerUserController`) : gestion des employés de sa boutique (auto-scopée à `getPrimaryCompany()`), affectation des rôles boutique.
- ⬜ Écran « **Gestion des créations** » : point d'entrée d'administration des ressources de la boutique (catalogue/taux/catégories) pour le rôle dédié.

**PWA (Ionic)** — ⬜
- Vue lecture de la boutique et de ses membres ; gestion d'employés (si permission) via l'API.

## 7. Règles métier

- **Isolation par boutique** : un manager n'agit que sur **sa** `Company` (`user->hasCompany($company)` via `CompanyVoter`) ; un employé sans boutique est bloqué (`CompanyAccessListener` → `/no-company`).
- **Assignation du manager** : réservée à l'Admin ; crée/active un `UserCompany` avec le `boutiqueRole` manager.
- **Rôles boutique** : portés par `UserCompany.boutiqueRole` ; résolution des permissions via ✅ **`PermissionResolver`**. En phase 1, les rôles **globaux** (`User::getRoles()`) restent l'autorité ; viser la bascule vers l'autorité par boutique en phase 2 (ADR-002).
- **Base de données cliente** : mot de passe **chiffré** (`EncryptionService`), jamais journalisé ; idiome « laisser vide pour conserver » à l'édition ; **test de connexion** réservé à `COMPANY_EDIT` (SSRF, cf. [multi-tenant §6](../../portail-manager/docs/ARCHITECTURE_MULTITENANT.md)).
- **Cycle de vie d'un employé** : retrait = désactivation (`isActive=false`, `leftAt`) et non suppression (traçabilité) ; `Company` en soft-delete.
- **« Gestion des créations »** : rôle regroupant `boutique.resource.manage` (+ permissions catalogue/taxes) — un manager peut déléguer l'administration des ressources sans donner la gestion des employés.
- I/O contrôleur : try/catch, `FileLogger`, écritures via `EntityManagerService`.

## 8. Projection e-commerce

- L'administration des boutiques est une donnée du **plan de contrôle** : **non projetée** vers les bases clients.
- En revanche, elle **provisionne** la cible de la [projection e-commerce](ecommerce-projection.md) : la `CompanyDatabase` configurée ici est la base où la sync écrit. Le futur site e-commerce est résolu par domaine/sous-domaine vers cette boutique (cf. [multi-tenant §4](../../portail-manager/docs/ARCHITECTURE_MULTITENANT.md)).

## 9. Tests

- **Fonctionnels** : CRUD boutique (admin), assignation manager, ajout/retrait d'employé (manager scopé), **test de connexion DB** (✅ `admin_companies_database_test`).
- **Accès** : `CompanyVoter`/`PermissionVoter` — un manager ne voit/édite pas une autre boutique ; employé sans boutique bloqué ; `boutique.database.manage` réservé Admin.
- **Unitaires** : `PermissionResolver` (résolution des permissions du `boutiqueRole`), chiffrement du mot de passe DB (jamais en clair).

## 10. Dépendances

- ✅ Socle existant : `Company`, `UserCompany`, `Role`/`Permission`, `PermissionResolver`, `CompanyVoter`, `PermissionVoter`, `CompanyDatabase`, `EncryptionService`, `TenantConnectionService`, `Admin/CompanyController`, `Manager/ManagerUserController`.
- Aval : [Projection e-commerce](ecommerce-projection.md) (cible DB), tous les modules métier (scoping `Company`).
- Socle transverse : `EntityManagerService`, `FileLogger`, `ApiResponseFormatter`.

## 11. Notes / ADR liés

- **ADR-002** — RBAC par boutique rétro-compatible (rôles globaux autoritaires en phase 1).
- **ADR-003** — Chiffrement des secrets (mot de passe DB client).
- **ADR-001** — La boutique administrée ici est le tenant dont la base reçoit la projection.
- ⬜ À faire : seeder les codes `boutique.*` et le rôle « Gestion des créations », brancher les voters sur ces codes, exposer l'API `/api/v1/boutiques`, provisioning automatique de la base (phase 2).
