Roles and permissions — legacy technical guide
Scope and evidence
Reviewed 15 October 2026 against local working trees of smartmobility-legacy, smartmobility-nextgen-back and smartmobility-nextgen-front. References below are repository-relative paths. This is code inspection; existing automated scenarios are cited as supporting specifications and were not executed. No production configuration, live authorization test or complete security audit is claimed.
The functional guide describes user behavior; the configuration guide describes administration.
Legacy data model and authorization
| Element | Source | Responsibility |
|---|---|---|
| Permission profile | src/Main/ConfigBundle/Entity/Permission.php | Named organization profile carrying right codes, manager attachments and user permission relations |
| Catalogue entry | src/Main/ConfigBundle/Entity/PermissionType.php | Individual right offered in the matrix |
| Additional user assignment | src/Main/ConfigBundle/Entity/UserPermission.php | Links a user to a profile |
| Administration | src/Company/PermissionBundle/Controller/DefaultController.php | Profile CRUD, rights matrix and deduplicated user listing |
| Form and matrix | src/Main/ConfigBundle/Form/Type/PermissionType.php; src/Company/PermissionBundle/Resources/views/Default/roles.html.twig | Name, display-hiding flag, checkbox matrix and automatic save |
| Authorization voter | src/Security/PermissionVoter.php; src/Security/Voter/BaseVoter.php | ROLE_PERMISSION checks and alternative grant paths |
PermissionVoter supports the ROLE_PERMISSION attribute. It first accepts the master-school branch; otherwise BaseVoter::hasRoleAccess checks, with OR semantics:
- The manager/school profile's stored right list.
- Every additional
UserPermissionprofile's right list. TokenizerService::hasRoleAccess, when the service is present.
isMasterSchool requires an enabled user with an attached school/manager object and ROLE_COMPANY, with neither a parent school nor an attached permission profile. This is a privileged branch of this voter, not a statement that every controller bypasses every other check.
Administration write and membership behavior
roleupdateAction handles an AJAX POST, initializes an empty right list for every submitted permission_ids[], then collects input-{profileId}-{rightCode} checkbox values and replaces each profile's stored list. The template submits the entire matrix after changes. The list and matrix load profiles from the current setting. Tenant boundaries and controller authorization must be assessed for each administration path; this overview is not a security audit.
datatableRoleAction resolves its requested profile with the current setting and combines consultant/manager attachments with UserPermission recipients, deduplicating by user ID. That listing is not an inventory of tokenizer grants.
Employee-platform route gate
src/EventListener/PermissionGateListener.php gates main requests whose paths begin with /plateforme when the authenticated legacy user has at least one additional permission profile with nonempty rights. It denies a missing _permission route attribute, or a required code list with no match. For an array of required codes, any matching code suffices.
The gate builds its code set from UserPermission profiles. It does not use the entire OR chain of BaseVoter, so the two mechanisms must not be described as equivalent. The gate is conditional and does not establish protection for every legacy path.
Legacy/nextgen integration
Legacy src/Service/V2/SmrPermissionService.php checks the hybrid feature switch and retrieves nextgen permission slugs through Mk4UserRightService, caching per user within the service. A disabled switch or switch-check exception returns an empty list; this does not describe all adapter error handling. src/Service/V2/RoleService.php delegates administrator initialization to Mk4AdminService and expects a success response of 1.
These services do not establish automatic equivalence between legacy right codes and nextgen role permissions, or synchronization of populations and visibility scopes.
Supporting scenarios and validation limits
Existing backend specifications under tests/Behat/Features/V2/access_control/role/ cover CRUD, permission attachment, user and user-group attachment, consolidated population, cloning, reset, presets, visibility groups and administration. attach_visibility_group.feature explicitly covers propagation to an enabled permission and removal from role defaults after a permission-specific detach. Permission-scope attachment scenarios also exist under access_control/role_permission/.
Legacy supporting tests include tests/Integration/Security/PermissionVoterTest.php, tests/Unit/EventListener/PermissionGateListenerTest.php and tests/Unit/Service/V2/SmrPermissionServiceTest.php. These files were identified, not run for this documentation change.
For deployed acceptance, test ordinary users through list, detail, write and export paths of each target module. Neither a menu condition nor the role-management contract establishes identical scope enforcement across all resource implementations.
Platform activation and runtime dependencies
Verified in code: legacy src/EventListener/FeatureSwitchListener.php defines HYBRID_MODE_SLUG and THEME_BO_V3_SLUG. themeV3Enabled persists V2 compatibility theme flags. hybridPlatformEnabled publishes hybrid configuration through SMRConfigurationPublisher before attempting administrator initialization when an impersonated user is available. Publication and administrator provisioning are distinct effects; successful initialization is not established merely by the theme being active.
The role editor depends on authenticated session bootstrap, the permission catalogue, locale/translation loading and access to the role API. Membership-derived rights depend on persisted user-group membership; no universal group-recalculation delay was established. Scope resolution in UserRightManager caches by permission within the service; the lifetime across deployed requests/workers and universal grant-refresh timing were Not verified. Do not promise an exact propagation SLA.
AIHub boundary: repository paths were verified and aihub/src/auth/security.py inspected. It defines its own API-key/JWT request authentication boundary. No role-editor caller or source evidence establishing AIHub as the nextgen role or visibility authority was found in the scoped search. It is not included as a dependency in the verified role flow; this is a bounded negative finding, not proof that every AIHub integration is unrelated to permissions.
Failure modes and observability
| Failure | Verified code behavior / diagnostic boundary |
|---|---|
| Missing role-management permission | Route permissions reject unauthorized operations; existing Behat specifications assert 403 for unauthorized permission/visibility mutations. The scenarios were not executed here. |
| Unknown visibility-group ID | Existing attachment specifications expect validation failure with a resource-not-found field message. Do not reuse IDs between tenants. |
| Role not found for population | src/Http/Api/Controller/V2/RoleController.php::population throws a not-found response when the role cannot be resolved. |
| Delete role still assigned | RoleListener::preDelete rejects with “Current Role is not deletable.” while direct or group links remain. |
| Initialize admin for disabled user | RoleController::initializeAdmin rejects a disabled user. This is not the ordinary customer role-create action. |
| Permission toggle fails | _handleTogglePermission in RolesDetailSettingsPermissions.vue logs the error and reverts the displayed state; server-confirmed state should be reloaded before retrying. |
| Preset restoration partly fails | Frontend logs an error, shows failure feedback and uses multiple requests; rollback atomicity is not established. |
| Hybrid admin initialization fails | Legacy FeatureSwitchListener::hybridPlatformEnabled logs “Failed to initialize admin role on hybrid platform”. A preceding publication/activation may already have happened. |
| Hybrid switch check fails | SmrPermissionService logs the switch-check exception and returns no retrieved rights; adapter-call failures are a separate boundary. |
For diagnosis, record generation, space, action, affected role and whether the denial came from shell display, API action or resource scope. Use authorized application logging; omit credentials and employee records from support exports. No role-specific centralized audit log, durable preset history or monitoring dashboard was established by this investigation.
Security, privacy and extension points
Verified in code: action grants and visibility scope are distinct. Direct and group-derived grants combine; there is no explicit deny overriding every other role in the inspected resolver. A restrictive role cannot be assumed to cancel a broader grant. Campaign membership and resource-specific validators remain independent.
For a new action, the relevant extension surfaces are the permission catalogue and preset mapping, backend route permission declarations, resource-specific scope enforcement, frontend action guards and translations. Confirm the consuming resource uses the scope resolver; attaching a visibility group is not proof of enforcement on an unrelated list, detail or export path. Extend the existing permission-denial and scope scenarios as appropriate for application changes; this documentation change does not modify those applications.
Client-safe boundary: no account-switch addresses, credentials, employee data or internal support access paths belong in examples or screenshots. The technical guide intentionally contains no application screenshot embeds or generated screenshot assets.
Documentary evidence and unresolved differences
Documented in Confluence: SMR - Roles & permission, version 4, 10 April 2026, describes end-user exposure intent; Back-office V3, version 2, 8 July 2026, and Playbook SMR, version 3, 24 September 2026, describe coexistence and setup. The April exclusion statement is not a verified removal of legacy persistence or voters. The playbook's default hierarchical scope and “one group = one role” recommendation are not universal resolver rules or database cardinalities. Its “no Super Admin” customer guidance does not erase privileged identities implemented in backend code.
The Visibility System, version 9, 11 October 2023, concerns historical scope behavior; it does not establish current nextgen filtering contracts.
The supplied KBCT entry returned 404. Both supplied PS entries were read and verified in PS: Delivery Philosophy & Project Methodology, version 7, 30 December 2025, and Onboarding/learning and partner certification, version 9, 18 February 2026. Neither defines an endpoint, default or runtime guarantee.
Deployment versions, synchronization completeness, cross-request caches, migration/rollback guarantees and every downstream resource's population enforcement remain Not verified. No commits were attributed as the deployed version. Application inspection is supplementary and documented in the functional/configuration guides; implementation claims here remain anchored to local paths and symbols.
Functional-guide evidence
These implementation and product references support the functional guide. Local source behavior does not establish which revision or optional features are deployed. Application observations remain distinct from code and documentary evidence.
Verified in code: legacy src/Security/PermissionVoter.php, src/Security/Voter/BaseVoter.php, src/EventListener/PermissionGateListener.php, src/Twig/Company/CompanyNavigationExtension.php; backend nextgen RoleManager, UserRightManager, RoleRightRepository and role routes; frontend src/modules/Users/Roles/. Precise paths and symbols are in the technical guide.
Documented in Confluence: SMR - Roles & permission, version 4, 10 April 2026; Back-office V3, version 2, 8 July 2026; Playbook - SmartMobility Redesign (SMR), version 3, 24 September 2026. The April page expresses exclusion of the old role system from end-user exposure; later guidance describes coexistence. The embedded live screen and local integration code support coexistence for the inspected context, not automatic migration of every tenant. The playbook's default hierarchy description was not verified as a universal resource rule.
Journey verification — 26 October 2026
Observed in application: PS Testing 2026, Jim Carter. Created role 112 with descriptive metadata only. Blank-name validation was observed. A fresh load retained title/description and 0 people, 0 activated permissions, 0 associated visibility groups. No access grant, preset or recipient was changed. User menu → Configuration returned an authorization denial at /company/account/setting.
Dernière mise à jour : 3 novembre 2026