Platform
Auth and Roles
Authentication surfaces, firewalls, roles, and scope checks.
Auth and Roles
Authentication is Auth0-based, but the app uses different Symfony firewalls for browser portals and API traffic.
Firewalls
Defined in app/config/packages/security.yaml:
| Firewall | Pattern | Authenticator | Provider | Notes |
|---|---|---|---|---|
api_docs | ^/api/docs | none | none | Public API docs. |
api_v2_docs | ^/api/v2/docs | none | none | Public API v2 docs. |
portal | `^/(supervisor | payroll | finance | electrician |
admin | `^/(admin | login | auth | xero |
api | ^/api | Auth0Authenticator | UserProvider | Stateless JWT API. |
main | fallback | default lazy | UserProvider | Fallback for non-API routes. |
Access control
Important rules:
/login,/logout,/admin/logout, and/auth/callbackare public./api/docsand/api/v2/docsare public and must be listed before/api./xero, portals, and debug routes require full authentication./apirequiresROLE_USER./admin/clients/{id}/projectsallowsROLE_ADMINandROLE_CLIENT_ADMIN./admingenerally requiresROLE_ADMIN.
Role and scope model
The code uses both broad user type and client/project relationships.
UserTypedecides the broad persona.ClientMembershipRoledecides client-scoped responsibilities.Project.clientSupervisorsidentifies users who can review work for a project.Client.clientAdminsandPortalClientScopeServiceidentify client-admin scope.Projectassigned electricians/users identify who can submit work.
Timesheet edit policy
TimesheetEditPolicy centralizes which roles can edit which timesheet fields:
| Actor | Allowed edits |
|---|---|
| Platform Admin | Any field. |
| Electrician owner | Any field only while the timesheet is draft or rejected. |
| Supervisor | Job code, cost code, status, signature, and location fields, only before sign-off. Status transition is restricted to accepted or rejected from submitted/accepted. |
| Client Admin | Job code and cost code only, and only before approval. |
| Payroll | No direct timesheet editing through this policy. |
Changes are logged by TimesheetChangeLogger as one TimesheetChangeLog row per changed field path, grouped by a change-set UUID.