# internal-authentication Specification ## Purpose Provide session-based authentication for the internal Filament panel at `/admin`, limited to two roles (admin and assistant), with unique emails, password reset without enumeration, inactive users denied, and user management restricted to admins. ## Requirements ### Requirement: Internal users authenticate via Filament panel The system SHALL provide authenticated access to the internal panel at `/admin` using Laravel's session-based authentication integrated with Filament 5. #### Scenario: Active admin logs in successfully - **WHEN** an active user with role `admin` submits valid credentials on the login page - **THEN** the system authenticates the user and redirects to the Filament dashboard #### Scenario: Active assistant logs in successfully - **WHEN** an active user with role `assistant` submits valid credentials on the login page - **THEN** the system authenticates the user and redirects to the Filament dashboard #### Scenario: Inactive user is denied panel access - **WHEN** a user with `is_active` set to false submits valid credentials - **THEN** the system MUST NOT grant access to the Filament panel ### Requirement: User roles are limited to admin and assistant The system SHALL store user roles using the `UserRole` enum with exactly two cases: `admin` and `assistant`. The system MUST NOT implement a granular permission system in the MVP. #### Scenario: User is created with a valid role - **WHEN** an administrator creates a user with role `admin` or `assistant` - **THEN** the role is persisted and enforced on subsequent authorization checks ### Requirement: Email addresses are unique per user The system SHALL enforce a unique constraint on user email addresses. #### Scenario: Duplicate email rejected - **WHEN** a user is created or updated with an email already assigned to another user - **THEN** the system MUST reject the operation with a validation error ### Requirement: Password reset is available for internal users The system SHALL support secure password reset for internal users using Laravel's built-in reset flow. #### Scenario: User requests password reset - **WHEN** a user submits a registered email on the password reset form - **THEN** the system sends a reset link without revealing whether the email exists ### Requirement: Only admin manages internal users The system SHALL restrict user management (create, update, deactivate) to users with role `admin`. Users with role `assistant` MUST NOT manage other users. #### Scenario: Assistant cannot access user management - **WHEN** an authenticated assistant attempts to access user management in the panel - **THEN** the system MUST deny access via authorization policy ### Requirement: Verified email is required for panel access Internal users MUST have a verified email address to access the Filament panel (SPEC §12.1, ADM-01). Active users with unverified email MUST be denied panel access. Development seeds MUST mark local demo users as verified. #### Scenario: Unverified active user is denied panel access - **WHEN** an active user with null `email_verified_at` authenticates - **THEN** the system MUST NOT grant access to the Filament panel #### Scenario: Verified active user can access the panel - **WHEN** an active user with a non-null `email_verified_at` submits valid credentials - **THEN** the system authenticates the user and allows Filament panel access subject to role rules #### Scenario: Local seed users are verified - **WHEN** `DatabaseSeeder` creates the local admin and assistant - **THEN** both users MUST have `email_verified_at` set ### Requirement: Password reset flow is covered by automated tests The secure password reset flow for internal users MUST be covered by feature tests that assert a reset request for a registered email queues/sends a reset notification without revealing whether the email exists to the client (SPEC §12.1; existing password-reset requirement). #### Scenario: Reset request does not reveal account existence - **WHEN** a visitor submits a password reset for an unknown email - **THEN** the response MUST not disclose that the email is unregistered #### Scenario: Registered email receives reset notification - **WHEN** a visitor submits a password reset for a registered email - **THEN** the system MUST dispatch the password reset notification (faked in tests)