diff --git a/docs/stories/story-1.2-authentication-role-system.md b/docs/stories/story-1.2-authentication-role-system.md
index 6ffc55f..42da0b9 100644
--- a/docs/stories/story-1.2-authentication-role-system.md
+++ b/docs/stories/story-1.2-authentication-role-system.md
@@ -1,91 +1,301 @@
# Story 1.2: Authentication & Role System
+## Status
+Draft
+
## Epic Reference
**Epic 1:** Core Foundation & Infrastructure
-## User Story
-As an **admin**,
-I want **a secure authentication system with Admin/Client roles**,
-So that **only authorized users can access the platform with appropriate permissions**.
-
-## Story Context
-
-### Existing System Integration
-- **Integrates with:** Fortify authentication, users table
-- **Technology:** Laravel Fortify, Livewire Volt
-- **Follows pattern:** Existing `app/Actions/Fortify/` for custom logic
-- **Touch points:** FortifyServiceProvider, login views, middleware
+## Story
+**As an** admin,
+**I want** a secure authentication system with Admin/Client roles,
+**So that** only authorized users can access the platform with appropriate permissions.
## Acceptance Criteria
### Functional Requirements
-- [ ] Fortify configured with custom Volt views
-- [ ] Login page with bilingual support (Arabic/English)
-- [ ] Session timeout after 2 hours of inactivity
-- [ ] Rate limiting on login attempts (5 attempts per minute)
-- [ ] Admin role with full access to all features
-- [ ] Client role with restricted access (own data only)
-- [ ] Registration feature DISABLED (admin creates all accounts)
+1. [ ] Fortify configured with custom Volt views
+2. [ ] Login page with bilingual support (Arabic/English)
+3. [ ] Session timeout after 2 hours of inactivity
+4. [ ] Rate limiting on login attempts (5 attempts per minute)
+5. [ ] Admin role with full access to all features
+6. [ ] Client role with restricted access (own data only)
+7. [ ] Registration feature DISABLED (admin creates all accounts)
### Security Requirements
-- [ ] CSRF protection enabled on all forms
-- [ ] Password hashing using bcrypt
-- [ ] Gates/Policies for authorization checks
-- [ ] Secure session configuration
-- [ ] Remember me functionality (optional)
+8. [ ] CSRF protection enabled on all forms
+9. [ ] Password hashing using bcrypt
+10. [ ] Custom middleware for admin authorization
+11. [ ] Secure session configuration
+12. [ ] Remember me functionality (optional)
### Integration Requirements
-- [ ] Login redirects to appropriate dashboard:
- - Admin users → `/admin/dashboard` (to be created in Epic 2)
- - Client users → `/dashboard` (to be created in Epic 2)
- - For now, redirect to a placeholder route or home page
-- [ ] Logout clears session properly and redirects to login page
-- [ ] Middleware protects admin-only routes (return 403 for unauthorized)
-- [ ] Failed login attempts logged to `admin_logs` table
+13. [ ] Login redirects to appropriate dashboard:
+ - Admin users → `/admin/dashboard` (placeholder until Epic 6)
+ - Client users → `/client/dashboard` (placeholder until Epic 7)
+14. [ ] Logout clears session properly and redirects to login page
+15. [ ] Admin middleware protects admin-only routes (return 403 for unauthorized)
+16. [ ] Failed login attempts logged to `admin_logs` table
+17. [ ] Deactivated users cannot log in
### Quality Requirements
-- [ ] Login form validates inputs properly
-- [ ] Error messages are clear and bilingual
-- [ ] All test scenarios in "Test Scenarios" section pass
-- [ ] No security vulnerabilities
+18. [ ] Login form validates inputs properly
+19. [ ] Error messages are clear and bilingual
+20. [ ] All test scenarios in "Testing" section pass
+21. [ ] No security vulnerabilities
-## Technical Notes
+## Tasks / Subtasks
+
+- [ ] **Task 1: Configure Fortify** (AC: 1, 7)
+ - [ ] Update `config/fortify.php` to disable registration feature
+ - [ ] Keep `resetPasswords` enabled (admin-triggered only via future Epic)
+ - [ ] Keep `emailVerification`, `updateProfileInformation`, `updatePasswords` enabled
+ - [ ] Keep `twoFactorAuthentication` enabled with confirm options
+
+- [ ] **Task 2: Add User Model Helper Methods** (AC: 5, 6)
+ - [ ] Add `isAdmin(): bool` method to `app/Models/User.php`
+ - [ ] Add `isClient(): bool` method to `app/Models/User.php`
+ - [ ] Add `isIndividual(): bool` method to `app/Models/User.php`
+ - [ ] Add `isCompany(): bool` method to `app/Models/User.php`
+
+- [ ] **Task 3: Create Custom Middleware** (AC: 10, 15, 17)
+ - [ ] Create `app/Http/Middleware/EnsureUserIsAdmin.php`
+ - [ ] Create `app/Http/Middleware/EnsureUserIsActive.php`
+ - [ ] Register middleware aliases in `bootstrap/app.php` as `admin` and `active`
+ - [ ] Add `SetLocale` middleware to web group (for bilingual support)
+
+- [ ] **Task 4: Create Login Volt Component** (AC: 1, 2, 8, 12, 18, 19)
+ - [ ] Create `resources/views/livewire/auth/login.blade.php` as class-based Volt component
+ - [ ] Implement form with email and password fields using Flux UI components
+ - [ ] Add remember me checkbox
+ - [ ] Add CSRF token via `@csrf` or Livewire handling
+ - [ ] Display validation errors in current locale
+ - [ ] Add language switcher or respect current locale
+
+- [ ] **Task 5: Configure Login Redirect Logic** (AC: 13, 14)
+ - [ ] Update `FortifyServiceProvider` to set custom login view
+ - [ ] Create `app/Actions/Fortify/RedirectIfAuthenticated.php` or configure in `AuthenticatedSessionController`
+ - [ ] Implement redirect logic: admin → `/admin/dashboard`, client → `/client/dashboard`
+ - [ ] Create placeholder routes for dashboards (return simple "Dashboard coming soon" view)
+ - [ ] Implement logout redirect to login page
+
+- [ ] **Task 6: Implement Session and Rate Limiting** (AC: 3, 4)
+ - [ ] Set `SESSION_LIFETIME=120` in `.env` (2 hours)
+ - [ ] Verify Fortify's built-in rate limiting (5 attempts per minute)
+ - [ ] Ensure rate limit error message uses translation key
+
+- [ ] **Task 7: Implement Login Attempt Logging** (AC: 16)
+ - [ ] Create listener for `Illuminate\Auth\Events\Failed` event
+ - [ ] Log failed attempts to `admin_logs` table with IP address
+ - [ ] Register listener in `EventServiceProvider` or `AppServiceProvider`
+
+- [ ] **Task 8: Implement Deactivated User Check** (AC: 17)
+ - [ ] Add check in `EnsureUserIsActive` middleware
+ - [ ] Or customize Fortify's `authenticateUsing` callback to reject deactivated users
+ - [ ] Return bilingual error message for deactivated accounts
+
+- [ ] **Task 9: Write Tests** (AC: 20)
+ - [ ] Create `tests/Feature/Auth/LoginTest.php` with all login flow tests
+ - [ ] Create `tests/Feature/Auth/AuthorizationTest.php` for middleware tests
+ - [ ] Create `tests/Unit/Models/UserHelperMethodsTest.php` for isAdmin/isClient tests
+ - [ ] Run all tests and ensure they pass
+
+- [ ] **Task 10: Final Verification** (AC: 21)
+ - [ ] Run `vendor/bin/pint` to format code
+ - [ ] Verify no security vulnerabilities (CSRF, session fixation, etc.)
+ - [ ] Test full login flow in browser for both admin and client users
+
+## Dev Notes
+
+### Relevant Source Tree
+```
+app/
+├── Actions/
+│ └── Fortify/ # Existing - authentication logic
+│ ├── CreateNewUser.php # Existing
+│ ├── ResetUserPassword.php # Existing
+│ └── UpdateUserPassword.php # Existing
+├── Http/
+│ └── Middleware/ # Create these
+│ ├── SetLocale.php
+│ ├── EnsureUserIsAdmin.php
+│ └── EnsureUserIsActive.php
+├── Models/
+│ └── User.php # Existing - add helper methods
+├── Providers/
+│ └── FortifyServiceProvider.php # Existing - configure views
+bootstrap/
+└── app.php # Register middleware aliases
+config/
+├── fortify.php # Configure features
+└── session.php # Session configuration
+resources/
+└── views/
+ └── livewire/
+ └── auth/
+ └── login.blade.php # Create - Volt component
+lang/
+├── ar/
+│ └── auth.php # Translation strings
+└── en/
+ └── auth.php # Translation strings
+tests/
+├── Feature/
+│ └── Auth/
+│ ├── LoginTest.php
+│ └── AuthorizationTest.php
+└── Unit/
+ └── Models/
+ └── UserHelperMethodsTest.php
+```
+
+### User Model Helper Methods (Add to User.php)
+```php
+// app/Models/User.php
+use App\Enums\UserType;
+use App\Enums\UserStatus;
+
+public function isAdmin(): bool
+{
+ return $this->user_type === UserType::Admin;
+}
+
+public function isClient(): bool
+{
+ return in_array($this->user_type, [UserType::Individual, UserType::Company]);
+}
+
+public function isIndividual(): bool
+{
+ return $this->user_type === UserType::Individual;
+}
+
+public function isCompany(): bool
+{
+ return $this->user_type === UserType::Company;
+}
+
+public function isActive(): bool
+{
+ return $this->status === UserStatus::Active;
+}
+```
+
+### Middleware Implementation (from Architecture Section 7.3)
+```php
+// app/Http/Middleware/EnsureUserIsAdmin.php
+class EnsureUserIsAdmin
+{
+ public function handle(Request $request, Closure $next): Response
+ {
+ if (!$request->user()?->isAdmin()) {
+ abort(403, __('messages.unauthorized'));
+ }
+
+ return $next($request);
+ }
+}
+
+// app/Http/Middleware/EnsureUserIsActive.php
+class EnsureUserIsActive
+{
+ public function handle(Request $request, Closure $next): Response
+ {
+ if ($request->user()?->status === UserStatus::Deactivated) {
+ Auth::logout();
+ $request->session()->invalidate();
+ $request->session()->regenerateToken();
+
+ return redirect()->route('login')
+ ->with('error', __('auth.account_deactivated'));
+ }
+
+ return $next($request);
+ }
+}
+```
+
+### Middleware Registration (bootstrap/app.php)
+```php
+// bootstrap/app.php
+->withMiddleware(function (Middleware $middleware) {
+ $middleware->web(append: [
+ \App\Http\Middleware\SetLocale::class,
+ ]);
+
+ $middleware->alias([
+ 'admin' => \App\Http\Middleware\EnsureUserIsAdmin::class,
+ 'active' => \App\Http\Middleware\EnsureUserIsActive::class,
+ ]);
+})
+```
### Fortify Configuration
```php
// config/fortify.php
'features' => [
- // Features::registration(), // DISABLED
+ // Features::registration(), // DISABLED - admin creates accounts
Features::resetPasswords(),
Features::emailVerification(),
Features::updateProfileInformation(),
Features::updatePasswords(),
+ Features::twoFactorAuthentication([
+ 'confirm' => true,
+ 'confirmPassword' => true,
+ ]),
],
```
-### Custom Views Setup
+### FortifyServiceProvider Setup
```php
-// FortifyServiceProvider boot()
-Fortify::loginView(fn () => view('auth.login'));
-// No registerView - registration disabled
+// app/Providers/FortifyServiceProvider.php
+public function boot(): void
+{
+ // Custom login view
+ Fortify::loginView(fn () => view('livewire.auth.login'));
+
+ // Custom authentication logic (optional - for deactivated check)
+ Fortify::authenticateUsing(function (Request $request) {
+ $user = User::where('email', $request->email)->first();
+
+ if ($user &&
+ Hash::check($request->password, $user->password) &&
+ $user->status === UserStatus::Active) {
+ return $user;
+ }
+
+ return null;
+ });
+}
```
-### Role Implementation
-- Use `user_type` column: 'admin', 'individual', 'company'
-- Admin check: `$user->user_type === 'admin'`
-- Client check: `in_array($user->user_type, ['individual', 'company'])`
-
-### Gate Definitions
+### Login Redirect Logic
```php
-// AuthServiceProvider or AppServiceProvider
-Gate::define('admin', fn (User $user) => $user->user_type === 'admin');
-Gate::define('client', fn (User $user) => $user->user_type !== 'admin');
+// app/Providers/FortifyServiceProvider.php or custom response
+// After successful login, redirect based on role:
+if ($user->isAdmin()) {
+ return redirect('/admin/dashboard');
+}
+return redirect('/client/dashboard');
```
-### Middleware
-- `auth` - Require authentication
-- `can:admin` - Require admin role
-- Custom middleware for session timeout if needed
+### Placeholder Dashboard Routes
+```php
+// routes/web.php
+Route::middleware(['auth', 'active'])->group(function () {
+ // Admin routes
+ Route::middleware('admin')->prefix('admin')->group(function () {
+ Route::view('/dashboard', 'livewire.admin.dashboard-placeholder')
+ ->name('admin.dashboard');
+ });
+
+ // Client routes
+ Route::prefix('client')->group(function () {
+ Route::view('/dashboard', 'livewire.client.dashboard-placeholder')
+ ->name('client.dashboard');
+ });
+});
+```
### Environment Configuration
```env
@@ -93,56 +303,143 @@ SESSION_LIFETIME=120 # 2 hours in minutes
SESSION_EXPIRE_ON_CLOSE=false
```
+### Translation Keys (lang/en/auth.php and lang/ar/auth.php)
+```php
+// lang/en/auth.php
+return [
+ 'failed' => 'These credentials do not match our records.',
+ 'password' => 'The provided password is incorrect.',
+ 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
+ 'account_deactivated' => 'Your account has been deactivated. Please contact the administrator.',
+];
+
+// lang/ar/auth.php
+return [
+ 'failed' => 'بيانات الاعتماد هذه لا تتطابق مع سجلاتنا.',
+ 'password' => 'كلمة المرور المقدمة غير صحيحة.',
+ 'throttle' => 'محاولات تسجيل دخول كثيرة جداً. يرجى المحاولة مرة أخرى بعد :seconds ثانية.',
+ 'account_deactivated' => 'تم تعطيل حسابك. يرجى الاتصال بالمسؤول.',
+];
+```
+
### Edge Case Behavior
**Rate Limiting (5 attempts per minute):**
-- After 5 failed attempts, show message: "Too many login attempts. Please try again in 60 seconds."
-- Use bilingual message from translation files
-- Log rate limit events for security monitoring
+- Fortify handles this automatically via `RateLimiter`
+- After 5 failed attempts, shows throttle message in current locale
+- Lockout duration: 60 seconds
**Session Timeout (2 hours inactivity):**
+- Configured via `SESSION_LIFETIME=120`
- When session expires, redirect to login page
-- Show flash message: "Your session has expired. Please log in again."
-- Preserve intended URL for redirect after re-authentication
+- Intended URL preserved for redirect after re-authentication
**Deactivated Account Login Attempt:**
-- Check `status` field during authentication
-- If `status === 'deactivated'`, reject login with message: "Your account has been deactivated. Please contact the administrator."
+- Check in `Fortify::authenticateUsing()` callback
+- Reject with `auth.account_deactivated` message
+- User never gets authenticated
-## Test Scenarios
+### Flux UI Components for Login Form
+```blade
+
+
+
+{{ __('Login') }}
+```
-### Feature Tests (tests/Feature/Auth/)
+## Testing
+
+### Test Location
+- Feature tests: `tests/Feature/Auth/`
+- Unit tests: `tests/Unit/Models/`
+
+### Testing Framework
+Pest 4 with Volt testing support
+
+### Feature Tests (tests/Feature/Auth/LoginTest.php)
**Login Flow:**
-- [ ] `test_login_page_renders_correctly` - Login page displays in default language
-- [ ] `test_user_can_login_with_valid_credentials` - Valid credentials redirect to dashboard
-- [ ] `test_admin_redirects_to_admin_dashboard` - Admin user goes to admin dashboard
-- [ ] `test_client_redirects_to_client_dashboard` - Client user goes to client dashboard
-- [ ] `test_invalid_credentials_show_error` - Wrong password shows bilingual error
-- [ ] `test_nonexistent_user_shows_error` - Unknown email shows generic error (no user enumeration)
-- [ ] `test_deactivated_user_cannot_login` - Deactivated account rejected with message
+- [ ] `test_login_page_renders_correctly` - Login page displays
+- [ ] `test_user_can_login_with_valid_credentials` - Valid credentials authenticate
+- [ ] `test_admin_redirects_to_admin_dashboard` - Admin → `/admin/dashboard`
+- [ ] `test_client_redirects_to_client_dashboard` - Client → `/client/dashboard`
+- [ ] `test_invalid_credentials_show_error` - Wrong password shows error
+- [ ] `test_nonexistent_user_shows_error` - Unknown email shows generic error (no enumeration)
+- [ ] `test_deactivated_user_cannot_login` - Deactivated account rejected
**Rate Limiting:**
- [ ] `test_rate_limiting_blocks_after_five_attempts` - 6th attempt blocked
-- [ ] `test_rate_limit_message_is_bilingual` - Error message respects locale
-- [ ] `test_rate_limit_resets_after_one_minute` - Can retry after cooldown
+- [ ] `test_rate_limit_resets_after_cooldown` - Can retry after 60 seconds
**Session Management:**
-- [ ] `test_logout_clears_session` - Logout destroys session data
-- [ ] `test_remember_me_extends_session` - Remember token works (if implemented)
+- [ ] `test_logout_clears_session` - Logout destroys session
+- [ ] `test_authenticated_user_cannot_access_login_page` - Redirect to dashboard
-**Authorization:**
-- [ ] `test_admin_can_access_admin_routes` - Admin passes `can:admin` middleware
-- [ ] `test_client_cannot_access_admin_routes` - Client gets 403 on admin routes
-- [ ] `test_unauthenticated_user_redirected_to_login` - Guest redirected from protected routes
+### Feature Tests (tests/Feature/Auth/AuthorizationTest.php)
-### Unit Tests (tests/Unit/)
+**Middleware:**
+- [ ] `test_admin_can_access_admin_routes` - Admin passes `admin` middleware
+- [ ] `test_client_cannot_access_admin_routes` - Client gets 403
+- [ ] `test_unauthenticated_user_redirected_to_login` - Guest redirected
+- [ ] `test_deactivated_user_logged_out_on_request` - Active middleware works
-**Gate Definitions:**
-- [ ] `test_admin_gate_returns_true_for_admin_user` - Gate check passes
-- [ ] `test_admin_gate_returns_false_for_client_user` - Gate check fails
-- [ ] `test_client_gate_returns_true_for_individual_user` - Client gate passes
-- [ ] `test_client_gate_returns_true_for_company_user` - Client gate passes
+### Unit Tests (tests/Unit/Models/UserHelperMethodsTest.php)
+
+**Helper Methods:**
+- [ ] `test_isAdmin_returns_true_for_admin_user`
+- [ ] `test_isAdmin_returns_false_for_client_user`
+- [ ] `test_isClient_returns_true_for_individual_user`
+- [ ] `test_isClient_returns_true_for_company_user`
+- [ ] `test_isClient_returns_false_for_admin_user`
+- [ ] `test_isActive_returns_true_for_active_user`
+- [ ] `test_isActive_returns_false_for_deactivated_user`
+
+### Test Patterns
+```php
+// tests/Feature/Auth/LoginTest.php
+use App\Models\User;
+use App\Enums\UserType;
+use App\Enums\UserStatus;
+use Livewire\Volt\Volt;
+
+test('admin redirects to admin dashboard after login', function () {
+ $admin = User::factory()->create([
+ 'user_type' => UserType::Admin,
+ 'status' => UserStatus::Active,
+ ]);
+
+ $response = $this->post('/login', [
+ 'email' => $admin->email,
+ 'password' => 'password',
+ ]);
+
+ $response->assertRedirect('/admin/dashboard');
+ $this->assertAuthenticatedAs($admin);
+});
+
+test('deactivated user cannot login', function () {
+ $user = User::factory()->create([
+ 'status' => UserStatus::Deactivated,
+ ]);
+
+ $response = $this->post('/login', [
+ 'email' => $user->email,
+ 'password' => 'password',
+ ]);
+
+ $this->assertGuest();
+});
+
+test('client cannot access admin routes', function () {
+ $client = User::factory()->create([
+ 'user_type' => UserType::Individual,
+ ]);
+
+ $this->actingAs($client)
+ ->get('/admin/dashboard')
+ ->assertForbidden();
+});
+```
## Definition of Done
@@ -152,22 +449,33 @@ SESSION_EXPIRE_ON_CLOSE=false
- [ ] Deactivated users cannot log in
- [ ] Rate limiting prevents brute force (5 attempts/minute)
- [ ] Session expires after 2 hours inactivity
-- [ ] Admin routes protected from clients (403 response)
-- [ ] All Feature and Unit tests from "Test Scenarios" section pass
-- [ ] Code formatted with Pint
+- [ ] Admin routes protected by `admin` middleware (403 for clients)
+- [ ] Failed login attempts logged to `admin_logs`
+- [ ] All Feature and Unit tests pass
+- [ ] Code formatted with `vendor/bin/pint`
## Dependencies
-- **Story 1.1:** Database schema - creates `users` table with `user_type` enum (`admin`, `individual`, `company`), `status` enum (`active`, `deactivated`), and `preferred_language` enum (`ar`, `en`)
-- **Story 1.3:** Bilingual infrastructure (for login page translations)
+- **Story 1.1:** Database schema - provides `users` table with `user_type` enum, `status` enum, and `preferred_language` field
+- **Story 1.3:** Bilingual infrastructure - provides translation files and locale switching (can be developed in parallel)
## Risk Assessment
-- **Primary Risk:** Security misconfiguration
-- **Mitigation:** Use Laravel's built-in security features, no custom auth logic
-- **Rollback:** Restore Fortify defaults
+| Risk | Impact | Likelihood | Mitigation |
+|------|--------|------------|------------|
+| Security misconfiguration | High | Low | Use Laravel's built-in security features |
+| Rate limiting bypass | Medium | Low | Use Fortify's built-in rate limiter |
+| Session hijacking | High | Low | Use secure session configuration |
+| Middleware registration issues | Low | Medium | Follow architecture Section 7.4 exactly |
-## Estimation
+### Rollback Plan
+- Restore default Fortify configuration
+- Remove custom middleware
+- Revert User model changes
-**Complexity:** Medium
-**Estimated Effort:** 3-4 hours
+## Change Log
+
+| Date | Version | Description | Author |
+|------|---------|-------------|--------|
+| Dec 21, 2025 | 1.0 | Initial story draft | SM Agent |
+| Dec 21, 2025 | 2.0 | Complete rewrite: Added Status, Tasks/Subtasks, Dev Notes with Source Tree, fixed middleware naming (admin vs can:admin), fixed redirect paths (/client/dashboard), added User helper methods, aligned with architecture Section 7, added Change Log | Validation Task |