Access Control
The admissions system uses a layered access control model combining ACL (Access Control List) roles from the Kinderpedia platform with RBAC (Role-Based Access Control) permissions defined within the admissions module.
Access Control Layers
Layer 1: Platform ACL Roles
The Kinderpedia platform assigns high-level ACL roles that determine whether a user can access the admissions module at all:
| Role | Access Level |
|---|---|
ROLE_MANAGER | Full platform management -- automatically grants admissions access |
ROLE_ACL_ADMISSIONSCRM_FULL | Full admissions module access |
ROLE_ACL_ADMISSIONSCRM_BASIC_ACCESS | Basic admissions read access |
ROLE_ACL_ADMISSIONSCRM_CONFIG_ACCESS | Admissions configuration write access |
WARNING
Important: ROLE_ACL_ADMISSIONSCRM_FULL does not automatically include BASIC_ACCESS or CONFIG_ACCESS. There is no role hierarchy. All required roles must be explicitly assigned.
Layer 2: Module RBAC Permissions
Within the admissions module, custom roles define granular permissions for specific actions (viewing leads, creating contracts, editing forms, etc.). These are configured in the Users & Roles page.
Layer 3: Route-Level Guards
Frontend routes check permissions via meta fields:
| Guard | Behavior |
|---|---|
requiresAuth: true | Must be authenticated |
permissions: ['leads.view'] | Must have the specified permission |
requiresConfig: true | Must have configuration access role |
How Access Checks Work
When a user tries to access a feature, the system checks in order:
- Is the user authenticated? -- JWT token must be valid.
- Does the user have the required ACL role? -- The platform role must grant access to the admissions module.
- Does the user have the required permission? -- The module-level permission for the specific action must be granted via one of the user's roles.
If any check fails, access is denied.
Permission Inheritance
Permissions are additive across roles:
- If a user has Role A with
leads.viewand Role B withleads.edit, they have both permissions. - There is no permission denial -- you cannot explicitly block a permission; you can only not grant it.
- A user with no roles has no permissions (beyond what their platform ACL role provides).
Backend Security
Every API endpoint enforces access control:
API Platform Entities
Entities use the security attribute to check roles:
security: "is_granted('ROLE_MANAGER') or is_granted('ROLE_ACL_ADMISSIONSCRM_FULL') or is_granted('ROLE_ACL_ADMISSIONSCRM_BASIC_ACCESS')"Custom Controllers
Controllers use the #[IsGranted] attribute with expression-based role checks:
- All three roles (
ROLE_MANAGER,_FULL, and the specific sub-role) must be explicitly listed. - Missing any role from the check would lock out users with that role.
Kindergarten Scoping
All data queries are automatically filtered by kindergartenId:
- A user can only see data belonging to their school.
- This is enforced at the database query level, not just at the UI level — so even an API request can never reach another school's data.
Common Access Patterns
Admissions Manager
- Platform role:
ROLE_MANAGERorROLE_ACL_ADMISSIONSCRM_FULL - Module roles: All permissions enabled
- Can: Everything -- configure, create, edit, delete, export
Admissions Officer
- Platform role:
ROLE_ACL_ADMISSIONSCRM_BASIC_ACCESS - Module roles: Leads (view, create, edit), Forms (view), Contracts (view, create)
- Can: Day-to-day operations; cannot configure settings
Read-Only Viewer
- Platform role:
ROLE_ACL_ADMISSIONSCRM_BASIC_ACCESS - Module roles: Only view permissions
- Can: View leads, forms, reports; cannot modify anything
Configuration Administrator
- Platform role:
ROLE_ACL_ADMISSIONSCRM_FULL+ROLE_ACL_ADMISSIONSCRM_CONFIG_ACCESS - Module roles: All settings and configuration permissions
- Can: Full configuration access plus operational features
Authentication Details
- JWT-based -- Authentication uses a JWT token stored in a cookie named
JWToken. - Stateless -- No server-side session; the token contains all claims.
- Auto-refresh -- When a token expires (401 response), the system automatically attempts a refresh before prompting re-login.
- Required headers -- Every API request includes the
X-KINDERGARTEN-IDheader to scope data to the correct school.
Troubleshooting Access Issues
| Problem | Possible Cause | Solution |
|---|---|---|
| "Unauthorized" page | JWT expired and refresh failed | Log in again from the main platform |
| Cannot see Configuration tab | Missing CONFIG_ACCESS role | Ask a manager to assign the role |
| Cannot create contracts | Missing contracts.create permission | Ask an admin to add the permission to your role |
| Cannot see any leads | Missing BASIC_ACCESS platform role | Contact your school's platform administrator |
| Seeing data from wrong school | X-KINDERGARTEN-ID mismatch | Log out and log back in |