Admin Account Management & Domain-Restricted Registration
Problem
-
Admin account management: When logged into the admin backend (
/admin), there's no way to manage your own account (change email, password). The account management pages at/accountuse a completely different layout, breaking the admin experience. -
Open registration: Anyone with any email can register. We need to restrict registration to pre-approved email domains, managed via the admin UI.
Design
Feature 1: Admin Account Management
New controller: AdminAccountController at /admin/account
Routes:
- GET /admin/account — Show account settings (change email, change password forms)
- POST /admin/account/change-email — Process email change
- GET /admin/account/verify-email/{token} — Verify new email
- POST /admin/account/cancel-email-change — Cancel pending email change
- POST /admin/account/change-password — Process password change
Reuses existing forms (ChangeEmailFormType, AccountChangePasswordFormType) and services (EmailVerificationService, UserPasswordHasherInterface). No account deletion from admin panel.
Admin layout additions:
- User dropdown in admin header (top-right): shows logged-in email, links to "My Account" and "Log out"
- Sidebar link under "Main" section
- Template: templates/admin/account/index.html.twig using admin card/form styles
Feature 2: Domain-Restricted Registration
New entity: AllowedDomain
- id (int, auto-increment)
- domain (string, unique) — e.g. "atraxion.com"
- createdAt (datetime_immutable)
Admin CRUD: AdminAllowedDomainController at /admin/allowed-domains
- List, create, delete (no edit — domains are simple strings)
- Follows existing AbstractAdminController pattern
- Sidebar link under "Main" section
Registration validation:
- Custom Symfony validator constraint AllowedEmailDomain
- Applied to the email field in RegistrationFormType
- Logic: if AllowedDomain table has entries, email domain must match one. If table is empty, all domains allowed
- Error message: "Registration is restricted to approved email domains."
Decisions
- Admin account pages are a separate controller (not a layout-switching refactor of
AccountController) to keep things clean and follow the existing admin pattern - Domain list stored in database with admin CRUD (not env vars or config files) for runtime flexibility
- Hard block on unapproved domains (no approval queue)
- Empty domain table = open registration (prevents lockout during setup)
- No edit for allowed domains — delete and re-add is simpler for a single-field entity