Compare commits

..

8 Commits

Author SHA1 Message Date
gitea-actions
1696602abb chore: bump version to v0.1.38
All checks were successful
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 22s
2026-05-19 06:38:13 +00:00
Matthieu
cacd8718e5 chore(prod) : ajuster conf prod pour HTTP en reseau local
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
- .env.prod.example : JWT_COOKIE_SECURE=0, CORS_ALLOW_ORIGIN en http
- prompt-rename-prod.md : retirer etape certbot/Let's Encrypt, verifier la resolution locale a la place
- deployment-docker.md : aligner DEFAULT_URI, CORS et JWT_COOKIE_SECURE sur HTTP
2026-05-19 08:38:03 +02:00
gitea-actions
f7a50168d5 chore: bump version to v0.1.37
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 1m11s
2026-05-19 06:33:20 +00:00
Matthieu
93cbd48bf5 chore : rename Coltura to Starseed
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
- Rename project name across code, configs, docs, dev/prod infra
- Dev: DOCKER_APP_NAME + POSTGRES_DB switched to starseed, containers become php-starseed-fpm / nginx-starseed / starseed-db-1
- Dev: mount nginx.conf on default.conf instead of starseed.conf to avoid alphabetical-order clash with image's default site
- Makefile: export CURRENT_UID/CURRENT_GID at top level so docker compose builds (db-reset etc.) get them
- Prod: image registry path, container_name, volumes, vhost server_name + paths, DATABASE_URL, CORS, CI workflow
- Add doc/prompt-rename-prod.md with the migration runbook for the prod server (DB rename, FS move, vhost, Let's Encrypt)
2026-05-19 08:24:19 +02:00
gitea-actions
cd17248427 chore: bump version to v0.1.36
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Successful in 2m10s
2026-05-13 09:22:08 +00:00
6bd7f3b059 fix : package-lock.json
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-05-13 11:21:39 +02:00
gitea-actions
b1ea732155 chore: bump version to v0.1.35
Some checks failed
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Failing after 10s
2026-05-13 09:03:50 +00:00
99e96cb493 [#ERP-41] Mise à jour Malio UI (#10)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|                  |                 |

## Description de la PR

## Modification du .env

## Check list

- [ ] Pas de régression
- [x] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [ ] CHANGELOG modifié

Reviewed-on: MALIO-DEV/Coltura#10
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-05-13 09:03:44 +00:00
46 changed files with 1321 additions and 292 deletions

View File

@@ -41,8 +41,8 @@ Si une verification echoue ou ne peut pas etre lancee (ex : container pas demarr
## Time tracking Lesstime ## Time tracking Lesstime
Au demarrage de toute tache de dev sur Coltura, creer une time entry via l'API Lesstime (cf. `~/.claude/CLAUDE.md` pour la procedure complete). Au demarrage de toute tache de dev sur Starseed, creer une time entry via l'API Lesstime (cf. `~/.claude/CLAUDE.md` pour la procedure complete).
- Projet : `/api/projects/6` (COLTURA) - Projet : `/api/projects/6` (STARSEED)
- Tags : choisir selon le type (Backend `3`, Frontend `2`, Infra `5`, UI/UX `4`, Maintenance `6`, Gestion projet `9`, etc.) - Tags : choisir selon le type (Backend `3`, Frontend `2`, Infra `5`, UI/UX `4`, Maintenance `6`, Gestion projet `9`, etc.)
## Fix `make cache-clear` (permissions `var/`) ## Fix `make cache-clear` (permissions `var/`)
@@ -50,17 +50,17 @@ Au demarrage de toute tache de dev sur Coltura, creer une time entry via l'API L
Si `make cache-clear` echoue sur les permissions de `var/` : Si `make cache-clear` echoue sur les permissions de `var/` :
```bash ```bash
docker exec -t -u root php-coltura-fpm chown -R www-data:www-data /var/www/html/var docker exec -t -u root php-starseed-fpm chown -R www-data:www-data /var/www/html/var
docker exec -t -u www-data php-coltura-fpm php bin/console cache:clear docker exec -t -u www-data php-starseed-fpm php bin/console cache:clear
``` ```
A terme : integrer ce fix dans le `makefile` lui-meme. A terme : integrer ce fix dans le `makefile` lui-meme.
## Docker — references utiles ## Docker — references utiles
- Container PHP : `php-coltura-fpm` - Container PHP : `php-starseed-fpm`
- Container Nginx : `nginx-coltura` (port 8083) - Container Nginx : `nginx-starseed` (port 8083)
- Container DB : PostgreSQL port **5437** (interne et externe) - Container DB : PostgreSQL port **5437** (interne et externe)
- Config dev : `infra/dev/.env.docker` (override local : `infra/dev/.env.docker.local`) - Config dev : `infra/dev/.env.docker` (override local : `infra/dev/.env.docker.local`)
- Config prod : `infra/prod/` (Dockerfile multi-stage, `docker-compose.prod.yml`) - Config prod : `infra/prod/` (Dockerfile multi-stage, `docker-compose.prod.yml`)
- Apres modif nginx : `docker restart nginx-coltura` - Apres modif nginx : `docker restart nginx-starseed`

View File

@@ -1,11 +1,11 @@
--- ---
name: create-module name: create-module
description: Scaffold a new Coltura module (backend + frontend) and optionally wire its entries into the sidebar config. Use when the user asks to create, add, scaffold, or generate a new module — e.g., "crée un module Paie", "add a Pointage module", "ajoute un module RH". The backend is the source of truth for activation and sidebar layout; the frontend scans modules automatically. description: Scaffold a new Starseed module (backend + frontend) and optionally wire its entries into the sidebar config. Use when the user asks to create, add, scaffold, or generate a new module — e.g., "crée un module Paie", "add a Pointage module", "ajoute un module RH". The backend is the source of truth for activation and sidebar layout; the frontend scans modules automatically.
--- ---
# Create a new Coltura module # Create a new Starseed module
Scaffolds a new module across backend and frontend following Coltura's modular monolith DDD architecture. Scaffolds a new module across backend and frontend following Starseed's modular monolith DDD architecture.
## Architecture reminder — read before acting ## Architecture reminder — read before acting
@@ -178,8 +178,8 @@ Execute in this exact order:
6. **Backend: sidebar** — if the user wants sidebar entries, edit `config/sidebar.php`. 6. **Backend: sidebar** — if the user wants sidebar entries, edit `config/sidebar.php`.
7. **Frontend: translations** — edit `frontend/i18n/locales/fr.json`. 7. **Frontend: translations** — edit `frontend/i18n/locales/fr.json`.
8. **Verify** — run: 8. **Verify** — run:
- `docker exec -t -u root php-coltura-fpm chown -R www-data:www-data /var/www/html/var` (avoid permission issues) - `docker exec -t -u root php-starseed-fpm chown -R www-data:www-data /var/www/html/var` (avoid permission issues)
- `docker exec -t -u www-data php-coltura-fpm php bin/console cache:clear` (validates backend) - `docker exec -t -u www-data php-starseed-fpm php bin/console cache:clear` (validates backend)
- `cd frontend && npx nuxi prepare` (validates Nuxt auto-detection of the new layer) - `cd frontend && npx nuxi prepare` (validates Nuxt auto-detection of the new layer)
9. **Report** — list files created, the route(s) to test, and the sidebar items added. 9. **Report** — list files created, the route(s) to test, and the sidebar items added.

View File

@@ -20,11 +20,11 @@ jobs:
run: | run: |
docker build \ docker build \
-f infra/prod/Dockerfile \ -f infra/prod/Dockerfile \
-t gitea.malio.fr/malio-dev/coltura:${{ gitea.ref_name }} \ -t gitea.malio.fr/malio-dev/starseed:${{ gitea.ref_name }} \
-t gitea.malio.fr/malio-dev/coltura:latest \ -t gitea.malio.fr/malio-dev/starseed:latest \
. .
- name: Push Docker image - name: Push Docker image
run: | run: |
docker push gitea.malio.fr/malio-dev/coltura:${{ gitea.ref_name }} docker push gitea.malio.fr/malio-dev/starseed:${{ gitea.ref_name }}
docker push gitea.malio.fr/malio-dev/coltura:latest docker push gitea.malio.fr/malio-dev/starseed:latest

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
/.env.local.php /.env.local.php
/.env.*.local /.env.*.local
/config/secrets/dev/dev.decrypt.private.php /config/secrets/dev/dev.decrypt.private.php
/config/reference.php
/public/bundles/ /public/bundles/
/var/ /var/
/vendor/ /vendor/

View File

@@ -1,6 +1,6 @@
# Changelog # Changelog
Liste des évolutions du projet Coltura Liste des évolutions du projet Starseed
## [0.0.0] ## [0.0.0]

View File

@@ -1,4 +1,4 @@
# Coltura # Starseed
## Contexte ## Contexte
CRM/ERP en architecture **modular monolith DDD**. Le backend est la source de verite unique (modules actifs, sidebar). Le frontend scanne `frontend/modules/*/` comme layers Nuxt et consomme l'API pour la navigation. Multi-tenant : chaque module est activable/desactivable. CRM/ERP en architecture **modular monolith DDD**. Le backend est la source de verite unique (modules actifs, sidebar). Le frontend scanne `frontend/modules/*/` comme layers Nuxt et consomme l'API pour la navigation. Multi-tenant : chaque module est activable/desactivable.
@@ -9,7 +9,7 @@ Doc humaine : @README.md — Spec audit : @doc/audit-log.md
- Backend : PHP 8.4, Symfony 8, API Platform 4, Doctrine ORM, PostgreSQL 16 (port 5437) - Backend : PHP 8.4, Symfony 8, API Platform 4, Doctrine ORM, PostgreSQL 16 (port 5437)
- Frontend : Nuxt 4 (SPA), Vue 3, Pinia, Tailwind, @malio/layer-ui, @nuxtjs/i18n - Frontend : Nuxt 4 (SPA), Vue 3, Pinia, Tailwind, @malio/layer-ui, @nuxtjs/i18n
- Auth : JWT HTTP-only cookie (Lexik), login a `/login_check` - Auth : JWT HTTP-only cookie (Lexik), login a `/login_check`
- Containers : `php-coltura-fpm`, `nginx-coltura` (port 8083), dev Nuxt port **3004** - Containers : `php-starseed-fpm`, `nginx-starseed` (port 8083), dev Nuxt port **3004**
## Regles ABSOLUES ## Regles ABSOLUES

View File

@@ -1,4 +1,4 @@
# Coltura # Starseed
CRM/ERP — Symfony 8 (API Platform 4) + Nuxt 4 CRM/ERP — Symfony 8 (API Platform 4) + Nuxt 4

View File

@@ -39,7 +39,7 @@ La branche est globalement solide : les trois miroirs RBAC sont synchronises, le
- { path: ^/api/docs, roles: PUBLIC_ACCESS } - { path: ^/api/docs, roles: PUBLIC_ACCESS }
``` ```
La documentation Swagger/OpenAPI d'API Platform est accessible sans authentification, quel que soit l'environnement — y compris en production sur `coltura.malio-dev.fr`. Elle expose : La documentation Swagger/OpenAPI d'API Platform est accessible sans authentification, quel que soit l'environnement — y compris en production sur `starseed.malio-dev.fr`. Elle expose :
- la liste complete des endpoints (`/api/audit-logs`, `/api/users/{id}/rbac`, `/api/sites`, etc.) - la liste complete des endpoints (`/api/audit-logs`, `/api/users/{id}/rbac`, `/api/sites`, etc.)
- les schemas de securite (`is_granted('core.audit_log.view')`) - les schemas de securite (`is_granted('core.audit_log.view')`)
@@ -94,7 +94,7 @@ Le reverse proxy ecoute uniquement sur le port 80 (HTTP), sans redirection 301 v
server { server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name coltura.malio-dev.fr; server_name starseed.malio-dev.fr;
# Redirection HTTPS obligatoire (ajouter un server block HTTPS par ailleurs). # Redirection HTTPS obligatoire (ajouter un server block HTTPS par ailleurs).
# Tant que le TLS n'est pas en place, au minimum poser les en-tetes suivants. # Tant que le TLS n'est pas en place, au minimum poser les en-tetes suivants.
@@ -123,7 +123,7 @@ User-Agent: *
Disallow: Disallow:
``` ```
La valeur `Disallow:` (vide) signifie "rien n'est interdit" — tous les crawlers peuvent indexer la totalite du site. Pour un outil CRM interne accessible sur un DNS public (`coltura.malio-dev.fr`), c'est un leak inutile : la page de login, les URLs `/admin/*`, les URLs des fiches clients peuvent remonter dans Google. La valeur `Disallow:` (vide) signifie "rien n'est interdit" — tous les crawlers peuvent indexer la totalite du site. Pour un outil CRM interne accessible sur un DNS public (`starseed.malio-dev.fr`), c'est un leak inutile : la page de login, les URLs `/admin/*`, les URLs des fiches clients peuvent remonter dans Google.
**Correction** : **Correction** :
@@ -581,7 +581,7 @@ Et ajouter les cles manquantes dans `fr.json` :
await loadSidebar() // apres chaque switch await loadSidebar() // apres chaque switch
``` ```
Commentaire : *"les filtres de modules peuvent dependre du site courant"*. En pratique, dans `config/sidebar.php` de Coltura aucun item ne depend du site. C'est un aller-retour reseau inutile a chaque switch, et la sidebar peut "flicker" pour l'utilisateur. Commentaire : *"les filtres de modules peuvent dependre du site courant"*. En pratique, dans `config/sidebar.php` de Starseed aucun item ne depend du site. C'est un aller-retour reseau inutile a chaque switch, et la sidebar peut "flicker" pour l'utilisateur.
**Correction** : rendre le rechargement opt-in ou documenter la raison actuelle (prevoir le futur). **Correction** : rendre le rechargement opt-in ou documenter la raison actuelle (prevoir le futur).

View File

@@ -39,7 +39,7 @@ access_control:
Comme `/api/docs` tombe desormais dans le dernier pattern (`^/api`), il faudra etre authentifie pour le voir. Les devs continueront de l'utiliser apres login — les attaquants non. Comme `/api/docs` tombe desormais dans le dernier pattern (`^/api`), il faudra etre authentifie pour le voir. Les devs continueront de l'utiliser apres login — les attaquants non.
3. Recharger : `make cache-clear` puis `make restart`. 3. Recharger : `make cache-clear` puis `make restart`.
4. Tester : `curl -i https://coltura.malio-dev.fr/api/docs` doit retourner `401 Unauthorized` (avant : `200`). 4. Tester : `curl -i https://starseed.malio-dev.fr/api/docs` doit retourner `401 Unauthorized` (avant : `200`).
**Fichiers :** `config/packages/security.yaml` **Fichiers :** `config/packages/security.yaml`
@@ -47,12 +47,12 @@ Comme `/api/docs` tombe desormais dans le dernier pattern (`^/api`), il faudra e
### T-002 — Ajouter les en-tetes de securite HTTP de base en prod ### T-002 — Ajouter les en-tetes de securite HTTP de base en prod
**Pourquoi :** sans `X-Frame-Options`, quelqu'un peut integrer Coltura dans une iframe sur un site tiers et faire du clickjacking (faire croire a l'utilisateur qu'il clique sur un bouton anodin alors qu'il valide une action dans Coltura). Sans `X-Content-Type-Options: nosniff`, un navigateur peut deviner le type MIME et executer un fichier qui n'aurait pas du l'etre. Ce sont 3 lignes de config Nginx pour proteger l'application. **Pourquoi :** sans `X-Frame-Options`, quelqu'un peut integrer Starseed dans une iframe sur un site tiers et faire du clickjacking (faire croire a l'utilisateur qu'il clique sur un bouton anodin alors qu'il valide une action dans Starseed). Sans `X-Content-Type-Options: nosniff`, un navigateur peut deviner le type MIME et executer un fichier qui n'aurait pas du l'etre. Ce sont 3 lignes de config Nginx pour proteger l'application.
**A faire :** **A faire :**
1. Ouvrir `infra/prod/nginx-proxy.conf` (c'est le proxy expose au public). 1. Ouvrir `infra/prod/nginx-proxy.conf` (c'est le proxy expose au public).
2. Ajouter juste apres `server_name coltura.malio-dev.fr;` : 2. Ajouter juste apres `server_name starseed.malio-dev.fr;` :
```nginx ```nginx
# En-tetes de securite applicables a toutes les reponses # En-tetes de securite applicables a toutes les reponses
@@ -62,13 +62,13 @@ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
``` ```
Explication : Explication :
- `X-Frame-Options: DENY` : personne ne peut mettre Coltura dans une iframe. - `X-Frame-Options: DENY` : personne ne peut mettre Starseed dans une iframe.
- `X-Content-Type-Options: nosniff` : le navigateur ne devine pas les types MIME, il fait confiance a ce que le serveur annonce. - `X-Content-Type-Options: nosniff` : le navigateur ne devine pas les types MIME, il fait confiance a ce que le serveur annonce.
- `Referrer-Policy: strict-origin-when-cross-origin` : limite ce que Coltura envoie comme Referer a des sites externes (evite de leaker `/admin/users/42` a un site tiers). - `Referrer-Policy: strict-origin-when-cross-origin` : limite ce que Starseed envoie comme Referer a des sites externes (evite de leaker `/admin/users/42` a un site tiers).
- `always` : envoyer ces en-tetes meme sur les reponses d'erreur (4xx/5xx). - `always` : envoyer ces en-tetes meme sur les reponses d'erreur (4xx/5xx).
3. Recharger Nginx : `docker restart nginx-coltura` (ou celui qui fait office de proxy public). 3. Recharger Nginx : `docker restart nginx-starseed` (ou celui qui fait office de proxy public).
4. Verifier : `curl -I https://coltura.malio-dev.fr/` doit afficher ces trois en-tetes. 4. Verifier : `curl -I https://starseed.malio-dev.fr/` doit afficher ces trois en-tetes.
**Note :** si un reverse proxy externe (Traefik, Cloudflare) ajoute deja ces en-tetes, les poser ici ne fait que dupliquer, c'est sans risque (meme valeur). **Note :** si un reverse proxy externe (Traefik, Cloudflare) ajoute deja ces en-tetes, les poser ici ne fait que dupliquer, c'est sans risque (meme valeur).
@@ -813,7 +813,7 @@ if (!is_array($payload)) {
```markdown ```markdown
# Changelog # Changelog
Liste des evolutions du projet Coltura. Liste des evolutions du projet Starseed.
## [0.1.34] - 2026-04-XX ## [0.1.34] - 2026-04-XX
@@ -859,7 +859,7 @@ Liste des evolutions du projet Coltura.
### T-019 — Conditionner `loadSidebar()` apres switch de site ### T-019 — Conditionner `loadSidebar()` apres switch de site
**Pourquoi :** apres chaque switch de site, `useCurrentSite` recharge la sidebar — mais la sidebar de Coltura ne depend d'aucun site. C'est un aller-retour reseau inutile par switch (~100ms + possible flicker visuel). **Pourquoi :** apres chaque switch de site, `useCurrentSite` recharge la sidebar — mais la sidebar de Starseed ne depend d'aucun site. C'est un aller-retour reseau inutile par switch (~100ms + possible flicker visuel).
**A faire :** **A faire :**

View File

@@ -1,5 +1,5 @@
api_platform: api_platform:
title: Coltura API title: Starseed API
version: 1.0.0 version: 1.0.0
# Scan du module Core pour decouvrir les classes ApiResource et ApiFilter. # Scan du module Core pour decouvrir les classes ApiResource et ApiFilter.
# Ajouter un chemin par module lors de l'ajout d'entites ApiResource dans d'autres modules. # Ajouter un chemin par module lors de l'ajout d'entites ApiResource dans d'autres modules.

View File

@@ -1,2 +1,2 @@
parameters: parameters:
app.version: '0.1.34' app.version: '0.1.38'

View File

@@ -210,7 +210,7 @@ Le `requestId` est set en `kernel.request` mais jamais cleared. En deploiement F
**Fichiers** : `config/packages/framework.yaml`, `src/Module/Core/Infrastructure/Audit/AuditLogWriter.php:69` **Fichiers** : `config/packages/framework.yaml`, `src/Module/Core/Infrastructure/Audit/AuditLogWriter.php:69`
Aucune entree `trusted_proxies` ni env `TRUSTED_PROXIES`. Coltura tourne derriere `nginx-coltura``php-coltura-fpm`. `Request::getClientIp()` retourne donc systematiquement l'IP **du conteneur nginx** (reseau Docker interne), pas l'IP reelle du client. Toute la valeur forensique de `ip_address` est nulle en prod. Aucune entree `trusted_proxies` ni env `TRUSTED_PROXIES`. Starseed tourne derriere `nginx-starseed``php-starseed-fpm`. `Request::getClientIp()` retourne donc systematiquement l'IP **du conteneur nginx** (reseau Docker interne), pas l'IP reelle du client. Toute la valeur forensique de `ip_address` est nulle en prod.
Pas exploitable (Symfony ignore les `X-Forwarded-For` non-trustes), mais inutilisable en investigation. Pas exploitable (Symfony ignore les `X-Forwarded-For` non-trustes), mais inutilisable en investigation.

View File

@@ -1,4 +1,4 @@
# Deploiement Docker — Coltura # Deploiement Docker — Starseed
## Pre-requis ## Pre-requis
@@ -29,9 +29,9 @@ sudo systemctl start nginx
### PostgreSQL ### PostgreSQL
PostgreSQL tourne dans un conteneur Docker separe (voir le repo `infra-postgres`). PostgreSQL tourne dans un conteneur Docker separe (voir le repo `infra-postgres`).
Il doit etre installe et accessible avant de deployer Coltura. Il doit etre installe et accessible avant de deployer Starseed.
Creer la base de donnees pour Coltura : Creer la base de donnees pour Starseed :
```bash ```bash
cd /var/www/postgres cd /var/www/postgres
@@ -43,7 +43,7 @@ docker compose exec postgres psql -U admin
CREATE USER malio WITH PASSWORD 'motdepasse'; CREATE USER malio WITH PASSWORD 'motdepasse';
-- Creer la base -- Creer la base
CREATE DATABASE coltura_prod OWNER malio; CREATE DATABASE starseed_prod OWNER malio;
\q \q
``` ```
@@ -51,7 +51,7 @@ CREATE DATABASE coltura_prod OWNER malio;
## Premiere installation (nouvelle machine) ## Premiere installation (nouvelle machine)
Guide complet pour mettre en ligne Coltura sur une machine vierge. Inclut les pre-requis, la BDD et l'app. Guide complet pour mettre en ligne Starseed sur une machine vierge. Inclut les pre-requis, la BDD et l'app.
### 1. Installer les pre-requis ### 1. Installer les pre-requis
@@ -60,9 +60,9 @@ Installer Docker, Nginx et PostgreSQL (voir section Pre-requis ci-dessus).
### 2. Creer le dossier de deploiement ### 2. Creer le dossier de deploiement
```bash ```bash
sudo mkdir -p /var/www/coltura sudo mkdir -p /var/www/starseed
sudo chown -R $(whoami):$(whoami) /var/www/coltura sudo chown -R $(whoami):$(whoami) /var/www/starseed
cd /var/www/coltura cd /var/www/starseed
``` ```
### 3. Se connecter au registry Docker de Gitea ### 3. Se connecter au registry Docker de Gitea
@@ -83,8 +83,8 @@ Creer `docker-compose.yml` :
```yaml ```yaml
services: services:
app: app:
image: gitea.malio.fr/malio-dev/coltura:${COLTURA_IMAGE_TAG:-latest} image: gitea.malio.fr/malio-dev/starseed:${STARSEED_IMAGE_TAG:-latest}
container_name: coltura-app container_name: starseed-app
env_file: .env env_file: .env
ports: ports:
- "8083:80" - "8083:80"
@@ -105,9 +105,9 @@ set -euo pipefail
cd "$(dirname "$0")" cd "$(dirname "$0")"
TAG="${1:-latest}" TAG="${1:-latest}"
export COLTURA_IMAGE_TAG="$TAG" export STARSEED_IMAGE_TAG="$TAG"
echo "==> Deploying coltura:${TAG}..." echo "==> Deploying starseed:${TAG}..."
echo "==> Pulling image..." echo "==> Pulling image..."
docker compose pull docker compose pull
@@ -146,22 +146,22 @@ APP_DEBUG=0
APP_SECRET=<generer avec: openssl rand -hex 32> APP_SECRET=<generer avec: openssl rand -hex 32>
# Database (host.docker.internal = la machine hote, ou le PG tourne en Docker) # Database (host.docker.internal = la machine hote, ou le PG tourne en Docker)
DATABASE_URL="postgresql://malio:password@host.docker.internal:5432/coltura_prod?serverVersion=16&charset=utf8" DATABASE_URL="postgresql://malio:password@host.docker.internal:5432/starseed_prod?serverVersion=16&charset=utf8"
# JWT # JWT
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=<generer avec: openssl rand -hex 32> JWT_PASSPHRASE=<generer avec: openssl rand -hex 32>
JWT_COOKIE_SECURE=1 JWT_COOKIE_SECURE=0
JWT_COOKIE_SAMESITE=lax JWT_COOKIE_SAMESITE=lax
JWT_TOKEN_TTL=86400 JWT_TOKEN_TTL=86400
JWT_COOKIE_TTL=86400 JWT_COOKIE_TTL=86400
# CORS # CORS
CORS_ALLOW_ORIGIN='^https?://coltura\.malio-dev\.fr$' CORS_ALLOW_ORIGIN='^https?://starseed\.malio-dev\.fr$'
# App # App
DEFAULT_URI=https://coltura.malio-dev.fr DEFAULT_URI=http://starseed.malio-dev.fr
``` ```
### 6. Generer les cles JWT ### 6. Generer les cles JWT
@@ -190,17 +190,17 @@ mkdir -p uploads
Copier la config reverse proxy depuis le repo : Copier la config reverse proxy depuis le repo :
```bash ```bash
sudo cp infra/prod/nginx-proxy.conf /etc/nginx/sites-available/coltura.conf sudo cp infra/prod/nginx-proxy.conf /etc/nginx/sites-available/starseed.conf
``` ```
Ou creer `/etc/nginx/sites-available/coltura.conf` manuellement (voir `infra/prod/nginx-proxy.conf`). Ou creer `/etc/nginx/sites-available/starseed.conf` manuellement (voir `infra/prod/nginx-proxy.conf`).
La config inclut le **mode maintenance** : si le fichier `/var/www/coltura/maintenance.on` existe, Nginx renvoie une 503 avec `maintenance.html`. La config inclut le **mode maintenance** : si le fichier `/var/www/starseed/maintenance.on` existe, Nginx renvoie une 503 avec `maintenance.html`.
Activer le site : Activer le site :
```bash ```bash
sudo ln -sf /etc/nginx/sites-available/coltura.conf /etc/nginx/sites-enabled/coltura.conf sudo ln -sf /etc/nginx/sites-available/starseed.conf /etc/nginx/sites-enabled/starseed.conf
sudo nginx -t && sudo systemctl reload nginx sudo nginx -t && sudo systemctl reload nginx
``` ```
@@ -208,13 +208,13 @@ sudo nginx -t && sudo systemctl reload nginx
```bash ```bash
# Activer la maintenance # Activer la maintenance
touch /var/www/coltura/maintenance.on touch /var/www/starseed/maintenance.on
# Desactiver la maintenance # Desactiver la maintenance
rm /var/www/coltura/maintenance.on rm /var/www/starseed/maintenance.on
``` ```
Optionnel : creer une page `/var/www/coltura/public/maintenance.html` personnalisee. Optionnel : creer une page `/var/www/starseed/public/maintenance.html` personnalisee.
### 9. Deployer ### 9. Deployer
@@ -232,7 +232,7 @@ Choisir `App\Entity\User`, taper le mdp, copier le hash. Puis :
```bash ```bash
cd /var/www/postgres cd /var/www/postgres
docker compose exec -T postgres psql -U malio coltura_prod -c "INSERT INTO \"user\" (username, roles, password, created_at) VALUES ('admin', '[\"ROLE_ADMIN\"]', '<le-hash>', NOW());" docker compose exec -T postgres psql -U malio starseed_prod -c "INSERT INTO \"user\" (username, roles, password, created_at) VALUES ('admin', '[\"ROLE_ADMIN\"]', '<le-hash>', NOW());"
``` ```
Ou charger les fixtures (dev uniquement) : Ou charger les fixtures (dev uniquement) :
@@ -244,7 +244,7 @@ docker compose exec -T -u www-data app php bin/console doctrine:fixtures:load --
### Structure finale du dossier ### Structure finale du dossier
``` ```
/var/www/coltura/ /var/www/starseed/
├── docker-compose.yml ├── docker-compose.yml
├── deploy.sh ├── deploy.sh
├── .env ├── .env
@@ -261,7 +261,7 @@ docker compose exec -T -u www-data app php bin/console doctrine:fixtures:load --
Quand l'app est deja installee, deployer une mise a jour : Quand l'app est deja installee, deployer une mise a jour :
```bash ```bash
cd /var/www/coltura cd /var/www/starseed
./deploy.sh # deploie la derniere version (latest) ./deploy.sh # deploie la derniere version (latest)
./deploy.sh v0.2.0 # deploie une version specifique ./deploy.sh v0.2.0 # deploie une version specifique
``` ```
@@ -293,7 +293,7 @@ docker compose exec -T -u www-data app php bin/console doctrine:migrations:migra
Le workflow `.gitea/workflows/build-docker.yml` se declenche automatiquement sur push de tag `v*` : Le workflow `.gitea/workflows/build-docker.yml` se declenche automatiquement sur push de tag `v*` :
1. Build l'image multi-stage 1. Build l'image multi-stage
2. Push vers `gitea.malio.fr/malio-dev/coltura:<tag>` et `:latest` 2. Push vers `gitea.malio.fr/malio-dev/starseed:<tag>` et `:latest`
Combine avec `auto-tag-develop.yml`, chaque push sur `develop` cree automatiquement un tag → build → image disponible. Combine avec `auto-tag-develop.yml`, chaque push sur `develop` cree automatiquement un tag → build → image disponible.
@@ -302,7 +302,7 @@ Combine avec `auto-tag-develop.yml`, chaque push sur `develop` cree automatiquem
## Voir les logs ## Voir les logs
```bash ```bash
cd /var/www/coltura cd /var/www/starseed
docker compose logs -f # tous les logs docker compose logs -f # tous les logs
docker compose logs -f --tail=100 # 100 dernieres lignes docker compose logs -f --tail=100 # 100 dernieres lignes
``` ```

231
doc/prompt-rename-prod.md Normal file
View File

@@ -0,0 +1,231 @@
# Prompt — Migration prod Coltura -> Starseed
Copier-coller integralement dans une session Claude lancee **sur le serveur de prod** apres que :
- le push develop + build CI ont publie l'image `gitea.malio.fr/malio-dev/starseed:latest`,
- la resolution reseau local (DNS interne ou `/etc/hosts` des postes clients) pour `starseed.malio-dev.fr` est en place.
> Setup : HTTP en reseau local, pas de TLS. Pas de Let's Encrypt.
---
## Prompt a fournir au Claude prod
Tu es sur le serveur de production d'une app Symfony+Nuxt qui s'appelait **Coltura** et qui doit etre renommee en **Starseed**. Le rename cote code est deja fait et merge. Le repo Gitea s'appelle deja `starseed`. L'image `gitea.malio.fr/malio-dev/starseed:latest` est publiee.
L'app est servie en **HTTP sur reseau local** (pas de TLS, pas de Let's Encrypt). La resolution `starseed.malio-dev.fr` est faite via DNS interne ou `/etc/hosts` cote postes clients — pas de certificat a gerer.
Objectif : basculer la prod sur le nouveau nom (registry, container, DB, path FS, vhost) **sans perdre les donnees** et avec downtime minimal (mode maintenance pendant la migration).
**Etat actuel a verifier en premier** (donne-moi le retour de chaque commande avant de continuer) :
```bash
# 1. Container actuel + image
sudo docker ps --filter name=coltura-app --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
# 2. DB existante
sudo -u postgres psql -c "\l" | grep -E "coltura|starseed"
# 3. Path FS app
ls -la /var/www/coltura/ 2>/dev/null | head -5
ls -la /var/www/starseed/ 2>/dev/null | head -5
# 4. Vhost nginx system
sudo ls -la /etc/nginx/sites-enabled/ | grep -E "coltura|starseed"
```
**Apres confirmation de l'etat, executer dans cet ordre, en demandant validation utilisateur AVANT chaque etape destructive (DB drop, rm -rf, certificat) :**
### Etape 1 — Mode maintenance
```bash
cd /var/www/coltura
touch maintenance.on
# Verifier qu'une requete renvoie 503
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://coltura.malio-dev.fr/
```
Doit renvoyer `503`.
### Etape 2 — Backup DB (CRITIQUE — ne pas skipper)
```bash
BACKUP_FILE="/root/coltura_prod_backup_$(date +%Y%m%d_%H%M%S).sql"
sudo -u postgres pg_dump -F c -f "$BACKUP_FILE" coltura_prod
ls -lh "$BACKUP_FILE"
```
**Stocker ce chemin** — il sera utilise pour le rollback.
### Etape 3 — Creer la DB cible et migrer
Recuperer l'owner et le user de connexion actuels :
```bash
sudo -u postgres psql -c "\l coltura_prod"
grep DATABASE_URL /var/www/coltura/.env
```
Puis (adapter l'owner si different de `malio`) :
```bash
sudo -u postgres psql <<'SQL'
CREATE DATABASE starseed_prod OWNER malio;
SQL
sudo -u postgres pg_dump coltura_prod | sudo -u postgres psql starseed_prod
sudo -u postgres psql starseed_prod -c "\dt" | head -20
```
Verifier que les tables sont bien copiees. Si le user PG s'appelle `coltura`, le renommer ou en creer un `starseed` est OPTIONNEL — la connexion peut continuer avec `coltura` tant que `GRANT` est OK. **Confirmer avec l'utilisateur** s'il veut renommer le role PG :
```bash
# Optionnel : renommer le role PG (si user de connexion s'appelle 'coltura')
# sudo -u postgres psql -c "ALTER ROLE coltura RENAME TO starseed;"
```
### Etape 4 — Renommer le path FS
```bash
sudo mv /var/www/coltura /var/www/starseed
# Verifier le contenu
sudo ls -la /var/www/starseed/ | head -10
# Verifier que .env existe encore
sudo test -f /var/www/starseed/.env && echo ".env OK"
```
### Etape 5 — Mettre a jour .env de prod
Editer `/var/www/starseed/.env` :
- `DATABASE_URL` : remplacer `/coltura_prod` -> `/starseed_prod` (et user si renomme a etape 3)
- `CORS_ALLOW_ORIGIN` : remplacer `coltura.malio-dev.fr` -> `starseed.malio-dev.fr`
- `DEFAULT_URI` : `http://starseed.malio-dev.fr`
- `JWT_COOKIE_SECURE` : doit etre `0` (HTTP, pas de TLS) — verifier qu'il l'est deja
Diff attendu :
```diff
- DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/coltura_prod?..."
+ DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/starseed_prod?..."
- CORS_ALLOW_ORIGIN='^http://coltura\.malio-dev\.fr$'
+ CORS_ALLOW_ORIGIN='^http://starseed\.malio-dev\.fr$'
- DEFAULT_URI=http://coltura.malio-dev.fr
+ DEFAULT_URI=http://starseed.malio-dev.fr
```
### Etape 6 — Stopper et supprimer l'ancien container
```bash
cd /var/www/starseed
sudo docker compose down
# Verifier qu'il n'y a plus de coltura-app
sudo docker ps -a --filter name=coltura
```
### Etape 7 — Pull la nouvelle image et demarrer
Le `docker-compose.prod.yml` du dossier deja a jour pointe sur `gitea.malio.fr/malio-dev/starseed:latest` et `container_name: starseed-app`.
```bash
cd /var/www/starseed
sudo docker compose pull
sudo docker compose up -d
sleep 5
sudo docker ps --filter name=starseed-app
sudo docker logs starseed-app --tail 30
```
### Etape 8 — Migrations Doctrine + cache
```bash
cd /var/www/starseed
sudo docker compose exec -T -u www-data app php bin/console doctrine:migrations:migrate --no-interaction
sudo docker compose exec -T -u www-data app php bin/console cache:clear --env=prod
sudo docker compose exec -T -u www-data app php bin/console cache:warmup --env=prod
```
### Etape 9 — Vhost nginx system (HTTP only)
Copier le nouveau vhost (a jour avec `server_name starseed.malio-dev.fr` et `root /var/www/starseed/public`, `listen 80` uniquement) :
```bash
sudo cp /var/www/starseed/infra/prod/nginx-proxy.conf /etc/nginx/sites-available/starseed.conf
sudo ln -sf /etc/nginx/sites-available/starseed.conf /etc/nginx/sites-enabled/starseed.conf
sudo rm -f /etc/nginx/sites-enabled/coltura.conf
sudo nginx -t
```
Verifier la resolution reseau local avant reload :
```bash
getent hosts starseed.malio-dev.fr || echo "ATTENTION : starseed.malio-dev.fr ne resout pas localement"
```
Puis :
```bash
sudo systemctl reload nginx
```
### Etape 10 — Desactiver le mode maintenance et tester
```bash
rm -f /var/www/starseed/maintenance.on
# Tests externes (HTTP local)
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://starseed.malio-dev.fr/
curl -s http://starseed.malio-dev.fr/api/version
```
`/api/version` doit renvoyer du JSON avec la version courante.
### Etape 11 — Cleanup (apres 24-48h de stabilite)
A faire **plus tard**, seulement quand on est sur que tout marche :
```bash
# Backup deja conserve en /root/coltura_prod_backup_*.sql.
# Apres validation utilisateur :
sudo -u postgres psql -c "DROP DATABASE coltura_prod;"
sudo rm -f /etc/nginx/sites-available/coltura.conf
sudo docker image prune # nettoie les vieilles images coltura
```
---
## Rollback (si echec apres etape 5)
```bash
# 1. Remettre maintenance
touch /var/www/starseed/maintenance.on 2>/dev/null || touch /var/www/coltura/maintenance.on
# 2. Restaurer le path FS
sudo mv /var/www/starseed /var/www/coltura 2>/dev/null || true
# 3. Restaurer le vhost coltura
sudo rm -f /etc/nginx/sites-enabled/starseed.conf
sudo ln -sf /etc/nginx/sites-available/coltura.conf /etc/nginx/sites-enabled/coltura.conf
sudo systemctl reload nginx
# 4. Redemarrer l'ancien container (l'image coltura est encore dans le registry)
cd /var/www/coltura
# Editer docker-compose.prod.yml pour pointer sur coltura:latest si necessaire
sudo docker compose up -d
# 5. Si la DB starseed_prod a ete modifiee, restaurer depuis le backup
sudo -u postgres psql -c "DROP DATABASE IF EXISTS coltura_prod;"
sudo -u postgres pg_restore -C -d postgres "$BACKUP_FILE"
# 6. Lever maintenance
rm -f /var/www/coltura/maintenance.on
```
---
## Regles de comportement pour le Claude prod
- **Ne jamais skipper le backup** (etape 2).
- **Demander confirmation utilisateur** avant : `DROP DATABASE`, `rm -rf`, et avant de lever le mode maintenance final.
- **Une seule operation destructive a la fois**, attendre le retour utilisateur entre chaque.
- **Logger systematiquement** la sortie des commandes critiques (pg_dump, docker compose up, nginx -t / reload).
- **Si une etape echoue**, NE PAS continuer — declencher le rollback.
- **Ne commit rien** sur le repo depuis le serveur prod.

View File

@@ -9,7 +9,7 @@
## Résumé de la PR ## Résumé de la PR
Cette PR restructure Coltura (CRM/ERP) en **architecture modulaire DDD** (Domain-Driven Design) : Cette PR restructure Starseed (CRM/ERP) en **architecture modulaire DDD** (Domain-Driven Design) :
- **Backend** : introduction de bounded contexts (`Module/Core`, `Module/Commercial`) avec séparation Domain / Application / Infrastructure - **Backend** : introduction de bounded contexts (`Module/Core`, `Module/Commercial`) avec séparation Domain / Application / Infrastructure
- **Shared** : couche partagée (events, value objects, contracts, bus interfaces) - **Shared** : couche partagée (events, value objects, contracts, bus interfaces)
@@ -36,9 +36,9 @@ Cette PR restructure Coltura (CRM/ERP) en **architecture modulaire DDD** (Domain
Liste des évolutions du projet Ferme Liste des évolutions du projet Ferme
``` ```
Ce fichier appartient à **Coltura**, pas au projet Ferme. C'est une erreur de copier-coller lors du scaffolding initial. Ce fichier appartient à **Starseed**, pas au projet Ferme. C'est une erreur de copier-coller lors du scaffolding initial.
**Correction** : Remplacer "Ferme" par "Coltura". **Correction** : Remplacer "Ferme" par "Starseed".
--- ---
@@ -76,10 +76,10 @@ Mais la seule page du module commercial est `frontend/modules/commercial/pages/c
|---|---| |---|---|
| **Sévérité** | Majeure | | **Sévérité** | Majeure |
| **Fichier** | `infra/dev/.env.docker` | | **Fichier** | `infra/dev/.env.docker` |
| **Règle violée** | Workspace `CLAUDE.md` : "Coltura — 8083 / 3003 / **5436**" | | **Règle violée** | Workspace `CLAUDE.md` : "Starseed — 8083 / 3003 / **5436**" |
| **Confiance** | 75/100 | | **Confiance** | 75/100 |
**Constat** : Le fichier `.env.docker` définit `POSTGRES_PORT=5437`, alors que le port documenté pour Coltura est `5436`. **Constat** : Le fichier `.env.docker` définit `POSTGRES_PORT=5437`, alors que le port documenté pour Starseed est `5436`.
**Impact** : Tout développeur qui suit les ports documentés (ou qui utilise des scripts basés sur ces ports) ne pourra pas se connecter à la base. **Impact** : Tout développeur qui suit les ports documentés (ou qui utilise des scripts basés sur ces ports) ne pourra pas se connecter à la base.
@@ -93,7 +93,7 @@ Mais la seule page du module commercial est `frontend/modules/commercial/pages/c
|---|---| |---|---|
| **Sévérité** | Majeure | | **Sévérité** | Majeure |
| **Fichiers** | `frontend/nuxt.config.ts` (ligne 40), `docker-compose.yml` (ligne 33) | | **Fichiers** | `frontend/nuxt.config.ts` (ligne 40), `docker-compose.yml` (ligne 33) |
| **Règle violée** | Workspace `CLAUDE.md` : "Coltura — 8083 / **3003** / 5436" et `CLAUDE.md` projet : "make dev-nuxt # port 3003" | | **Règle violée** | Workspace `CLAUDE.md` : "Starseed — 8083 / **3003** / 5436" et `CLAUDE.md` projet : "make dev-nuxt # port 3003" |
| **Confiance** | 75/100 (confirmé par 3 agents indépendants) | | **Confiance** | 75/100 (confirmé par 3 agents indépendants) |
**Constat** : **Constat** :

View File

@@ -41,7 +41,7 @@ services:
- "8083:80" - "8083:80"
volumes: volumes:
- ./:/var/www/html:ro - ./:/var/www/html:ro
- ./infra/dev/nginx.conf:/etc/nginx/conf.d/coltura.conf:ro - ./infra/dev/nginx.conf:/etc/nginx/conf.d/default.conf:ro
restart: unless-stopped restart: unless-stopped
db: db:
image: postgres:16-alpine image: postgres:16-alpine

View File

@@ -13,7 +13,7 @@ Ce ticket livre la base RBAC backend de l'epic en 5 tickets en remplacant le sto
- Faire evoluer `User` avec une relation ManyToMany vers `Role`, une relation ManyToMany vers `Permission` pour les permissions directes et un booleen `is_admin`. - Faire evoluer `User` avec une relation ManyToMany vers `Role`, une relation ManyToMany vers `Permission` pour les permissions directes et un booleen `is_admin`.
- Faire evoluer `User::getRoles()` pour rester compatible Symfony en retournant toujours `ROLE_USER` et `ROLE_ADMIN` si `is_admin = true`. - Faire evoluer `User::getRoles()` pour rester compatible Symfony en retournant toujours `ROLE_USER` et `ROLE_ADMIN` si `is_admin = true`.
- Ajouter `User::getEffectivePermissions()` pour retourner l'union des codes de permissions provenant des roles et des permissions directes. - Ajouter `User::getEffectivePermissions()` pour retourner l'union des codes de permissions provenant des roles et des permissions directes.
- Ajouter une methode statique `permissions()` sur `/home/matthieu/dev_malio/Coltura/src/Module/Core/CoreModule.php` et definir le pattern a reproduire pour les autres modules. - Ajouter une methode statique `permissions()` sur `/home/matthieu/dev_malio/Starseed/src/Module/Core/CoreModule.php` et definir le pattern a reproduire pour les autres modules.
- Ajouter une commande console `app:sync-permissions` transactionnelle, idempotente et non destructive avec gestion `orphan`. - Ajouter une commande console `app:sync-permissions` transactionnelle, idempotente et non destructive avec gestion `orphan`.
- Ajouter une migration Doctrine modulaire Core qui cree les tables RBAC, migre les donnees depuis `user.roles`, cree les roles systeme `admin` et `user`, puis supprime la colonne JSON `roles`. - Ajouter une migration Doctrine modulaire Core qui cree les tables RBAC, migre les donnees depuis `user.roles`, cree les roles systeme `admin` et `user`, puis supprime la colonne JSON `roles`.
- Mettre a jour les fixtures Core pour creer les roles systeme et rattacher l'utilisateur admin au role `admin`. - Mettre a jour les fixtures Core pour creer les roles systeme et rattacher l'utilisateur admin au role `admin`.
@@ -31,30 +31,30 @@ Ce ticket livre la base RBAC backend de l'epic en 5 tickets en remplacant le sto
### Domaine - Entités ### Domaine - Entités
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Permission.php` : entite Doctrine de permission RBAC, code unique, module source et etat `orphan`. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Permission.php` : entite Doctrine de permission RBAC, code unique, module source et etat `orphan`.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Role.php` : entite Doctrine de role RBAC avec relations vers permissions et garde de role systeme. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Role.php` : entite Doctrine de role RBAC avec relations vers permissions et garde de role systeme.
### Domaine - Repositories ### Domaine - Repositories
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php` : contrat de lecture/ecriture des permissions pour la commande de sync et les fixtures. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Repository/PermissionRepositoryInterface.php` : contrat de lecture/ecriture des permissions pour la commande de sync et les fixtures.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Repository/RoleRepositoryInterface.php` : contrat de lecture/ecriture des roles pour migration fonctionnelle, fixtures et usages futurs. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Repository/RoleRepositoryInterface.php` : contrat de lecture/ecriture des roles pour migration fonctionnelle, fixtures et usages futurs.
### Domaine - Exceptions ### Domaine - Exceptions
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Exception/SystemRoleDeletionException.php` : exception domaine levee si une suppression vise un role systeme. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Exception/SystemRoleDeletionException.php` : exception domaine levee si une suppression vise un role systeme.
### Infrastructure - Doctrine ### Infrastructure - Doctrine
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php` : implementation Doctrine de `PermissionRepositoryInterface`. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/DoctrinePermissionRepository.php` : implementation Doctrine de `PermissionRepositoryInterface`.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php` : implementation Doctrine de `RoleRepositoryInterface`. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/DoctrineRoleRepository.php` : implementation Doctrine de `RoleRepositoryInterface`.
### Infrastructure - Doctrine Migrations ### Infrastructure - Doctrine Migrations
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` : migration modulaire RBAC Core avec schema + migration de donnees + rollback minimal. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` : migration modulaire RBAC Core avec schema + migration de donnees + rollback minimal.
### Infrastructure - Console ### Infrastructure - Console
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php` : commande `app:sync-permissions` qui scanne les modules actifs et synchronise la table `permission`. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php` : commande `app:sync-permissions` qui scanne les modules actifs et synchronise la table `permission`.
### Infrastructure - DataFixtures ### Infrastructure - DataFixtures
@@ -62,12 +62,12 @@ Ce ticket livre la base RBAC backend de l'epic en 5 tickets en remplacant le sto
### Constantes domaine ### Constantes domaine
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Security/SystemRoles.php` : constantes partagees `ADMIN_CODE = 'admin'` et `USER_CODE = 'user'`, utilisees a la fois par les fixtures et par la migration SQL. Place dans `Domain/Security/` (pas `ValueObject/` : ce n'est pas un VO, c'est un conteneur de constantes metier laissant de la place pour d'autres constantes de securite plus tard). - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Security/SystemRoles.php` : constantes partagees `ADMIN_CODE = 'admin'` et `USER_CODE = 'user'`, utilisees a la fois par les fixtures et par la migration SQL. Place dans `Domain/Security/` (pas `ValueObject/` : ce n'est pas un VO, c'est un conteneur de constantes metier laissant de la place pour d'autres constantes de securite plus tard).
## 4. Fichiers à modifier ## 4. Fichiers à modifier
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/User.php` : supprimer le stockage JSON `roles`, ajouter `isAdmin`, `roles`, `directPermissions`, initialiser les collections, configurer les relations ManyToMany en `fetch=EAGER`, ajouter `getEffectivePermissions()` et adapter `getRoles()` / mutateurs. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/User.php` : supprimer le stockage JSON `roles`, ajouter `isAdmin`, `roles`, `directPermissions`, initialiser les collections, configurer les relations ManyToMany en `fetch=EAGER`, ajouter `getEffectivePermissions()` et adapter `getRoles()` / mutateurs.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/CoreModule.php` : ajouter une methode statique `public static function permissions(): array` qui declare les permissions natives du module Core et sert de reference pour les autres modules. Contenu initial exact : - `/home/matthieu/dev_malio/Starseed/src/Module/Core/CoreModule.php` : ajouter une methode statique `public static function permissions(): array` qui declare les permissions natives du module Core et sert de reference pour les autres modules. Contenu initial exact :
```php ```php
public static function permissions(): array public static function permissions(): array
{ {
@@ -80,17 +80,17 @@ Ce ticket livre la base RBAC backend de l'epic en 5 tickets en remplacant le sto
} }
``` ```
La cle `module` n'est PAS presente dans le payload : elle est auto-injectee par la commande de sync a partir de `CoreModule::ID`. Le code de permission doit obligatoirement commencer par `self::ID . '.'` sous peine d'echec de la sync (garde anti-typo). La cle `module` n'est PAS presente dans le payload : elle est auto-injectee par la commande de sync a partir de `CoreModule::ID`. Le code de permission doit obligatoirement commencer par `self::ID . '.'` sous peine d'echec de la sync (garde anti-typo).
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/DoctrineUserRepository.php` : aucun changement attendu dans ce ticket. Les nouvelles relations `$roles`, `$directPermissions` sont chargees par Doctrine via leurs mappings `fetch=EAGER` declares sur l'entite. Si les tests d'integration revelent un lazy-load non voulu au refresh JWT ou a la desserialisation, ajouter une methode `findForSecurity(string $username): ?User` avec `leftJoin` + `addSelect` explicites sur `roles`, `roles.permissions`, `directPermissions`, et brancher le user provider dessus. A trancher par les tests, pas en prevention. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/DoctrineUserRepository.php` : aucun changement attendu dans ce ticket. Les nouvelles relations `$roles`, `$directPermissions` sont chargees par Doctrine via leurs mappings `fetch=EAGER` declares sur l'entite. Si les tests d'integration revelent un lazy-load non voulu au refresh JWT ou a la desserialisation, ajouter une methode `findForSecurity(string $username): ?User` avec `leftJoin` + `addSelect` explicites sur `roles`, `roles.permissions`, `directPermissions`, et brancher le user provider dessus. A trancher par les tests, pas en prevention.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Repository/UserRepositoryInterface.php` : aucun changement dans ce ticket. Ajout eventuel de `findForSecurity()` uniquement si le cas ci-dessus se materialise. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Repository/UserRepositoryInterface.php` : aucun changement dans ce ticket. Ajout eventuel de `findForSecurity()` uniquement si le cas ci-dessus se materialise.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` : remplacer l'usage de `setRoles(array)` par la creation des roles systeme, le rattachement des utilisateurs a ces roles et le positionnement de `is_admin`. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` : remplacer l'usage de `setRoles(array)` par la creation des roles systeme, le rattachement des utilisateurs a ces roles et le positionnement de `is_admin`.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Console/CreateUserCommand.php` : remplacer la gestion historique de `ROLE_ADMIN` par `setIsAdmin(true)` et rattachement au role systeme `admin` si l'option `--admin` est conservee. - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Console/CreateUserCommand.php` : remplacer la gestion historique de `ROLE_ADMIN` par `setIsAdmin(true)` et rattachement au role systeme `admin` si l'option `--admin` est conservee.
- `/home/matthieu/dev_malio/Coltura/config/services.yaml` : ajouter 2 alias repository, aligne sur le pattern existant pour `UserRepositoryInterface` : - `/home/matthieu/dev_malio/Starseed/config/services.yaml` : ajouter 2 alias repository, aligne sur le pattern existant pour `UserRepositoryInterface` :
```yaml ```yaml
App\Module\Core\Domain\Repository\RoleRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrineRoleRepository' App\Module\Core\Domain\Repository\RoleRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrineRoleRepository'
App\Module\Core\Domain\Repository\PermissionRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrinePermissionRepository' App\Module\Core\Domain\Repository\PermissionRepositoryInterface: '@App\Module\Core\Infrastructure\Doctrine\DoctrinePermissionRepository'
``` ```
La commande `SyncPermissionsCommand` est auto-configuree via `autoconfigure: true`, aucun binding manuel necessaire. La commande `SyncPermissionsCommand` est auto-configuree via `autoconfigure: true`, aucun binding manuel necessaire.
- `/home/matthieu/dev_malio/Coltura/config/modules.php` : aucun changement de contenu requis, mais la commande `app:sync-permissions` devra s'appuyer sur ce fichier comme source de verite des modules actifs. - `/home/matthieu/dev_malio/Starseed/config/modules.php` : aucun changement de contenu requis, mais la commande `app:sync-permissions` devra s'appuyer sur ce fichier comme source de verite des modules actifs.
## 5. Schéma cible — mappings Doctrine ## 5. Schéma cible — mappings Doctrine
@@ -209,7 +209,7 @@ Etat final attendu :
## 6. Plan de migration Doctrine ## 6. Plan de migration Doctrine
La migration doit etre implementée dans `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` et executer `up()` dans cet ordre. La migration doit etre implementée dans `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` et executer `up()` dans cet ordre.
**Workflow recommande** : **Workflow recommande** :
1. Ecrire d'abord les entites `Permission`, `Role` et la mutation de `User` (section 5). 1. Ecrire d'abord les entites `Permission`, `Role` et la mutation de `User` (section 5).
@@ -287,7 +287,7 @@ Cas couverts explicitement :
Le mapping Doctrine actuel (`array` PHP → default) peut avoir genere une colonne `JSON` OU `TEXT` selon la version de Symfony/Doctrine. Le cast `::jsonb` fonctionne directement sur `JSON`, mais pas sur `TEXT`. **Avant d'executer la migration en prod**, verifier avec : Le mapping Doctrine actuel (`array` PHP → default) peut avoir genere une colonne `JSON` OU `TEXT` selon la version de Symfony/Doctrine. Le cast `::jsonb` fonctionne directement sur `JSON`, mais pas sur `TEXT`. **Avant d'executer la migration en prod**, verifier avec :
```bash ```bash
docker exec -it db-coltura psql -U malio -d coltura -c '\d "user"' docker exec -it db-starseed psql -U malio -d starseed -c '\d "user"'
``` ```
- Si `roles | json` : le SQL ci-dessus fonctionne tel quel. - Si `roles | json` : le SQL ci-dessus fonctionne tel quel.
@@ -306,11 +306,11 @@ Le rollback ne restitue pas la granularite RBAC complete, ce qui est acceptable
## 7. Algorithme sync-permissions ## 7. Algorithme sync-permissions
La commande `app:sync-permissions` doit vivre dans `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php` et encapsuler toute l'operation dans une transaction Doctrine unique. La commande `app:sync-permissions` doit vivre dans `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php` et encapsuler toute l'operation dans une transaction Doctrine unique.
### Source de verite ### Source de verite
- Le scan des modules actifs vient de `/home/matthieu/dev_malio/Coltura/config/modules.php`. - Le scan des modules actifs vient de `/home/matthieu/dev_malio/Starseed/config/modules.php`.
- Chaque classe module active peut exposer `public static function permissions(): array`. - Chaque classe module active peut exposer `public static function permissions(): array`.
- Par compatibilite montante, si une classe module n'expose pas encore `permissions()`, elle est traitee comme retournant `[]`. - Par compatibilite montante, si une classe module n'expose pas encore `permissions()`, elle est traitee comme retournant `[]`.
@@ -330,7 +330,7 @@ Garde anti-typo : le sync command verifie que chaque `code` commence obligatoire
```text ```text
begin transaction begin transaction
load active module classes from /home/matthieu/dev_malio/Coltura/config/modules.php load active module classes from /home/matthieu/dev_malio/Starseed/config/modules.php
desired_permissions = empty map keyed by code desired_permissions = empty map keyed by code
for each module class: for each module class:
@@ -439,7 +439,7 @@ Repasse `orphan` a `false` et remet a jour les metadonnees issues de la declarat
## 9. Fixtures mises à jour ## 9. Fixtures mises à jour
Le fichier cible reste `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php`. Le fichier cible reste `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php`.
### Principe cle : decouplage via `is_admin` ### Principe cle : decouplage via `is_admin`
@@ -519,7 +519,7 @@ Les tests d'integration migration up/down exigent une base de test dediee avec u
- Risque de perte de donnees pendant la suppression de la colonne `user.roles`. - Risque de perte de donnees pendant la suppression de la colonne `user.roles`.
- Mitigation : creer les roles systeme et inserer les jointures `user_role` avant tout `DROP COLUMN`, avec tests de migration sur etats mixtes. - Mitigation : creer les roles systeme et inserer les jointures `user_role` avant tout `DROP COLUMN`, avec tests de migration sur etats mixtes.
- Risque de divergence entre migration SQL brute et fixtures sur les codes des roles systeme. - Risque de divergence entre migration SQL brute et fixtures sur les codes des roles systeme.
- Mitigation : centraliser `admin` et `user` dans `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Security/SystemRoles.php` et documenter que la migration doit reprendre ces valeurs telles quelles. - Mitigation : centraliser `admin` et `user` dans `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Security/SystemRoles.php` et documenter que la migration doit reprendre ces valeurs telles quelles.
- Risque d'accumulation de permissions orphelines sur des environnements de dev ou apres refactors de codes. - Risque d'accumulation de permissions orphelines sur des environnements de dev ou apres refactors de codes.
- Mitigation : conserver `orphan = true` pour la non-destruction, mais ajouter un suivi explicite dans les tests et dans la documentation d'exploitation; une strategie de purge pourra etre traitee plus tard si necessaire. - Mitigation : conserver `orphan = true` pour la non-destruction, mais ajouter un suivi explicite dans les tests et dans la documentation d'exploitation; une strategie de purge pourra etre traitee plus tard si necessaire.
- Risque de sync incoherente entre dev et prod si un module actif ne declare pas encore `permissions()`. - Risque de sync incoherente entre dev et prod si un module actif ne declare pas encore `permissions()`.
@@ -533,12 +533,12 @@ Les tests d'integration migration up/down exigent une base de test dediee avec u
1. Creer `Permission`, `Role`, `SystemRoleDeletionException` et `SystemRoles`. 1. Creer `Permission`, `Role`, `SystemRoleDeletionException` et `SystemRoles`.
2. Creer `PermissionRepositoryInterface`, `RoleRepositoryInterface` et leurs implementations Doctrine. 2. Creer `PermissionRepositoryInterface`, `RoleRepositoryInterface` et leurs implementations Doctrine.
3. Faire evoluer `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/User.php` avec `is_admin`, `roles`, `directPermissions`, `getRoles()` et `getEffectivePermissions()`. 3. Faire evoluer `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/User.php` avec `is_admin`, `roles`, `directPermissions`, `getRoles()` et `getEffectivePermissions()`.
4. Ajouter `CoreModule::permissions()` et documenter le pattern de declaration statique pour les autres modules. 4. Ajouter `CoreModule::permissions()` et documenter le pattern de declaration statique pour les autres modules.
5. Ajouter la commande `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php`. 5. Ajouter la commande `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Console/SyncPermissionsCommand.php`.
6. Ecrire la migration `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` avec schema + migration de donnees + down(). 6. Ecrire la migration `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/Migrations/Version<timestamp>.php` avec schema + migration de donnees + down().
7. Mettre a jour `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` et `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Console/CreateUserCommand.php`. 7. Mettre a jour `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` et `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Console/CreateUserCommand.php`.
8. Ajouter les alias repository dans `/home/matthieu/dev_malio/Coltura/config/services.yaml`. 8. Ajouter les alias repository dans `/home/matthieu/dev_malio/Starseed/config/services.yaml`.
9. Ecrire les tests unitaires et d'integration couvrant domaine, sync, fixtures et migration. 9. Ecrire les tests unitaires et d'integration couvrant domaine, sync, fixtures et migration.
## 13. Critères d'acceptation (DoD) ## 13. Critères d'acceptation (DoD)
@@ -553,4 +553,4 @@ Les tests d'integration migration up/down exigent une base de test dediee avec u
- La suppression d'un role systeme leve `SystemRoleDeletionException` au niveau domaine. - La suppression d'un role systeme leve `SystemRoleDeletionException` au niveau domaine.
- Les associations `User::$roles`, `User::$directPermissions` et `Role::$permissions` sont explicitement configurees en `fetch=EAGER` et ce point est verifie par tests. - Les associations `User::$roles`, `User::$directPermissions` et `Role::$permissions` sont explicitement configurees en `fetch=EAGER` et ce point est verifie par tests.
- Les fixtures attribuent `is_admin = true` + role `admin` a l'utilisateur `admin`, et le role `user` aux utilisateurs standards. - Les fixtures attribuent `is_admin = true` + role `admin` a l'utilisateur `admin`, et le role `user` aux utilisateurs standards.
- Le spec est compatible avec l'architecture modulaire actuelle basee sur `/home/matthieu/dev_malio/Coltura/config/modules.php` et n'introduit aucune resource API Platform ni voter dans ce ticket. - Le spec est compatible avec l'architecture modulaire actuelle basee sur `/home/matthieu/dev_malio/Starseed/config/modules.php` et n'introduit aucune resource API Platform ni voter dans ce ticket.

View File

@@ -38,28 +38,28 @@ Le ticket n'introduit **aucune logique d'autorisation metier** : toute la verifi
### Infrastructure - Processors ### Infrastructure - Processors
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/RoleProcessor.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/RoleProcessor.php`
Decorator de `ApiPlatform\Doctrine\Common\State\PersistProcessor` et `RemoveProcessor`. Charge de la garde `ensureDeletable()` et de la protection des champs immuables sur un role systeme. Decorator de `ApiPlatform\Doctrine\Common\State\PersistProcessor` et `RemoveProcessor`. Charge de la garde `ensureDeletable()` et de la protection des champs immuables sur un role systeme.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php`
Decorator de `PersistProcessor` specifique a l'operation `PATCH /api/users/{id}/rbac`. Persiste les mutations `isAdmin`, `roles`, `directPermissions` sans passer par `UserPasswordHasherProcessor`. Decorator de `PersistProcessor` specifique a l'operation `PATCH /api/users/{id}/rbac`. Persiste les mutations `isAdmin`, `roles`, `directPermissions` sans passer par `UserPasswordHasherProcessor`.
### Tests unitaires ### Tests unitaires
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/RoleProcessorTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/RoleProcessorTest.php`
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessorTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessorTest.php`
### Tests fonctionnels ### Tests fonctionnels
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Api/PermissionApiTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Api/PermissionApiTest.php`
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Api/RoleApiTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Api/RoleApiTest.php`
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Api/UserRbacApiTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Api/UserRbacApiTest.php`
## 4. Fichiers a modifier ## 4. Fichiers a modifier
### Entite `Permission` ### Entite `Permission`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Permission.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Permission.php`
- Ajouter l'attribut `#[ApiResource]` avec operations `GetCollection` + `Get` uniquement. - Ajouter l'attribut `#[ApiResource]` avec operations `GetCollection` + `Get` uniquement.
- Normalization context : groupe `permission:read` uniquement. - Normalization context : groupe `permission:read` uniquement.
@@ -89,7 +89,7 @@ Extrait attendu :
### Entite `Role` ### Entite `Role`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Role.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Role.php`
- Ajouter l'attribut `#[ApiResource]` avec operations `GetCollection`, `Get`, `Post`, `Patch`, `Delete`. - Ajouter l'attribut `#[ApiResource]` avec operations `GetCollection`, `Get`, `Post`, `Patch`, `Delete`.
- Normalization context : `role:read`. Denormalization context : `role:write`. - Normalization context : `role:read`. Denormalization context : `role:write`.
@@ -107,7 +107,7 @@ Extrait attendu :
### Entite `User` ### Entite `User`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/User.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/User.php`
- Ajouter dans la liste des operations `ApiResource` existantes une operation dediee : - Ajouter dans la liste des operations `ApiResource` existantes une operation dediee :

View File

@@ -39,50 +39,50 @@ A l'issue de ce ticket, l'application dispose d'un systeme d'autorisation applic
### Domaine - Securite ### Domaine - Securite
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Security/AdminHeadcountGuard.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Security/AdminHeadcountGuard.php`
Service domaine encapsulant l'invariant "au moins un admin reste apres l'operation". Depend uniquement de `UserRepositoryInterface::countAdmins()`. Aucune dependance infrastructure, testable en isolation. Service domaine encapsulant l'invariant "au moins un admin reste apres l'operation". Depend uniquement de `UserRepositoryInterface::countAdmins()`. Aucune dependance infrastructure, testable en isolation.
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Exception/LastAdminProtectionException.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Exception/LastAdminProtectionException.php`
Exception metier levee par le guard. Traduite en `BadRequestHttpException` (400) dans les processors. Exception metier levee par le guard. Traduite en `BadRequestHttpException` (400) dans les processors.
### Infrastructure - Security ### Infrastructure - Security
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Security/PermissionVoter.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Security/PermissionVoter.php`
Voter Symfony etendant `Symfony\Component\Security\Core\Authorization\Voter\Voter`. Decouvert automatiquement par `autoconfigure: true`. Voter Symfony etendant `Symfony\Component\Security\Core\Authorization\Voter\Voter`. Decouvert automatiquement par `autoconfigure: true`.
### Infrastructure - Processors ### Infrastructure - Processors
- `/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserProcessor.php` - `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserProcessor.php`
Decorateur de `RemoveProcessor` cible sur `DELETE /api/users/{id}`. Appelle `AdminHeadcountGuard` avant de deleguer. Meme pattern qu'`UserRbacProcessor`/`RoleProcessor` : `final class`, `#[Autowire]` sur l'inner, `LogicException` fail-fast si le type entrant n'est pas `User`. Decorateur de `RemoveProcessor` cible sur `DELETE /api/users/{id}`. Appelle `AdminHeadcountGuard` avant de deleguer. Meme pattern qu'`UserRbacProcessor`/`RoleProcessor` : `final class`, `#[Autowire]` sur l'inner, `LogicException` fail-fast si le type entrant n'est pas `User`.
### Frontend - Composable ### Frontend - Composable
- `/home/matthieu/dev_malio/Coltura/frontend/shared/composables/usePermissions.ts` - `/home/matthieu/dev_malio/Starseed/frontend/shared/composables/usePermissions.ts`
Composable stateless qui lit `useAuthStore().user`. Pas de fetch propre, pas de reset (le cycle de vie est porte par l'auth store). Composable stateless qui lit `useAuthStore().user`. Pas de fetch propre, pas de reset (le cycle de vie est porte par l'auth store).
### Tests unitaires PHP ### Tests unitaires PHP
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Infrastructure/Security/PermissionVoterTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Infrastructure/Security/PermissionVoterTest.php`
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Domain/Security/AdminHeadcountGuardTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Domain/Security/AdminHeadcountGuardTest.php`
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserProcessorTest.php` - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserProcessorTest.php`
### Tests fonctionnels PHP ### Tests fonctionnels PHP
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Api/MeApiTest.php` (si absent — sinon extension) - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Api/MeApiTest.php` (si absent — sinon extension)
Couvre l'enrichissement du payload `/api/me`. Couvre l'enrichissement du payload `/api/me`.
- `/home/matthieu/dev_malio/Coltura/tests/Module/Core/Api/UserApiTest.php` (si absent — sinon extension) - `/home/matthieu/dev_malio/Starseed/tests/Module/Core/Api/UserApiTest.php` (si absent — sinon extension)
Couvre la garde "dernier admin global" sur `DELETE /api/users/{id}`. Couvre la garde "dernier admin global" sur `DELETE /api/users/{id}`.
### Tests frontend ### Tests frontend
- `/home/matthieu/dev_malio/Coltura/frontend/shared/composables/__tests__/usePermissions.test.ts` - `/home/matthieu/dev_malio/Starseed/frontend/shared/composables/__tests__/usePermissions.test.ts`
Vitest. Emplacement a adapter si le projet Nuxt a une autre convention (colocalise avec un fichier `.spec.ts`, ou repertoire `tests/`). A verifier au debut de la task frontend. Vitest. Emplacement a adapter si le projet Nuxt a une autre convention (colocalise avec un fichier `.spec.ts`, ou repertoire `tests/`). A verifier au debut de la task frontend.
## 4. Fichiers a modifier ## 4. Fichiers a modifier
### `CoreModule.php` ### `CoreModule.php`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/CoreModule.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/CoreModule.php`
Ajouter une cinquieme entree au catalogue : Ajouter une cinquieme entree au catalogue :
@@ -103,7 +103,7 @@ La commande `app:sync-permissions` creera automatiquement `core.roles.view` a la
### Entite `Permission` ### Entite `Permission`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Permission.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Permission.php`
Remplacer les 2 gardes placeholder : Remplacer les 2 gardes placeholder :
@@ -122,7 +122,7 @@ Supprimer les commentaires `// TODO ticket #345`.
### Entite `Role` ### Entite `Role`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/Role.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/Role.php`
Remplacer les 5 gardes placeholder : Remplacer les 5 gardes placeholder :
@@ -136,7 +136,7 @@ Supprimer les commentaires `// TODO ticket #345`.
### Entite `User` ### Entite `User`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Entity/User.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Entity/User.php`
Remplacer les 6 gardes `ROLE_ADMIN` restantes : Remplacer les 6 gardes `ROLE_ADMIN` restantes :
@@ -172,7 +172,7 @@ Supprimer tous les commentaires `// TODO ticket #345` rencontres.
### `UserRepositoryInterface` ### `UserRepositoryInterface`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Domain/Repository/UserRepositoryInterface.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Domain/Repository/UserRepositoryInterface.php`
Ajouter la methode : Ajouter la methode :
@@ -187,7 +187,7 @@ public function countAdmins(): int;
### `DoctrineUserRepository` ### `DoctrineUserRepository`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/Doctrine/DoctrineUserRepository.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/Doctrine/DoctrineUserRepository.php`
Implementer `countAdmins()` via un `QueryBuilder` simple : Implementer `countAdmins()` via un `QueryBuilder` simple :
@@ -204,7 +204,7 @@ public function countAdmins(): int
### `UserRbacProcessor` ### `UserRbacProcessor`
`/home/matthieu/dev_malio/Coltura/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php` `/home/matthieu/dev_malio/Starseed/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php`
Ajouter la dependance `AdminHeadcountGuard` et l'invoquer **apres** la garde auto-suicide existante, **avant** de deleguer au persist processor. Supprimer le `TODO ticket #345` du docblock. Ajouter la dependance `AdminHeadcountGuard` et l'invoquer **apres** la garde auto-suicide existante, **avant** de deleguer au persist processor. Supprimer le `TODO ticket #345` du docblock.

View File

@@ -10,14 +10,14 @@ Le resultat attendu est un socle de persistance activable par tenant via `config
### IN ### IN
- Creer le module `/home/m-tristan/workspace/Coltura/src/Module/Sites/SitesModule.php` avec `ID = 'sites'`, `LABEL = 'Sites'`, `REQUIRED = false`, et une methode statique `permissions()` declarant les deux codes RBAC `sites.view` et `sites.manage`. - Creer le module `/home/m-tristan/workspace/Starseed/src/Module/Sites/SitesModule.php` avec `ID = 'sites'`, `LABEL = 'Sites'`, `REQUIRED = false`, et une methode statique `permissions()` declarant les deux codes RBAC `sites.view` et `sites.manage`.
- Creer l'entite Doctrine `Site` avec `id`, `name` (unique), `city`, `postalCode`, `color`, `fullAddress`, `createdAt`, `updatedAt` et les contraintes de validation applicatives associees (NotBlank, Length, Regex hex `#RRGGBB`, Regex CP FR `^\d{5}$`, UniqueEntity). - Creer l'entite Doctrine `Site` avec `id`, `name` (unique), `city`, `postalCode`, `color`, `fullAddress`, `createdAt`, `updatedAt` et les contraintes de validation applicatives associees (NotBlank, Length, Regex hex `#RRGGBB`, Regex CP FR `^\d{5}$`, UniqueEntity).
- Creer l'interface `SiteRepositoryInterface` et son implementation Doctrine `DoctrineSiteRepository`, avec un contrat CRUD complet (`findById`, `findByName`, `findAllOrderedByName`, `save`, `remove`) en anticipation du ticket 2. - Creer l'interface `SiteRepositoryInterface` et son implementation Doctrine `DoctrineSiteRepository`, avec un contrat CRUD complet (`findById`, `findByName`, `findAllOrderedByName`, `save`, `remove`) en anticipation du ticket 2.
- Creer une migration Doctrine creant la table `site` avec son index unique `uniq_site_name`. La migration est placee dans `/home/m-tristan/workspace/Coltura/migrations/` au namespace racine `DoctrineMigrations` conformement a l'exception documentee dans `CLAUDE.md` (bug de tri alphabetique des migrations multi-namespaces dans Doctrine Migrations 3.x). - Creer une migration Doctrine creant la table `site` avec son index unique `uniq_site_name`. La migration est placee dans `/home/m-tristan/workspace/Starseed/migrations/` au namespace racine `DoctrineMigrations` conformement a l'exception documentee dans `CLAUDE.md` (bug de tri alphabetique des migrations multi-namespaces dans Doctrine Migrations 3.x).
- Creer `SitesFixtures` creant trois sites de demonstration : `Chatellerault` (`#056CF2`), `Saint-Jean` (`#10B981`), `Pommevic` (`#F59E0B`). Fixtures idempotentes via lookup par nom lorsque le purger Doctrine est desactive. - Creer `SitesFixtures` creant trois sites de demonstration : `Chatellerault` (`#056CF2`), `Saint-Jean` (`#10B981`), `Pommevic` (`#F59E0B`). Fixtures idempotentes via lookup par nom lorsque le purger Doctrine est desactive.
- Enregistrer `SitesModule::class` dans `/home/m-tristan/workspace/Coltura/config/modules.php` pour l'activer par defaut. - Enregistrer `SitesModule::class` dans `/home/m-tristan/workspace/Starseed/config/modules.php` pour l'activer par defaut.
- Declarer le mapping Doctrine du module dans `/home/m-tristan/workspace/Coltura/config/packages/doctrine.yaml` (inconditionnel, le mapping reste charge meme si le module est retire de `modules.php`). - Declarer le mapping Doctrine du module dans `/home/m-tristan/workspace/Starseed/config/packages/doctrine.yaml` (inconditionnel, le mapping reste charge meme si le module est retire de `modules.php`).
- Enregistrer l'alias service `SiteRepositoryInterface → DoctrineSiteRepository` dans `/home/m-tristan/workspace/Coltura/config/services.yaml`. - Enregistrer l'alias service `SiteRepositoryInterface → DoctrineSiteRepository` dans `/home/m-tristan/workspace/Starseed/config/services.yaml`.
- Ajouter deux suites de tests PHPUnit : - Ajouter deux suites de tests PHPUnit :
- `SiteTest` (pure `TestCase`) pour le comportement de l'entite (constructeur, getters/setters, lifecycle `PreUpdate`). - `SiteTest` (pure `TestCase`) pour le comportement de l'entite (constructeur, getters/setters, lifecycle `PreUpdate`).
- `SiteValidationTest` (`KernelTestCase`) pour la validation complete : regex hex, regex CP FR, NotBlank, Length, UniqueEntity via Doctrine. - `SiteValidationTest` (`KernelTestCase`) pour la validation complete : regex hex, regex CP FR, NotBlank, Length, UniqueEntity via Doctrine.
@@ -25,7 +25,7 @@ Le resultat attendu est un socle de persistance activable par tenant via `config
### OUT ### OUT
- Ticket `#02` : relation `User ↔ Site` (FK ou ManyToMany selon decision UX), expose les sites de l'utilisateur courant via `/api/me` et propage l'autorisation au niveau des ressources decoupees par site. - Ticket `#02` : relation `User ↔ Site` (FK ou ManyToMany selon decision UX), expose les sites de l'utilisateur courant via `/api/me` et propage l'autorisation au niveau des ressources decoupees par site.
- Ticket `#03` : integration dans la navbar Coltura (selecteur de site actif, persistance du choix cote front, consommation du flux issu du ticket 2). - Ticket `#03` : integration dans la navbar Starseed (selecteur de site actif, persistance du choix cote front, consommation du flux issu du ticket 2).
- Ticket `#04` : ecran d'administration CRUD des sites (page admin/sites, DataTable, drawer creation/edition, modale suppression, API Platform `Site` resource avec voters RBAC). - Ticket `#04` : ecran d'administration CRUD des sites (page admin/sites, DataTable, drawer creation/edition, modale suppression, API Platform `Site` resource avec voters RBAC).
- Gestion des soft-deletes sur `Site` : non introduite dans ce ticket. - Gestion des soft-deletes sur `Site` : non introduite dans ce ticket.
- Rattachement historique ou audit trail des modifications : hors scope. - Rattachement historique ou audit trail des modifications : hors scope.
@@ -34,38 +34,38 @@ Le resultat attendu est un socle de persistance activable par tenant via `config
### Domaine — Entité ### Domaine — Entité
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Domain/Entity/Site.php` : entite Doctrine porteuse des attributs metier (nom unique, ville, code postal FR, couleur hex, adresse complete multi-ligne) et des timestamps auto-maintenus via lifecycle callbacks. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Domain/Entity/Site.php` : entite Doctrine porteuse des attributs metier (nom unique, ville, code postal FR, couleur hex, adresse complete multi-ligne) et des timestamps auto-maintenus via lifecycle callbacks.
### Domaine — Repository ### Domaine — Repository
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Domain/Repository/SiteRepositoryInterface.php` : contrat d'acces domaine a l'entite Site (CRUD applicatif ; l'acces API Platform du ticket 4 utilisera le provider Doctrine par defaut). - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Domain/Repository/SiteRepositoryInterface.php` : contrat d'acces domaine a l'entite Site (CRUD applicatif ; l'acces API Platform du ticket 4 utilisera le provider Doctrine par defaut).
### Infrastructure — Doctrine ### Infrastructure — Doctrine
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/Doctrine/DoctrineSiteRepository.php` : implementation Doctrine de `SiteRepositoryInterface` basee sur `ServiceEntityRepository`. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/Doctrine/DoctrineSiteRepository.php` : implementation Doctrine de `SiteRepositoryInterface` basee sur `ServiceEntityRepository`.
### Infrastructure — Migration ### Infrastructure — Migration
- `/home/m-tristan/workspace/Coltura/migrations/Version<timestamp>.php` : migration racine (namespace `DoctrineMigrations`) qui cree la table `site` et son index unique. Emplacement racine et non modulaire, cf. exception documentee dans `CLAUDE.md` (bug Doctrine 3.x sur le tri alphabetique des migrations multi-namespaces). - `/home/m-tristan/workspace/Starseed/migrations/Version<timestamp>.php` : migration racine (namespace `DoctrineMigrations`) qui cree la table `site` et son index unique. Emplacement racine et non modulaire, cf. exception documentee dans `CLAUDE.md` (bug Doctrine 3.x sur le tri alphabetique des migrations multi-namespaces).
### Infrastructure — DataFixtures ### Infrastructure — DataFixtures
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/DataFixtures/SitesFixtures.php` : fixture Doctrine seedant les 3 sites de demonstration. Ne declare pas de `DependentFixtureInterface` (aucune dependance a AppFixtures dans ce ticket). - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/DataFixtures/SitesFixtures.php` : fixture Doctrine seedant les 3 sites de demonstration. Ne declare pas de `DependentFixtureInterface` (aucune dependance a AppFixtures dans ce ticket).
### Module — Declaration ### Module — Declaration
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/SitesModule.php` : marker class du module avec `ID`, `LABEL`, `REQUIRED` et `permissions()`. Meme pattern que `CoreModule`. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/SitesModule.php` : marker class du module avec `ID`, `LABEL`, `REQUIRED` et `permissions()`. Meme pattern que `CoreModule`.
### Tests ### Tests
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Domain/Entity/SiteTest.php` : tests unitaires purs (`TestCase`) couvrant constructeur, getters, setters et lifecycle `PreUpdate`. - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Domain/Entity/SiteTest.php` : tests unitaires purs (`TestCase`) couvrant constructeur, getters, setters et lifecycle `PreUpdate`.
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Domain/Entity/SiteValidationTest.php` : tests de validation (`KernelTestCase`) couvrant regex hex, regex CP FR, NotBlank, Length sur tous les champs, et `UniqueEntity` via la DB de test. - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Domain/Entity/SiteValidationTest.php` : tests de validation (`KernelTestCase`) couvrant regex hex, regex CP FR, NotBlank, Length sur tous les champs, et `UniqueEntity` via la DB de test.
## 4. Fichiers à modifier ## 4. Fichiers à modifier
- `/home/m-tristan/workspace/Coltura/config/modules.php` : ajouter `App\Module\Sites\SitesModule::class` dans le tableau de retour. Le module est actif par defaut. Le commenter suffit a le desactiver sans autre intervention (les permissions deviendront orphelines a la prochaine sync mais la table reste). - `/home/m-tristan/workspace/Starseed/config/modules.php` : ajouter `App\Module\Sites\SitesModule::class` dans le tableau de retour. Le module est actif par defaut. Le commenter suffit a le desactiver sans autre intervention (les permissions deviendront orphelines a la prochaine sync mais la table reste).
- `/home/m-tristan/workspace/Coltura/config/packages/doctrine.yaml` : ajouter une mapping `Sites:` alignee sur le pattern du module `Core:`. Le mapping est inconditionnel : il reste declare meme si `SitesModule::class` est retire de `modules.php`. Le commentaire doit etre explicite sur cette decoupe (activation fonctionnelle via `modules.php`, structure DB via la mapping Doctrine). - `/home/m-tristan/workspace/Starseed/config/packages/doctrine.yaml` : ajouter une mapping `Sites:` alignee sur le pattern du module `Core:`. Le mapping est inconditionnel : il reste declare meme si `SitesModule::class` est retire de `modules.php`. Le commentaire doit etre explicite sur cette decoupe (activation fonctionnelle via `modules.php`, structure DB via la mapping Doctrine).
- `/home/m-tristan/workspace/Coltura/config/services.yaml` : ajouter l'alias `App\Module\Sites\Domain\Repository\SiteRepositoryInterface``App\Module\Sites\Infrastructure\Doctrine\DoctrineSiteRepository`. Pattern aligne sur les trois aliases Core existants. - `/home/m-tristan/workspace/Starseed/config/services.yaml` : ajouter l'alias `App\Module\Sites\Domain\Repository\SiteRepositoryInterface``App\Module\Sites\Infrastructure\Doctrine\DoctrineSiteRepository`. Pattern aligne sur les trois aliases Core existants.
## 5. Schéma cible — mapping Doctrine ## 5. Schéma cible — mapping Doctrine
@@ -152,7 +152,7 @@ Sites:
## 6. Plan de migration Doctrine ## 6. Plan de migration Doctrine
La migration est placee dans `/home/m-tristan/workspace/Coltura/migrations/Version<timestamp>.php` au namespace racine `DoctrineMigrations`, conformement a l'exception documentee dans `CLAUDE.md`. Tant que le bug de tri alphabetique des `MigrationsComparator` multi-namespaces n'est pas resolu (via un comparator custom ou un upgrade Doctrine), toute migration d'initialisation (creation de table sur base vide) reste au namespace racine. La migration est placee dans `/home/m-tristan/workspace/Starseed/migrations/Version<timestamp>.php` au namespace racine `DoctrineMigrations`, conformement a l'exception documentee dans `CLAUDE.md`. Tant que le bug de tri alphabetique des `MigrationsComparator` multi-namespaces n'est pas resolu (via un comparator custom ou un upgrade Doctrine), toute migration d'initialisation (creation de table sur base vide) reste au namespace racine.
### `up()` — ordre des instructions ### `up()` — ordre des instructions
@@ -289,7 +289,7 @@ Trois sites de demonstration, avec des couleurs distinctes suffisamment contrast
| Nom | Ville | CP | Couleur | Commentaire | | Nom | Ville | CP | Couleur | Commentaire |
|-----|-------|-----|---------|-------------| |-----|-------|-----|---------|-------------|
| Chatellerault | Chatellerault | 86100 | `#056CF2` | Couleur imposee par le ticket (bleu Coltura). | | Chatellerault | Chatellerault | 86100 | `#056CF2` | Couleur imposee par le ticket (bleu Starseed). |
| Saint-Jean | Saint-Jean-de-Sauves | 86330 | `#10B981` | Vert emeraude (contraste avec le bleu). | | Saint-Jean | Saint-Jean-de-Sauves | 86330 | `#10B981` | Vert emeraude (contraste avec le bleu). |
| Pommevic | Pommevic | 82400 | `#F59E0B` | Ambre (troisieme teinte nettement distincte). | | Pommevic | Pommevic | 82400 | `#F59E0B` | Ambre (troisieme teinte nettement distincte). |

View File

@@ -40,70 +40,70 @@ Le resultat attendu est un module Sites utilisable de bout en bout cote admin (c
### Backend — Module Sites ### Backend — Module Sites
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Domain/Exception/SiteNotAuthorizedException.php` : exception domaine levee si un user tente de switcher vers un site qui ne fait pas partie de ses sites autorises. Porte un message i18n-able et le code du site cible. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Domain/Exception/SiteNotAuthorizedException.php` : exception domaine levee si un user tente de switcher vers un site qui ne fait pas partie de ses sites autorises. Porte un message i18n-able et le code du site cible.
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/ApiPlatform/Resource/CurrentSiteResource.php` : ressource API Platform **virtuelle** (pas de mapping Doctrine, pas de `#[ORM\Entity]`). Sert uniquement a porter l'operation `Patch` `/me/current-site`. Expose une propriete `site: Site` en denormalisation pour recevoir l'IRI du site cible, et re-expose l'user courant en normalisation via le groupe `me:read`. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/ApiPlatform/Resource/CurrentSiteResource.php` : ressource API Platform **virtuelle** (pas de mapping Doctrine, pas de `#[ORM\Entity]`). Sert uniquement a porter l'operation `Patch` `/me/current-site`. Expose une propriete `site: Site` en denormalisation pour recevoir l'IRI du site cible, et re-expose l'user courant en normalisation via le groupe `me:read`.
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/ApiPlatform/State/Processor/CurrentSiteProcessor.php` : processor dedie a l'operation de switch. Valide l'appartenance du site aux `user.sites`, positionne `user.currentSite`, flush, retourne l'user. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/ApiPlatform/State/Processor/CurrentSiteProcessor.php` : processor dedie a l'operation de switch. Valide l'appartenance du site aux `user.sites`, positionne `user.currentSite`, flush, retourne l'user.
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/ApiPlatform/EventListener/SiteNotAuthorizedExceptionListener.php` : listener Kernel qui convertit `SiteNotAuthorizedException` en `ForbiddenHttpException` (403) avec un code i18n stable (cf. pattern `SystemRoleDeletionException` du module Core dans les tickets RBAC precedents). - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/ApiPlatform/EventListener/SiteNotAuthorizedExceptionListener.php` : listener Kernel qui convertit `SiteNotAuthorizedException` en `ForbiddenHttpException` (403) avec un code i18n stable (cf. pattern `SystemRoleDeletionException` du module Core dans les tickets RBAC precedents).
### Backend — Migration ### Backend — Migration
- `/home/m-tristan/workspace/Coltura/migrations/Version<timestamp2>.php` : migration au namespace racine `DoctrineMigrations` (cf. exception Doctrine documentee dans `CLAUDE.md`). Cree la table `user_site` et la colonne `user.current_site_id` avec les FKs et cascades appropriees. - `/home/m-tristan/workspace/Starseed/migrations/Version<timestamp2>.php` : migration au namespace racine `DoctrineMigrations` (cf. exception Doctrine documentee dans `CLAUDE.md`). Cree la table `user_site` et la colonne `user.current_site_id` avec les FKs et cascades appropriees.
### Backend — Tests API ### Backend — Tests API
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Api/SiteApiTest.php` : CRUD complet `/api/sites` avec matrices RBAC (admin, user avec `sites.view`, user avec `sites.manage`, user sans permission). - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Api/SiteApiTest.php` : CRUD complet `/api/sites` avec matrices RBAC (admin, user avec `sites.view`, user avec `sites.manage`, user sans permission).
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Api/CurrentSiteSwitchApiTest.php` : PATCH `/me/current-site` (OK avec site autorise, 403 avec site non autorise, 400 avec IRI invalide). - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Api/CurrentSiteSwitchApiTest.php` : PATCH `/me/current-site` (OK avec site autorise, 403 avec site non autorise, 400 avec IRI invalide).
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Api/MeEndpointSitesTest.php` : `/api/me` expose bien `sites` et `currentSite` en objets. User sans site : `sites: []`, `currentSite: null`. - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Api/MeEndpointSitesTest.php` : `/api/me` expose bien `sites` et `currentSite` en objets. User sans site : `sites: []`, `currentSite: null`.
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Api/SiteCascadeTest.php` : suppression d'un site `X` → toutes les lignes `user_site` referencant `X` sont supprimees, tous les users ayant `X` en `currentSite` voient leur `currentSite` repasser a `NULL`. - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Api/SiteCascadeTest.php` : suppression d'un site `X` → toutes les lignes `user_site` referencant `X` sont supprimees, tous les users ayant `X` en `currentSite` voient leur `currentSite` repasser a `NULL`.
- `/home/m-tristan/workspace/Coltura/tests/Module/Core/Api/UserRbacSitesApiTest.php` : extension du endpoint `/api/users/{id}/rbac` — ajout de `sites: []` dans le payload, retrait du `currentSite` quand le site retire etait le courant. - `/home/m-tristan/workspace/Starseed/tests/Module/Core/Api/UserRbacSitesApiTest.php` : extension du endpoint `/api/users/{id}/rbac` — ajout de `sites: []` dans le payload, retrait du `currentSite` quand le site retire etait le courant.
### Frontend — Module Sites (nouveau layer) ### Frontend — Module Sites (nouveau layer)
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/nuxt.config.ts` : marker de layer Nuxt (vide). Declenche l'auto-detection par `nuxt.config.ts` racine. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/nuxt.config.ts` : marker de layer Nuxt (vide). Declenche l'auto-detection par `nuxt.config.ts` racine.
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/pages/admin/sites.vue` : page `/admin/sites`. Reutilise les composants Malio UI (`MalioDataTable`, `MalioButton`, `MalioInputText`, `MalioInputTextArea`). Pattern identique a `frontend/modules/core/pages/admin/roles.vue`. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/pages/admin/sites.vue` : page `/admin/sites`. Reutilise les composants Malio UI (`MalioDataTable`, `MalioButton`, `MalioInputText`, `MalioInputTextArea`). Pattern identique a `frontend/modules/core/pages/admin/roles.vue`.
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/components/SiteDrawer.vue` : drawer creation/edition. Formulaire 5 champs (nom, ville, CP, couleur avec preview puce, adresse). Valide cote front sur le submit avant d'envoyer. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/components/SiteDrawer.vue` : drawer creation/edition. Formulaire 5 champs (nom, ville, CP, couleur avec preview puce, adresse). Valide cote front sur le submit avant d'envoyer.
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/components/SiteDeleteModal.vue` : modale de confirmation suppression. Pattern aligne sur `RoleDeleteModal.vue`. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/components/SiteDeleteModal.vue` : modale de confirmation suppression. Pattern aligne sur `RoleDeleteModal.vue`.
### Frontend — Types partages ### Frontend — Types partages
- `/home/m-tristan/workspace/Coltura/frontend/shared/types/sites.ts` : types `Site`, `SiteInput`. Pattern identique a `frontend/shared/types/rbac.ts`. - `/home/m-tristan/workspace/Starseed/frontend/shared/types/sites.ts` : types `Site`, `SiteInput`. Pattern identique a `frontend/shared/types/rbac.ts`.
### Tests frontend (optionnels mais recommandes) ### Tests frontend (optionnels mais recommandes)
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/pages/admin/sites.spec.ts` : smoke test Vitest (rendu + clic bouton "Nouveau site" ouvre le drawer). - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/pages/admin/sites.spec.ts` : smoke test Vitest (rendu + clic bouton "Nouveau site" ouvre le drawer).
## 4. Fichiers à modifier ## 4. Fichiers à modifier
### Backend — Module Core ### Backend — Module Core
- `/home/m-tristan/workspace/Coltura/src/Module/Core/Domain/Entity/User.php` : - `/home/m-tristan/workspace/Starseed/src/Module/Core/Domain/Entity/User.php` :
- Ajouter `private Collection $sites;` (M2M, `fetch: EAGER`, `JoinTable: user_site`), groupes `me:read`, `user:list`, `user:rbac:read`, `user:rbac:write`. - Ajouter `private Collection $sites;` (M2M, `fetch: EAGER`, `JoinTable: user_site`), groupes `me:read`, `user:list`, `user:rbac:read`, `user:rbac:write`.
- Ajouter `private ?Site $currentSite = null;` (M2O, `fetch: EAGER`, `onDelete: 'SET NULL'`), groupe `me:read`. - Ajouter `private ?Site $currentSite = null;` (M2O, `fetch: EAGER`, `onDelete: 'SET NULL'`), groupe `me:read`.
- Initialiser `$this->sites = new ArrayCollection();` dans le constructeur. - Initialiser `$this->sites = new ArrayCollection();` dans le constructeur.
- Ajouter les accesseurs `getSites()`, `addSite(Site)`, `removeSite(Site)`, `hasSite(Site)`, `getCurrentSite()`, `setCurrentSite(?Site)`. - Ajouter les accesseurs `getSites()`, `addSite(Site)`, `removeSite(Site)`, `hasSite(Site)`, `getCurrentSite()`, `setCurrentSite(?Site)`.
- **Important** : `import` direct `App\Module\Sites\Domain\Entity\Site`. Ce ticket assume le couplage Core → Sites au niveau code PHP (cf. Risque 1). - **Important** : `import` direct `App\Module\Sites\Domain\Entity\Site`. Ce ticket assume le couplage Core → Sites au niveau code PHP (cf. Risque 1).
- `/home/m-tristan/workspace/Coltura/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php` : - `/home/m-tristan/workspace/Starseed/src/Module/Core/Infrastructure/ApiPlatform/State/Processor/UserRbacProcessor.php` :
- Etendre le contrat d'entree pour accepter le champ `sites` (collection d'IRIs denormalisees en `Collection<Site>`). - Etendre le contrat d'entree pour accepter le champ `sites` (collection d'IRIs denormalisees en `Collection<Site>`).
- Apres l'application des roles et permissions directes, detecter si `currentSite` du user cible n'est plus dans la nouvelle collection `sites` → basculer `currentSite` a `null`. - Apres l'application des roles et permissions directes, detecter si `currentSite` du user cible n'est plus dans la nouvelle collection `sites` → basculer `currentSite` a `null`.
- Conserver toutes les gardes existantes (auto-suicide admin, dernier admin global). - Conserver toutes les gardes existantes (auto-suicide admin, dernier admin global).
- `/home/m-tristan/workspace/Coltura/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` : - `/home/m-tristan/workspace/Starseed/src/Module/Core/Infrastructure/DataFixtures/AppFixtures.php` :
- Declarer l'implementation `DependentFixtureInterface` avec `getDependencies(): [SitesFixtures::class]` (inversion de l'ordre actuel : AppFixtures doit tourner **apres** SitesFixtures pour pouvoir reference les sites). - Declarer l'implementation `DependentFixtureInterface` avec `getDependencies(): [SitesFixtures::class]` (inversion de l'ordre actuel : AppFixtures doit tourner **apres** SitesFixtures pour pouvoir reference les sites).
- Rattacher chaque user a au moins un site : `admin` a tous les sites (`Chatellerault`, `Saint-Jean`, `Pommevic`), `alice` a `Chatellerault`, `bob` a `Saint-Jean`. - Rattacher chaque user a au moins un site : `admin` a tous les sites (`Chatellerault`, `Saint-Jean`, `Pommevic`), `alice` a `Chatellerault`, `bob` a `Saint-Jean`.
- Positionner `currentSite` : `admin.currentSite = Chatellerault`, `alice.currentSite = Chatellerault`, `bob.currentSite = Saint-Jean`. - Positionner `currentSite` : `admin.currentSite = Chatellerault`, `alice.currentSite = Chatellerault`, `bob.currentSite = Saint-Jean`.
### Backend — Module Sites ### Backend — Module Sites
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Domain/Entity/Site.php` : - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Domain/Entity/Site.php` :
- Ajouter les attributs `#[ApiResource]` + operations (cf. section 5 Schema). - Ajouter les attributs `#[ApiResource]` + operations (cf. section 5 Schema).
- Ajouter les groupes de serialisation `site:read`, `site:write`, `me:read` sur les proprietes scalaires. - Ajouter les groupes de serialisation `site:read`, `site:write`, `me:read` sur les proprietes scalaires.
- Ajouter la relation inverse `private Collection $users;` (M2M mappedBy=`sites`), **sans** groupe de serialisation (pas d'exposition API cote Site). - Ajouter la relation inverse `private Collection $users;` (M2M mappedBy=`sites`), **sans** groupe de serialisation (pas d'exposition API cote Site).
- Initialiser `$this->users = new ArrayCollection();` dans le constructeur. - Initialiser `$this->users = new ArrayCollection();` dans le constructeur.
- Ajouter les accesseurs `getUsers()` pour les besoins metier (count / cascade manuel si besoin). - Ajouter les accesseurs `getUsers()` pour les besoins metier (count / cascade manuel si besoin).
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/DataFixtures/SitesFixtures.php` : aucun changement de contenu, mais verifier que la fixture n'est plus en bout de chaine de dependance (AppFixtures depend d'elle maintenant). - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/DataFixtures/SitesFixtures.php` : aucun changement de contenu, mais verifier que la fixture n'est plus en bout de chaine de dependance (AppFixtures depend d'elle maintenant).
### Backend — Configuration ### Backend — Configuration
- `/home/m-tristan/workspace/Coltura/config/sidebar.php` : inserer l'entree `Sites` dans la section `sidebar.general.section` entre `sidebar.core.users` et `sidebar.general.logout` : - `/home/m-tristan/workspace/Starseed/config/sidebar.php` : inserer l'entree `Sites` dans la section `sidebar.general.section` entre `sidebar.core.users` et `sidebar.general.logout` :
```php ```php
[ [
'label' => 'sidebar.core.sites', 'label' => 'sidebar.core.sites',
@@ -113,18 +113,18 @@ Le resultat attendu est un module Sites utilisable de bout en bout cote admin (c
'permission' => 'sites.view', 'permission' => 'sites.view',
], ],
``` ```
- `/home/m-tristan/workspace/Coltura/config/services.yaml` : aucun changement requis. `CurrentSiteProcessor`, `SiteNotAuthorizedExceptionListener` sont autoconfigures. - `/home/m-tristan/workspace/Starseed/config/services.yaml` : aucun changement requis. `CurrentSiteProcessor`, `SiteNotAuthorizedExceptionListener` sont autoconfigures.
### Frontend ### Frontend
- `/home/m-tristan/workspace/Coltura/frontend/modules/core/components/UserRbacDrawer.vue` : - `/home/m-tristan/workspace/Starseed/frontend/modules/core/components/UserRbacDrawer.vue` :
- Charger `GET /api/sites?itemsPerPage=999` a l'ouverture du drawer (parallelement aux roles et permissions deja charges). - Charger `GET /api/sites?itemsPerPage=999` a l'ouverture du drawer (parallelement aux roles et permissions deja charges).
- Ajouter une section `sidebar.admin.usersDrawer.sitesSection` sous la section permissions directes, avec un groupe de `MalioCheckbox` par site (ou un `MalioMultiSelect` si le composant existe dans `@malio/layer-ui`). - Ajouter une section `sidebar.admin.usersDrawer.sitesSection` sous la section permissions directes, avec un groupe de `MalioCheckbox` par site (ou un `MalioMultiSelect` si le composant existe dans `@malio/layer-ui`).
- Etendre le payload `PATCH /api/users/{id}/rbac` avec `sites: Array<string>` (IRIs). - Etendre le payload `PATCH /api/users/{id}/rbac` avec `sites: Array<string>` (IRIs).
- Auto-refresh de l'auth store apres save si `isSelfEdit` (deja present, conserver). - Auto-refresh de l'auth store apres save si `isSelfEdit` (deja present, conserver).
- `/home/m-tristan/workspace/Coltura/frontend/shared/types/rbac.ts` : ajouter le champ `sites: string[]` a `UserListItem` (IRIs de sites attaches). - `/home/m-tristan/workspace/Starseed/frontend/shared/types/rbac.ts` : ajouter le champ `sites: string[]` a `UserListItem` (IRIs de sites attaches).
- `/home/m-tristan/workspace/Coltura/frontend/shared/stores/auth.ts` : le store auth expose deja `user` via `/api/me`. Aucune modification requise, les nouveaux champs `sites` et `currentSite` suivent automatiquement via la typologie — a condition de mettre a jour le type `UserData` dans `shared/types/` (ajouter `sites: Site[]` et `currentSite: Site | null`). - `/home/m-tristan/workspace/Starseed/frontend/shared/stores/auth.ts` : le store auth expose deja `user` via `/api/me`. Aucune modification requise, les nouveaux champs `sites` et `currentSite` suivent automatiquement via la typologie — a condition de mettre a jour le type `UserData` dans `shared/types/` (ajouter `sites: Site[]` et `currentSite: Site | null`).
- `/home/m-tristan/workspace/Coltura/frontend/i18n/locales/fr.json` : cles - `/home/m-tristan/workspace/Starseed/frontend/i18n/locales/fr.json` : cles
- `sidebar.core.sites` = "Sites". - `sidebar.core.sites` = "Sites".
- `admin.sites.title`, `admin.sites.newSite`, `admin.sites.editSite`, `admin.sites.createSite`, `admin.sites.noSites`. - `admin.sites.title`, `admin.sites.newSite`, `admin.sites.editSite`, `admin.sites.createSite`, `admin.sites.noSites`.
- `admin.sites.table.{name, city, postalCode, color, fullAddress}`. - `admin.sites.table.{name, city, postalCode, color, fullAddress}`.
@@ -228,7 +228,7 @@ final class CurrentSiteResource
## 6. Plan de migration Doctrine ## 6. Plan de migration Doctrine
La migration est placee dans `/home/m-tristan/workspace/Coltura/migrations/Version<timestamp2>.php` au namespace racine (cf. Risque 2 du ticket 1 et `CLAUDE.md`). La migration est placee dans `/home/m-tristan/workspace/Starseed/migrations/Version<timestamp2>.php` au namespace racine (cf. Risque 2 du ticket 1 et `CLAUDE.md`).
### `up()` — ordre des instructions ### `up()` — ordre des instructions

View File

@@ -77,42 +77,42 @@ Resultat attendu : apres merge, un user avec ≥ 1 site voit une barre sous la n
### Frontend — Module Sites (layer deja cree au ticket 2) ### Frontend — Module Sites (layer deja cree au ticket 2)
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/components/SiteSelector.vue` : wrapper Vue autour de `MalioSiteSelector`. Branche `useCurrentSite()`, gere l'optimistic update et les toasts. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/components/SiteSelector.vue` : wrapper Vue autour de `MalioSiteSelector`. Branche `useCurrentSite()`, gere l'optimistic update et les toasts.
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/composables/useCurrentSite.ts` : composable global exposant l'etat `currentSite` / `availableSites`, les actions `switchSite`, `resetCurrentSite`, et un flag `switching: Ref<boolean>` pour desactiver le selecteur pendant une requete en vol. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/composables/useCurrentSite.ts` : composable global exposant l'etat `currentSite` / `availableSites`, les actions `switchSite`, `resetCurrentSite`, et un flag `switching: Ref<boolean>` pour desactiver le selecteur pendant une requete en vol.
### Frontend — Shared ### Frontend — Shared
- `/home/m-tristan/workspace/Coltura/frontend/shared/composables/useModules.ts` : composable qui charge `/api/modules` et expose `isModuleActive(id: string): boolean`. Pattern aligne sur `useSidebar()` : ref singleton au niveau module, chargement idempotent, `resetModules()` expose pour le logout. - `/home/m-tristan/workspace/Starseed/frontend/shared/composables/useModules.ts` : composable qui charge `/api/modules` et expose `isModuleActive(id: string): boolean`. Pattern aligne sur `useSidebar()` : ref singleton au niveau module, chargement idempotent, `resetModules()` expose pour le logout.
- `/home/m-tristan/workspace/Coltura/frontend/shared/utils/color.ts` : fonctions utilitaires de couleur, au minimum : - `/home/m-tristan/workspace/Starseed/frontend/shared/utils/color.ts` : fonctions utilitaires de couleur, au minimum :
- `parseHex(hex: string): { r: number; g: number; b: number }` — tolere la casse, rejette les formats hors `#RRGGBB`. - `parseHex(hex: string): { r: number; g: number; b: number }` — tolere la casse, rejette les formats hors `#RRGGBB`.
- `getRelativeLuminance({r, g, b}): number` — formule WCAG standard. - `getRelativeLuminance({r, g, b}): number` — formule WCAG standard.
- `getReadableTextColor(hex: string): 'black' | 'white'` — renvoie `'black'` si la luminance > 0.5, `'white'` sinon. Seuil simple, suffisant pour un CRM interne (pas WCAG AAA). - `getReadableTextColor(hex: string): 'black' | 'white'` — renvoie `'black'` si la luminance > 0.5, `'white'` sinon. Seuil simple, suffisant pour un CRM interne (pas WCAG AAA).
### Frontend — Tests ### Frontend — Tests
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/composables/__tests__/useCurrentSite.spec.ts` : Vitest. Tests : - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/composables/__tests__/useCurrentSite.spec.ts` : Vitest. Tests :
- `switchSite` met a jour l'etat localement avant la requete (optimistic). - `switchSite` met a jour l'etat localement avant la requete (optimistic).
- Si la requete reussit, l'etat reste aligne. - Si la requete reussit, l'etat reste aligne.
- Si la requete echoue, l'etat rollback a l'ancien `currentSite`. - Si la requete echoue, l'etat rollback a l'ancien `currentSite`.
- `resetCurrentSite` vide l'etat. - `resetCurrentSite` vide l'etat.
- `/home/m-tristan/workspace/Coltura/frontend/shared/composables/__tests__/useModules.spec.ts` : Vitest. Tests `isModuleActive` apres chargement, `resetModules` vide l'etat. - `/home/m-tristan/workspace/Starseed/frontend/shared/composables/__tests__/useModules.spec.ts` : Vitest. Tests `isModuleActive` apres chargement, `resetModules` vide l'etat.
- `/home/m-tristan/workspace/Coltura/frontend/shared/utils/__tests__/color.spec.ts` : Vitest. Jeu de donnees sur `getReadableTextColor` : `#000000` → white, `#FFFFFF` → black, `#056CF2` (bleu Coltura) → white, `#F59E0B` (ambre) → black, `#10B981` (vert) → black ou white selon seuil (a verifier). Tester aussi le rejet de formats invalides. - `/home/m-tristan/workspace/Starseed/frontend/shared/utils/__tests__/color.spec.ts` : Vitest. Jeu de donnees sur `getReadableTextColor` : `#000000` → white, `#FFFFFF` → black, `#056CF2` (bleu Starseed) → white, `#F59E0B` (ambre) → black, `#10B981` (vert) → black ou white selon seuil (a verifier). Tester aussi le rejet de formats invalides.
- `/home/m-tristan/workspace/Coltura/frontend/modules/sites/components/__tests__/SiteSelector.spec.ts` : smoke test Vitest. - `/home/m-tristan/workspace/Starseed/frontend/modules/sites/components/__tests__/SiteSelector.spec.ts` : smoke test Vitest.
## 4. Fichiers à modifier ## 4. Fichiers à modifier
- `/home/m-tristan/workspace/Coltura/frontend/package.json` : upgrade `@malio/layer-ui` vers la version qui inclut `MalioSiteSelector`. Commit du `package-lock.json` dans le meme changeset. - `/home/m-tristan/workspace/Starseed/frontend/package.json` : upgrade `@malio/layer-ui` vers la version qui inclut `MalioSiteSelector`. Commit du `package-lock.json` dans le meme changeset.
- `/home/m-tristan/workspace/Coltura/frontend/shared/types/user-data.ts` : ajouter les champs - `/home/m-tristan/workspace/Starseed/frontend/shared/types/user-data.ts` : ajouter les champs
```ts ```ts
sites: Site[] sites: Site[]
currentSite: Site | null currentSite: Site | null
``` ```
Import du type `Site` depuis `./sites`. Note : si le type `Site` a deja ete introduit au ticket 2, reutiliser ; sinon, ce ticket le cree dans `frontend/shared/types/sites.ts`. Import du type `Site` depuis `./sites`. Note : si le type `Site` a deja ete introduit au ticket 2, reutiliser ; sinon, ce ticket le cree dans `frontend/shared/types/sites.ts`.
- `/home/m-tristan/workspace/Coltura/frontend/shared/types/sites.ts` : si absent, creer avec l'interface `Site` (cf. section Schema ticket 2 pour la forme). Si present, aucune modification. - `/home/m-tristan/workspace/Starseed/frontend/shared/types/sites.ts` : si absent, creer avec l'interface `Site` (cf. section Schema ticket 2 pour la forme). Si present, aucune modification.
- `/home/m-tristan/workspace/Coltura/frontend/app/layouts/default.vue` : integrer `SiteSelector` sous le header, avant `<main>`, dans le flex column. Rendu conditionnel via `v-if="showSiteSelector"` ou via un `defineAsyncComponent` chargement lazy si on veut eviter l'import statique quand le module est off. - `/home/m-tristan/workspace/Starseed/frontend/app/layouts/default.vue` : integrer `SiteSelector` sous le header, avant `<main>`, dans le flex column. Rendu conditionnel via `v-if="showSiteSelector"` ou via un `defineAsyncComponent` chargement lazy si on veut eviter l'import statique quand le module est off.
- `/home/m-tristan/workspace/Coltura/frontend/app/middleware/auth.global.ts` : ajouter le chargement de `useModules().loadModules()` apres `loadSidebar()`. Necessaire pour que `isModuleActive` soit resolu quand le layout se rend. - `/home/m-tristan/workspace/Starseed/frontend/app/middleware/auth.global.ts` : ajouter le chargement de `useModules().loadModules()` apres `loadSidebar()`. Necessaire pour que `isModuleActive` soit resolu quand le layout se rend.
- `/home/m-tristan/workspace/Coltura/frontend/modules/core/pages/logout.vue` : appeler `useCurrentSite().resetCurrentSite()` et `useModules().resetModules()` apres le `auth.logout()`, aligne sur le pattern `resetSidebar()` deja present. - `/home/m-tristan/workspace/Starseed/frontend/modules/core/pages/logout.vue` : appeler `useCurrentSite().resetCurrentSite()` et `useModules().resetModules()` apres le `auth.logout()`, aligne sur le pattern `resetSidebar()` deja present.
- `/home/m-tristan/workspace/Coltura/frontend/i18n/locales/fr.json` : ajouter les cles - `/home/m-tristan/workspace/Starseed/frontend/i18n/locales/fr.json` : ajouter les cles
```json ```json
"sites": { "sites": {
"selector": { "selector": {

View File

@@ -34,50 +34,50 @@ Le ticket livre aussi une documentation developpeur (`docs/modules/site-aware.md
### Shared — Contrat ### Shared — Contrat
- `/home/m-tristan/workspace/Coltura/src/Shared/Domain/Contract/SiteAwareInterface.php` : interface minimale. Depends uniquement du type `App\Module\Sites\Domain\Entity\Site`, qui est deja couple cote Core depuis le ticket 2 — le placement dans Shared n'introduit pas de nouvelle dependance transversale non souhaitee. - `/home/m-tristan/workspace/Starseed/src/Shared/Domain/Contract/SiteAwareInterface.php` : interface minimale. Depends uniquement du type `App\Module\Sites\Domain\Entity\Site`, qui est deja couple cote Core depuis le ticket 2 — le placement dans Shared n'introduit pas de nouvelle dependance transversale non souhaitee.
### Module Sites — Application ### Module Sites — Application
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Application/Service/CurrentSiteProvider.php` : service injecte partout ou le site courant doit etre lu (extensions, processor, futurs voters). Gere les trois cas de retour `null` : pas d'user, `currentSite` null, module desactive. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Application/Service/CurrentSiteProvider.php` : service injecte partout ou le site courant doit etre lu (extensions, processor, futurs voters). Gere les trois cas de retour `null` : pas d'user, `currentSite` null, module desactive.
### Module Sites — Infrastructure ### Module Sites — Infrastructure
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/ApiPlatform/Extension/SiteScopedQueryExtension.php` : une seule classe, implementant a la fois `QueryCollectionExtensionInterface` et `QueryItemExtensionInterface`. Le comportement est identique pour les deux, modulo que l'item manque retourne 404 (API Platform converti un `getOneOrNullResult` null en 404). - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/ApiPlatform/Extension/SiteScopedQueryExtension.php` : une seule classe, implementant a la fois `QueryCollectionExtensionInterface` et `QueryItemExtensionInterface`. Le comportement est identique pour les deux, modulo que l'item manque retourne 404 (API Platform converti un `getOneOrNullResult` null en 404).
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/Infrastructure/ApiPlatform/State/Processor/SiteAwareInjectionProcessor.php` : decorator sur le persist processor Doctrine. Injecte le site courant sur `$data` si applicable, puis delegue a `$persistProcessor`. - `/home/m-tristan/workspace/Starseed/src/Module/Sites/Infrastructure/ApiPlatform/State/Processor/SiteAwareInjectionProcessor.php` : decorator sur le persist processor Doctrine. Injecte le site courant sur `$data` si applicable, puis delegue a `$persistProcessor`.
### Documentation ### Documentation
- `/home/m-tristan/workspace/Coltura/docs/modules/site-aware.md` : guide developpeur (cf. contenu section 10). - `/home/m-tristan/workspace/Starseed/docs/modules/site-aware.md` : guide developpeur (cf. contenu section 10).
### Tests ### Tests
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Infrastructure/ApiPlatform/Extension/SiteScopedQueryExtensionTest.php` : tests d'integration (`KernelTestCase`) avec l'entite `FakeSiteAwareEntity` (declaree uniquement dans le dossier de tests). Verifie : - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Infrastructure/ApiPlatform/Extension/SiteScopedQueryExtensionTest.php` : tests d'integration (`KernelTestCase`) avec l'entite `FakeSiteAwareEntity` (declaree uniquement dans le dossier de tests). Verifie :
- Le filtre s'applique sur une resource `SiteAware` quand le provider retourne un site. - Le filtre s'applique sur une resource `SiteAware` quand le provider retourne un site.
- Le filtre est no-op si `SiteAware` mais provider null. - Le filtre est no-op si `SiteAware` mais provider null.
- Le filtre est no-op si resource non `SiteAware`. - Le filtre est no-op si resource non `SiteAware`.
- Le filtre est no-op si user a `sites.bypass_scope`. - Le filtre est no-op si user a `sites.bypass_scope`.
- `totalItems` Hydra reflete bien le filtrage. - `totalItems` Hydra reflete bien le filtrage.
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Infrastructure/ApiPlatform/State/Processor/SiteAwareInjectionProcessorTest.php` : tests unitaires (`TestCase` pur) avec mocks. Verifie : - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Infrastructure/ApiPlatform/State/Processor/SiteAwareInjectionProcessorTest.php` : tests unitaires (`TestCase` pur) avec mocks. Verifie :
- `$data` SiteAware sans site → injection du site courant. - `$data` SiteAware sans site → injection du site courant.
- `$data` SiteAware avec site deja positionne → pas d'overwrite. - `$data` SiteAware avec site deja positionne → pas d'overwrite.
- `$data` non-SiteAware → delegation directe sans modification. - `$data` non-SiteAware → delegation directe sans modification.
- Provider retourne null (module off ou user sans site) ET `$data` SiteAware sans site → BadRequestHttpException (400) "aucun site selectionne". - Provider retourne null (module off ou user sans site) ET `$data` SiteAware sans site → BadRequestHttpException (400) "aucun site selectionne".
- `/home/m-tristan/workspace/Coltura/tests/Module/Sites/Application/Service/CurrentSiteProviderTest.php` : tests unitaires `TestCase`. Couvre : - `/home/m-tristan/workspace/Starseed/tests/Module/Sites/Application/Service/CurrentSiteProviderTest.php` : tests unitaires `TestCase`. Couvre :
- User authentifie avec currentSite → retourne le Site. - User authentifie avec currentSite → retourne le Site.
- User authentifie sans currentSite → null. - User authentifie sans currentSite → null.
- Pas d'user → null. - Pas d'user → null.
- Module desactive dans config/modules.php de test → null meme si user.currentSite existe. - Module desactive dans config/modules.php de test → null meme si user.currentSite existe.
- `/home/m-tristan/workspace/Coltura/tests/Fixtures/SiteAware/FakeSiteAwareEntity.php` : entite Doctrine minimale (`id`, `name`, `site`) utilisee **uniquement** en tests. Mapping Doctrine declare via un `#[ORM\Entity]` mais la table n'existe jamais en prod car la fixture n'est jamais chargee hors tests. **Alternative** : utiliser un schema DB dedie au dossier de tests, cree a la volee par un helper setUp. A trancher a l'implementation. - `/home/m-tristan/workspace/Starseed/tests/Fixtures/SiteAware/FakeSiteAwareEntity.php` : entite Doctrine minimale (`id`, `name`, `site`) utilisee **uniquement** en tests. Mapping Doctrine declare via un `#[ORM\Entity]` mais la table n'existe jamais en prod car la fixture n'est jamais chargee hors tests. **Alternative** : utiliser un schema DB dedie au dossier de tests, cree a la volee par un helper setUp. A trancher a l'implementation.
## 4. Fichiers à modifier ## 4. Fichiers à modifier
- `/home/m-tristan/workspace/Coltura/src/Module/Sites/SitesModule.php` : ajouter la permission `sites.bypass_scope` dans `permissions()` : - `/home/m-tristan/workspace/Starseed/src/Module/Sites/SitesModule.php` : ajouter la permission `sites.bypass_scope` dans `permissions()` :
```php ```php
['code' => 'sites.bypass_scope', 'label' => 'Voir les donnees site-scoped de tous les sites (bypass du filtrage)'], ['code' => 'sites.bypass_scope', 'label' => 'Voir les donnees site-scoped de tous les sites (bypass du filtrage)'],
``` ```
**Note importante** : la methode `permissions()` signale l'existence de la permission mais c'est la commande `app:sync-permissions` (inchangee) qui la positionne en base. **Note importante** : la methode `permissions()` signale l'existence de la permission mais c'est la commande `app:sync-permissions` (inchangee) qui la positionne en base.
- `/home/m-tristan/workspace/Coltura/config/services.yaml` : aucun changement requis. `SiteScopedQueryExtension`, `SiteAwareInjectionProcessor` et `CurrentSiteProvider` sont autoconfigures via les `_defaults` du module. Le decorator du persist processor est declare via `#[AsDecorator]` ou via tag (cf. section 8). - `/home/m-tristan/workspace/Starseed/config/services.yaml` : aucun changement requis. `SiteScopedQueryExtension`, `SiteAwareInjectionProcessor` et `CurrentSiteProvider` sont autoconfigures via les `_defaults` du module. Le decorator du persist processor est declare via `#[AsDecorator]` ou via tag (cf. section 8).
- `/home/m-tristan/workspace/Coltura/phpunit.dist.xml` : aucune modification requise si la config des fixtures de tests est autonome. Si `FakeSiteAwareEntity` necessite un mapping dedie, l'option la plus propre est un `doctrine.yaml.test` ajoute via `when@test`, sans polluer la config dev/prod (cf. Risque 3). - `/home/m-tristan/workspace/Starseed/phpunit.dist.xml` : aucune modification requise si la config des fixtures de tests est autonome. Si `FakeSiteAwareEntity` necessite un mapping dedie, l'option la plus propre est un `doctrine.yaml.test` ajoute via `when@test`, sans polluer la config dev/prod (cf. Risque 3).
## 5. Contrat `SiteAwareInterface` ## 5. Contrat `SiteAwareInterface`
@@ -459,7 +459,7 @@ A mitiger par un test qui genere une entite `FakeSiteAwareEntity` via un POST `a
### Risque 8 — Doc developpeur en francais vs anglais ### Risque 8 — Doc developpeur en francais vs anglais
Le fichier `docs/modules/site-aware.md` s'adresse aux developpeurs de Coltura. Il est redige en **francais**, aligne sur la convention projet (CLAUDE.md : "commentaires en francais, code en anglais"). Aucun extrait de code ne doit etre traduit, seules les explications. Le fichier `docs/modules/site-aware.md` s'adresse aux developpeurs de Starseed. Il est redige en **francais**, aligne sur la convention projet (CLAUDE.md : "commentaires en francais, code en anglais"). Aucun extrait de code ne doit etre traduit, seules les explications.
## 12. Plan de tests ## 12. Plan de tests

View File

@@ -62,6 +62,6 @@ watch(() => route.path, () => {
}) })
useHead({ useHead({
titleTemplate: (title) => title || 'Coltura', titleTemplate: (title) => title || 'Starseed',
}) })
</script> </script>

View File

@@ -1 +1 @@
/* Coltura - Custom styles */ /* Starseed - Custom styles */

View File

@@ -14,7 +14,7 @@ export default await nuxt(
}, },
}, },
{ {
name: 'coltura/custom-overrides', name: 'starseed/custom-overrides',
rules: { rules: {
// Indentation 4 espaces (convention CLAUDE.md) // Indentation 4 espaces (convention CLAUDE.md)
'vue/html-indent': ['error', 4], 'vue/html-indent': ['error', 4],

View File

@@ -36,7 +36,7 @@
}, },
"dashboard": { "dashboard": {
"title": "Tableau de bord", "title": "Tableau de bord",
"welcome": "Bienvenue sur Coltura" "welcome": "Bienvenue sur Starseed"
}, },
"commercial": { "commercial": {
"title": "Commercial", "title": "Commercial",

View File

@@ -9,7 +9,8 @@
<!-- Filtres --> <!-- Filtres -->
<section class="mt-4 rounded border border-gray-200 bg-white p-4"> <section class="mt-4 rounded border border-gray-200 bg-white p-4">
<!-- Labels uniformes au-dessus : les composants Malio sont utilises sans <!-- Labels uniformes au-dessus : les composants Malio sont utilises sans
leur `label` flottant interne pour ne pas mixer deux patterns de label. --> leur `label` flottant interne pour ne pas mixer deux patterns de label.
A revoir une fois le composant calendar Malio développé -->
<div class="grid grid-cols-1 items-start gap-3 md:grid-cols-5"> <div class="grid grid-cols-1 items-start gap-3 md:grid-cols-5">
<!-- TODO(malio-ui): remplacer par un composant Malio quand la lib <!-- TODO(malio-ui): remplacer par un composant Malio quand la lib
exposera un datetime picker. Cf. exception documentee dans exposera un datetime picker. Cf. exception documentee dans
@@ -59,26 +60,20 @@
v-model="performedByInput" v-model="performedByInput"
icon-name="mdi:account-search" icon-name="mdi:account-search"
input-class="text-sm" input-class="text-sm"
group-class="h-10"
/> />
</div> </div>
<!-- TODO(malio-ui): remplacer par MalioSelect quand la lib
supportera de maniere fiable des options a valeur string
(cf. note Lesstime CLAUDE.md). Exception documentee dans
CLAUDE.md (section "Composants formulaires"). -->
<div> <div>
<label class="mb-1 block text-xs font-medium text-gray-600"> <label class="mb-1 block text-xs font-medium text-gray-600">
{{ t('audit.filters.action') }} {{ t('audit.filters.action') }}
</label> </label>
<select <div class="[&>div>div]:!mt-0">
v-model="actionValue" <MalioSelect
class="h-[40px] w-full rounded-md border border-m-muted bg-white px-3 text-sm outline-none focus-visible:border-2 focus-visible:border-m-primary" v-model="actionValue"
> :options="actionOptions"
<option value="">{{ t('audit.filters.all_actions') }}</option> text-field="text-sm"
<option v-for="opt in actionOptions" :key="opt.value" :value="opt.value"> text-value="text-sm"
{{ opt.label }} />
</option> </div>
</select>
</div> </div>
</div> </div>
@@ -204,11 +199,14 @@ const entityTypeOptions = computed(() =>
// pas binder directement un `string | undefined` reactive. // pas binder directement un `string | undefined` reactive.
const performedByInput = ref<string>('') const performedByInput = ref<string>('')
// Action : MalioSelect ne gere pas fiablement des options a valeur string (cf. // Action : '' = "toutes les actions". On declare l'option dans `actionOptions`
// note Lesstime CLAUDE.md). On utilise un `<select>` natif stylise comme les // plutot que via `emptyOptionLabel` (qui n'inclut pas l'option vide dans
// inputs dates pour garder un look coherent. '' = "toutes les actions". // `props.options`, donc `selectedLabel` reste vide). On evite aussi `value: null`
// car MalioSelect grise visuellement les options dont la valeur est `null`
// (Select.vue:137) — on utilise donc une chaine vide comme sentinelle.
const actionValue = ref<string>('') const actionValue = ref<string>('')
const actionOptions = [ const actionOptions = [
{ value: '', label: t('audit.filters.all_actions') },
{ value: 'create', label: t('audit.action.create') }, { value: 'create', label: t('audit.action.create') },
{ value: 'update', label: t('audit.action.update') }, { value: 'update', label: t('audit.action.update') },
{ value: 'delete', label: t('audit.action.delete') }, { value: 'delete', label: t('audit.action.delete') },
@@ -378,7 +376,7 @@ watch(selectedEntityTypes, values => {
loadEntries() loadEntries()
}) })
// Sync select action natif -> filters.action. // Sync MalioSelect action -> filters.action.
watch(actionValue, value => { watch(actionValue, value => {
if (watchersSuspended) return if (watchersSuspended) return
filters.action = value === '' ? undefined : value filters.action = value === '' ? undefined : value

View File

@@ -8,7 +8,7 @@
<MalioButton <MalioButton
v-if="can('core.roles.manage')" v-if="can('core.roles.manage')"
:label="t('admin.roles.newRole')" :label="t('admin.roles.newRole')"
icon-name="mdi:plus" icon-name="mdi:add-bold"
icon-position="left" icon-position="left"
@click="openCreateDrawer" @click="openCreateDrawer"
/> />

View File

@@ -27,8 +27,8 @@
<MalioButton <MalioButton
label="Se connecter" label="Se connecter"
button-class="w-full" button-class="w-full"
type="submit"
:disabled="isSubmitting" :disabled="isSubmitting"
@click="handleSubmit"
/> />
<p class="font-bold">v{{ version }}</p> <p class="font-bold">v{{ version }}</p>
</form> </form>

View File

@@ -78,7 +78,7 @@ async function onChange(site: { id: string; name: string; color: string }): Prom
// intentionnellement supprimee pour garantir qu'un clic sur le tile // intentionnellement supprimee pour garantir qu'un clic sur le tile
// "actif selon cet onglet" envoie quand meme le PATCH et re-synchronise // "actif selon cet onglet" envoie quand meme le PATCH et re-synchronise
// l'etat. Amelioration future : ecouter l'evenement `storage` sur la // l'etat. Amelioration future : ecouter l'evenement `storage` sur la
// cle `coltura:site-switch` pour mettre a jour les onglets inactifs // cle `starseed:site-switch` pour mettre a jour les onglets inactifs
// sans clic via auth.fetchUser() / auth.refreshUser(). // sans clic via auth.fetchUser() / auth.refreshUser().
try { try {

View File

@@ -8,7 +8,7 @@
<MalioButton <MalioButton
v-if="can('sites.manage')" v-if="can('sites.manage')"
:label="t('admin.sites.newSite')" :label="t('admin.sites.newSite')"
icon-name="mdi:plus" icon-name="mdi:add-bold"
icon-position="left" icon-position="left"
@click="openCreateDrawer" @click="openCreateDrawer"
/> />

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{ {
"name": "coltura-frontend", "name": "starseed-frontend",
"type": "module", "type": "module",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -17,7 +17,7 @@
"test:e2e:ui": "playwright test --ui" "test:e2e:ui": "playwright test --ui"
}, },
"dependencies": { "dependencies": {
"@malio/layer-ui": "^1.4.2", "@malio/layer-ui": "^1.5.0",
"@nuxt/icon": "^2.2.1", "@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3", "@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0", "@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -1,7 +1,7 @@
import { defineConfig, devices } from '@playwright/test' import { defineConfig, devices } from '@playwright/test'
/** /**
* Config Playwright pour les tests E2E de Coltura. * Config Playwright pour les tests E2E de Starseed.
* *
* Pre-requis avant de lancer : * Pre-requis avant de lancer :
* 1. Les containers Docker tournent (`make start`) * 1. Les containers Docker tournent (`make start`)

View File

@@ -1,7 +1,7 @@
import type {Config} from 'tailwindcss' import type {Config} from 'tailwindcss'
/** /**
* Config Tailwind du projet Coltura. * Config Tailwind du projet Starseed.
* *
* @nuxtjs/tailwindcss merge automatiquement les configs de chaque layer * @nuxtjs/tailwindcss merge automatiquement les configs de chaque layer
* Nuxt declare dans `nuxt.config.ts:extends`. Le layer `@malio/layer-ui` * Nuxt declare dans `nuxt.config.ts:extends`. Le layer `@malio/layer-ui`
@@ -11,7 +11,7 @@ import type {Config} from 'tailwindcss'
* success,btn-*,site-blue,site-yellow,site-green} * success,btn-*,site-blue,site-yellow,site-green}
* - fontFamily.sans (Helvetica Neue) * - fontFamily.sans (Helvetica Neue)
* *
* Cette config locale ne redeclare QUE ce qui est specifique a Coltura * Cette config locale ne redeclare QUE ce qui est specifique a Starseed
* ou absent de la config Malio — evite la duplication et les derives. * ou absent de la config Malio — evite la duplication et les derives.
*/ */
export default <Partial<Config>>{ export default <Partial<Config>>{
@@ -19,7 +19,7 @@ export default <Partial<Config>>{
theme: { theme: {
extend: { extend: {
colors: { colors: {
// Couleurs applicatives Coltura (hors namespace `m` reserve // Couleurs applicatives Starseed (hors namespace `m` reserve
// au design system Malio partage). // au design system Malio partage).
primary: { primary: {
500: '#222783', 500: '#222783',

View File

@@ -1,8 +1,8 @@
DOCKER_APP_NAME=coltura DOCKER_APP_NAME=starseed
DOCKER_PHP_VERSION=8.4.6 DOCKER_PHP_VERSION=8.4.6
DOCKER_NODE_VERSION=24.12.0 DOCKER_NODE_VERSION=24.12.0
APP_USER=www-data APP_USER=www-data
POSTGRES_DB=coltura POSTGRES_DB=starseed
POSTGRES_USER=root POSTGRES_USER=root
POSTGRES_PASSWORD=root POSTGRES_PASSWORD=root
POSTGRES_PORT=5437 POSTGRES_PORT=5437

View File

@@ -2,11 +2,12 @@ APP_ENV=prod
APP_DEBUG=0 APP_DEBUG=0
APP_SECRET=CHANGE_ME_IN_PRODUCTION APP_SECRET=CHANGE_ME_IN_PRODUCTION
DATABASE_URL="postgresql://coltura:CHANGE_ME@host.docker.internal:5432/coltura?serverVersion=16&charset=utf8" DATABASE_URL="postgresql://starseed:CHANGE_ME@host.docker.internal:5432/starseed_prod?serverVersion=16&charset=utf8"
JWT_PASSPHRASE=CHANGE_ME_IN_PRODUCTION JWT_PASSPHRASE=CHANGE_ME_IN_PRODUCTION
JWT_COOKIE_SECURE=1 # HTTP en reseau local => cookie non secure
JWT_COOKIE_SECURE=0
JWT_TOKEN_TTL=86400 JWT_TOKEN_TTL=86400
JWT_COOKIE_TTL=86400 JWT_COOKIE_TTL=86400
CORS_ALLOW_ORIGIN='^https://coltura\.malio-dev\.fr$' CORS_ALLOW_ORIGIN='^http://starseed\.malio-dev\.fr$'

View File

@@ -60,7 +60,7 @@ RUN rm -f /etc/nginx/sites-enabled/default
# Configs # Configs
COPY infra/prod/supervisord.conf /etc/supervisor/conf.d/app.conf COPY infra/prod/supervisord.conf /etc/supervisor/conf.d/app.conf
COPY infra/prod/nginx.conf /etc/nginx/sites-enabled/coltura.conf COPY infra/prod/nginx.conf /etc/nginx/sites-enabled/starseed.conf
# Backend from stage 1 # Backend from stage 1
COPY --from=backend-build /app /var/www/html COPY --from=backend-build /app /var/www/html

View File

@@ -4,9 +4,9 @@ set -euo pipefail
cd "$(dirname "$0")" cd "$(dirname "$0")"
TAG="${1:-latest}" TAG="${1:-latest}"
export COLTURA_IMAGE_TAG="$TAG" export STARSEED_IMAGE_TAG="$TAG"
echo "==> Deploying coltura:${TAG}..." echo "==> Deploying starseed:${TAG}..."
echo "==> Enabling maintenance mode..." echo "==> Enabling maintenance mode..."
touch maintenance.on touch maintenance.on

View File

@@ -1,16 +1,16 @@
services: services:
app: app:
image: gitea.malio.fr/malio-dev/coltura:${COLTURA_IMAGE_TAG:-latest} image: gitea.malio.fr/malio-dev/starseed:${STARSEED_IMAGE_TAG:-latest}
container_name: coltura-app container_name: starseed-app
env_file: .env env_file: .env
ports: ports:
- "8086:80" - "8086:80"
volumes: volumes:
- ./config/jwt:/var/www/html/config/jwt:ro - ./config/jwt:/var/www/html/config/jwt:ro
- coltura_logs:/var/www/html/var/log - starseed_logs:/var/www/html/var/log
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
restart: unless-stopped restart: unless-stopped
volumes: volumes:
coltura_logs: starseed_logs:

View File

@@ -1,12 +1,12 @@
server { server {
listen 80; listen 80;
listen [::]:80; listen [::]:80;
server_name coltura.malio-dev.fr; server_name starseed.malio-dev.fr;
root /var/www/coltura/public; root /var/www/starseed/public;
# Maintenance mode # Maintenance mode
if (-f /var/www/coltura/maintenance.on) { if (-f /var/www/starseed/maintenance.on) {
return 503; return 503;
} }

View File

@@ -9,6 +9,12 @@ ENV_FILE := $(if $(wildcard $(ENV_LOCAL)),$(ENV_LOCAL),$(ENV_DEFAULT))
include $(ENV_DEFAULT) include $(ENV_DEFAULT)
-include $(ENV_LOCAL) -include $(ENV_LOCAL)
# Export du UID/GID host pour que docker compose les voie dans toutes les targets
# (sinon le build du Dockerfile dev fail sur `usermod -u ${CURRENT_UID}` quand l'image
# n'est pas en cache, ex: apres renommage du compose project).
export CURRENT_UID := $(shell id -u)
export CURRENT_GID := $(shell id -g)
PHP_CONTAINER = php-$(DOCKER_APP_NAME)-fpm PHP_CONTAINER = php-$(DOCKER_APP_NAME)-fpm
SYMFONY_CONSOLE = $(EXEC_PHP) php bin/console SYMFONY_CONSOLE = $(EXEC_PHP) php bin/console
@@ -26,7 +32,7 @@ FILES =
# Affiche l'aide — cible par defaut (make ou make help) # Affiche l'aide — cible par defaut (make ou make help)
help: help:
@printf "\n \033[1mColtura — Commandes make\033[0m\n\n" @printf "\n \033[1mStarseed — Commandes make\033[0m\n\n"
@printf " \033[1;33mContainers\033[0m\n" @printf " \033[1;33mContainers\033[0m\n"
@printf " \033[36m%-28s\033[0m %s\n" "start" "Demarrer les containers Docker" @printf " \033[36m%-28s\033[0m %s\n" "start" "Demarrer les containers Docker"
@printf " \033[36m%-28s\033[0m %s\n" "stop" "Arreter les containers" @printf " \033[36m%-28s\033[0m %s\n" "stop" "Arreter les containers"

View File

@@ -11,7 +11,7 @@ use Doctrine\Migrations\AbstractMigration;
* Module Sites - Ticket 1/4 : brique fondatrice de donnees. * Module Sites - Ticket 1/4 : brique fondatrice de donnees.
* *
* Cree la table `site` qui porte les etablissements physiques de l'instance * Cree la table `site` qui porte les etablissements physiques de l'instance
* Coltura. La table est creee inconditionnellement : meme si SitesModule est * Starseed. La table est creee inconditionnellement : meme si SitesModule est
* desactive dans `config/modules.php`, la structure DB existe (pas de * desactive dans `config/modules.php`, la structure DB existe (pas de
* dependance dure depuis Core, mais pas de coin d'ombre schema non plus). * dependance dure depuis Core, mais pas de coin d'ombre schema non plus).
* *

View File

@@ -24,7 +24,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
/** /**
* Site physique (usine / etablissement) appartenant a l'instance Coltura. * Site physique (usine / etablissement) appartenant a l'instance Starseed.
* *
* Adresse decomposee en champs structures (rue, complement, CP, ville) pour * Adresse decomposee en champs structures (rue, complement, CP, ville) pour
* permettre des recherches/tris fins ulterieurs et eviter les divergences * permettre des recherches/tris fins ulterieurs et eviter les divergences

View File

@@ -36,7 +36,7 @@ class SitesFixtures extends Fixture
public function load(ObjectManager $manager): void public function load(ObjectManager $manager): void
{ {
// Chatellerault : bleu Coltura. // Chatellerault : bleu Starseed.
$this->ensureSite( $this->ensureSite(
$manager, $manager,
name: 'Chatellerault', name: 'Chatellerault',