- Expose l'entite Permission via ApiResource (GetCollection + Get uniquement)
- Serialisation limitee au groupe permission:read (id, code, label, module, orphan)
- Securite temporaire is_granted('ROLE_ADMIN'), a remplacer par
is_granted('core.permissions.view') au ticket #345
- Filtres : SearchFilter exact sur module, BooleanFilter sur orphan
- Configure api_platform.mapping.paths pour que le compile pass AP decouvre
les ApiResource/ApiFilter declares dans src/Module/Core/Domain/Entity
- Ajoute symfony/browser-kit et symfony/http-client en dev pour les tests
fonctionnels API Platform, plus KERNEL_CLASS dans phpunit.dist.xml
- Tests fonctionnels PermissionApiTest : collection, get item, filtres
module et orphan, 405 sur POST, 401 non authentifie, 403 non-admin
isAdmin, roles et directPermissions ne doivent pas etre modifiables via
PATCH /api/users/{id}. L exposition en ecriture sera traitee par un
processor dedie dans le ticket #344 (spec section 2 OUT).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documente le bug Doctrine Migrations 3.x (tri par FQCN au lieu de
version timestamp avec plusieurs migrations_paths) et la regle
provisoire : migrations d'init au namespace racine, namespace
modulaire reserve aux migrations applicatives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug decouvert a l'execution de 'make db-reset' sur base vide : Doctrine
Migrations 3.x avec plusieurs 'migrations_paths' execute les migrations
dans l'ordre (namespace, version) et non (version, namespace). Le
Version20260414150034 sous 'App\Module\Core\...' passait donc avant
Version20260407095546 sous 'DoctrineMigrations', provoquant un
"relation user does not exist".
Deplacement du fichier vers 'migrations/' (namespace DoctrineMigrations).
Le chemin modulaire reste configure pour les futurs modules, mais
la migration RBAC d'initialisation vit a la racine pour que
'make db-reset' fonctionne en one-shot.
Smoke test end-to-end valide :
- db-reset + fixtures : admin (is_admin=t, role admin), alice/bob
(is_admin=f, role user)
- app:sync-permissions : 4 permissions Core ajoutees, idempotent au 2e run
- User::getRoles() : ['ROLE_USER', 'ROLE_ADMIN'] pour admin, ['ROLE_USER']
pour alice/bob
- User::getEffectivePermissions() : union triee des permissions via roles
Ticket #343 - 7/7 : smoke test end-to-end OK.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ensureSystemRole() recopie desormais la description depuis la migration
RBAC pour que les chemins prod (migration) et dev (fixtures) produisent
un etat identique.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AppFixtures : rattachement des users aux entites Role via
RoleRepositoryInterface. Re-seed idempotent des roles systeme dans
ensureSystemRole() pour compenser le purger Doctrine qui vide la table
role avant load(), afin que "make db-reset && make fixtures" reste un
workflow one-shot.
- CreateUserCommand : flag --admin attache au role systeme admin + is_admin,
sinon au role user. Gestion d'erreur explicite si les roles systeme sont
absents (FAILURE + message pointant vers la migration).
- CreateUserCommand devient final, descriptions traduites en francais.
Ticket #343 - 6/7 : fixtures et command alignes sur le RBAC relationnel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Nouvelles tables permission, role, role_permission, user_role, user_permission
- Ajout user.is_admin (BOOLEAN, default false)
- Seed des roles systeme admin et user via SQL brut (autonome, pas besoin
de fixtures pour cette etape)
- Migration des donnees : is_admin reflete ROLE_ADMIN du JSON roles, puis
rattachement user_role selon admin/user
- Drop user.roles en dernier (apres la migration de donnees)
- down() recree la colonne roles et la rehydrate depuis is_admin
Ticket #343 - 5/7 : persistance + migration donnees safe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CoreModule declare 4 permissions initiales (users.view/manage, roles.manage,
permissions.view)
- Nouvelle commande app:sync-permissions :
* scan des *Module::permissions() via config/modules.php
* validation stricte : cles [code, label], prefixe module, non-vides
* upsert transactionnel non-destructif
* revival des permissions orphelines qui reapparaissent
* marquage orphan pour les permissions disparues du code
* un seul flush() final (evite le flush-par-save de la repo save())
Ticket #343 - 4/7 : scanner et synchroniseur de permissions RBAC.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Suppression de la colonne JSON roles (persiste jusqu'a la migration Task 5)
- Ajout is_admin bool (seul levier de bypass RBAC via getRoles())
- Ajout ManyToMany User-Role (EAGER, table user_role)
- Ajout ManyToMany User-Permission directes (EAGER, table user_permission)
- getEffectivePermissions() : union dedupliquee triee, utilisee par le
futur PermissionVoter (#345)
- getRbacRoles() pour ne pas shadow getRoles() de UserInterface Symfony
- Tests unitaires couvrant derivation getRoles, union, deduplication, tri
Ticket #343 - 3/7 : migration du User vers le modele RBAC relationnel.
Fetch EAGER documente : evite le lazy-load au refresh JWT.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PermissionRepositoryInterface avec findByCode et findAllCodes (pour le sync
command et le futur PermissionVoter)
- RoleRepositoryInterface avec findByCode
- Implementations Doctrine alignees sur DoctrineUserRepository
- Alias DI dans config/services.yaml
- Rebranchement de repositoryClass sur les entites Permission et Role
Ticket #343 - 2/7 : couche persistence RBAC.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Permission : guards constructeur (code/label/module non vides, code avec point)
- Permission::revive() reutilise updateMetadata() pour eviter la duplication
- Suppression de SystemRolesTest (tautologique, ne capture aucun comportement)
- Role::permissions : commentaire explicite sur la raison du fetch EAGER
- Alignement des types de retour sur static (style User.php)
- Nouveau test Role::addPermission avec permissions distinctes
Ticket #343 - Task 1 polish (revue qualite).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Entite Permission avec methodes markOrphan/revive/updateMetadata
- Entite Role avec addPermission/removePermission/ensureDeletable
- Constantes SystemRoles (codes admin/user partages)
- Exception SystemRoleDeletionException pour la garde de suppression
- Tests unitaires couvrant le comportement domaine (pas de BDD)
Ticket #343 - 1/7 : fondations RBAC (domaine pur, sans persistence).
Les entites ne portent pas encore repositoryClass (ajoute en Task 2).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Spec detaillee des fondations RBAC backend (entites Role/Permission, sync
command, migration, fixtures, tests) dans docs/rbac/ticket-343-spec.md
- Ajout CLAUDE.md des regles projet : commentaires francais (PHP + TS/Vue)
et convention de nommage des permissions module.resource[.sub].action
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Persist var/log/ via named volume coltura_logs so logs survive
container restarts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ESLint with @nuxt/eslint-config enforcing 4-space indentation.
Add make nuxt-lint and nuxt-lint-fix targets.
Add ESLint check to pre-commit hook (lint only, no auto-fix).
Fix auth.vue indentation from 2 to 4 spaces.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Change UserOutput.id from int to ?int to match User::getId() return type.
Replace EntityManagerInterface with UserRepositoryInterface in CreateUserCommand.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add resetSidebar() to useSidebar composable and call it on logout
to prevent stale sidebar data after re-login.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update CLAUDE.md to reflect actual ports (PG 5437, frontend 3004).
Fix CHANGELOG.md header from "Ferme" to "Coltura".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Maintenance is handled by nginx-proxy on the host, not inside the
container. deploy.sh extracts maintenance.html from the container.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single container with supervisord (Nginx + PHP-FPM), 3-stage
Dockerfile build, pre-built image from registry, port 8086.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without APP_ENV=prod, Symfony defaults to dev and tries to load
DoctrineFixturesBundle which is excluded by --no-dev.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- tailwind.config.ts: full theme with primary/secondary/tertiary + m-* CSS vars
- infra/prod/maintenance.html: maintenance page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>