reviewd and fixed epic 1 & 2
This commit is contained in:
@@ -11,10 +11,17 @@ So that **I can manage the full lifecycle of client relationships**.
|
||||
## Story Context
|
||||
|
||||
### Existing System Integration
|
||||
- **Integrates with:** Users table, consultations, timelines, notifications
|
||||
- **Technology:** Livewire Volt, confirmation modals
|
||||
- **Follows pattern:** Soft deactivation, hard deletion with cascade
|
||||
- **Touch points:** User model, all related models
|
||||
- **Integrates with:** Users table, consultations, timelines, notifications, sessions
|
||||
- **Technology:** Livewire Volt (class-based), Flux UI modals, Pest tests
|
||||
- **Follows pattern:** Same admin action patterns as Story 2.1/2.2, soft deactivation via status field, hard deletion with cascade
|
||||
- **Touch points:** User model, AdminLog model, FortifyServiceProvider (authentication check)
|
||||
- **PRD Reference:** Section 5.3 (User Management System - Account Lifecycle)
|
||||
- **Key Files to Create/Modify:**
|
||||
- `resources/views/livewire/admin/users/partials/` - Lifecycle action components
|
||||
- `app/Notifications/` - Reactivation and password reset notifications
|
||||
- `app/Providers/FortifyServiceProvider.php` - Add deactivation check to authenticateUsing
|
||||
- `app/Models/User.php` - Add lifecycle methods and deleting event
|
||||
- `tests/Feature/Admin/AccountLifecycleTest.php` - Feature tests
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
@@ -69,6 +76,19 @@ So that **I can manage the full lifecycle of client relationships**.
|
||||
|
||||
## Technical Notes
|
||||
|
||||
### Files to Create
|
||||
```
|
||||
resources/views/livewire/admin/users/
|
||||
├── partials/
|
||||
│ ├── lifecycle-actions.blade.php # Deactivate/Reactivate/Delete action buttons
|
||||
│ └── password-reset-modal.blade.php # Password reset modal component
|
||||
app/Notifications/
|
||||
├── AccountReactivatedNotification.php
|
||||
└── PasswordResetByAdminNotification.php
|
||||
tests/Feature/Admin/
|
||||
└── AccountLifecycleTest.php
|
||||
```
|
||||
|
||||
### User Status Management
|
||||
```php
|
||||
// User model
|
||||
@@ -252,6 +272,142 @@ new class extends Component {
|
||||
</flux:modal>
|
||||
```
|
||||
|
||||
### Edge Cases & Error Handling
|
||||
- **Active sessions on deactivation:** Invalidate all user sessions when deactivated (use `DB::table('sessions')->where('user_id', $user->id)->delete()`)
|
||||
- **Deactivated user login attempt:** Show bilingual message: "Your account has been deactivated. Please contact the administrator."
|
||||
- **Delete with related data:** Cascade deletion handles consultations/timelines automatically via model `deleting` event
|
||||
- **Delete confirmation mismatch:** Display validation error, do not proceed with deletion
|
||||
- **Password reset email failure:** Queue the email, log failure, show success message (email queued)
|
||||
- **Reactivation email failure:** Queue the email, log failure, still complete reactivation
|
||||
|
||||
### Session Invalidation on Deactivation
|
||||
```php
|
||||
// Add to deactivate() method in Volt component
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
public function deactivate(): void
|
||||
{
|
||||
$this->user->deactivate();
|
||||
|
||||
// Invalidate all active sessions for this user
|
||||
DB::table('sessions')
|
||||
->where('user_id', $this->user->id)
|
||||
->delete();
|
||||
|
||||
// Log action...
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
### Test File Location
|
||||
`tests/Feature/Admin/AccountLifecycleTest.php`
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
#### Deactivation Tests
|
||||
- [ ] Admin can deactivate an active user
|
||||
- [ ] Deactivated user cannot login (returns null from authenticateUsing)
|
||||
- [ ] Deactivated user shows visual indicator in user list
|
||||
- [ ] User sessions are invalidated on deactivation
|
||||
- [ ] AdminLog entry created with old/new status values
|
||||
- [ ] Deactivation preserves all user data (consultations, timelines intact)
|
||||
|
||||
#### Reactivation Tests
|
||||
- [ ] Admin can reactivate a deactivated user
|
||||
- [ ] Reactivated user can login successfully
|
||||
- [ ] Reactivated user status changes to 'active'
|
||||
- [ ] Email notification queued on reactivation
|
||||
- [ ] AdminLog entry created for reactivation
|
||||
|
||||
#### Permanent Deletion Tests
|
||||
- [ ] Delete button shows danger styling
|
||||
- [ ] Delete requires typing user email for confirmation
|
||||
- [ ] Incorrect email confirmation shows validation error
|
||||
- [ ] Successful deletion removes user record permanently
|
||||
- [ ] Cascade deletion removes user's consultations
|
||||
- [ ] Cascade deletion removes user's timelines and timeline_updates
|
||||
- [ ] Cascade deletion removes user's notifications
|
||||
- [ ] AdminLog entry preserved after user deletion (for audit trail)
|
||||
- [ ] Redirect to users index after successful deletion
|
||||
|
||||
#### Password Reset Tests
|
||||
- [ ] Admin can reset user password with random generation
|
||||
- [ ] New password meets minimum requirements (8+ characters)
|
||||
- [ ] Password reset email sent to user with new credentials
|
||||
- [ ] AdminLog entry created for password reset
|
||||
- [ ] User can login with new password
|
||||
|
||||
#### Authorization Tests
|
||||
- [ ] Non-admin users cannot access lifecycle actions
|
||||
- [ ] Admin cannot deactivate their own account
|
||||
- [ ] Admin cannot delete their own account
|
||||
|
||||
#### Bilingual Tests
|
||||
- [ ] Confirmation dialogs display in Arabic when locale is 'ar'
|
||||
- [ ] Confirmation dialogs display in English when locale is 'en'
|
||||
- [ ] Success/error messages respect user's preferred language
|
||||
|
||||
### Testing Approach
|
||||
```php
|
||||
use App\Models\User;
|
||||
use App\Models\AdminLog;
|
||||
use Livewire\Volt\Volt;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use App\Notifications\AccountReactivatedNotification;
|
||||
|
||||
test('admin can deactivate active user', function () {
|
||||
$admin = User::factory()->admin()->create();
|
||||
$client = User::factory()->individual()->create(['status' => 'active']);
|
||||
|
||||
Volt::actingAs($admin)
|
||||
->test('admin.users.show', ['user' => $client])
|
||||
->call('deactivate')
|
||||
->assertHasNoErrors();
|
||||
|
||||
expect($client->fresh()->status)->toBe('deactivated');
|
||||
expect(AdminLog::where('action_type', 'deactivate')->exists())->toBeTrue();
|
||||
});
|
||||
|
||||
test('deactivated user cannot login', function () {
|
||||
$user = User::factory()->create(['status' => 'deactivated']);
|
||||
|
||||
$this->post('/login', [
|
||||
'email' => $user->email,
|
||||
'password' => 'password',
|
||||
])->assertSessionHasErrors();
|
||||
|
||||
$this->assertGuest();
|
||||
});
|
||||
|
||||
test('delete requires email confirmation', function () {
|
||||
$admin = User::factory()->admin()->create();
|
||||
$client = User::factory()->individual()->create();
|
||||
|
||||
Volt::actingAs($admin)
|
||||
->test('admin.users.show', ['user' => $client])
|
||||
->set('deleteConfirmation', 'wrong@email.com')
|
||||
->call('delete')
|
||||
->assertHasErrors(['deleteConfirmation']);
|
||||
|
||||
expect(User::find($client->id))->not->toBeNull();
|
||||
});
|
||||
|
||||
test('reactivation sends email notification', function () {
|
||||
Notification::fake();
|
||||
|
||||
$admin = User::factory()->admin()->create();
|
||||
$client = User::factory()->individual()->create(['status' => 'deactivated']);
|
||||
|
||||
Volt::actingAs($admin)
|
||||
->test('admin.users.show', ['user' => $client])
|
||||
->call('reactivate')
|
||||
->assertHasNoErrors();
|
||||
|
||||
Notification::assertSentTo($client, AccountReactivatedNotification::class);
|
||||
});
|
||||
```
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] Deactivate prevents login but preserves data
|
||||
@@ -268,10 +424,25 @@ new class extends Component {
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Story 2.1:** Individual client management
|
||||
### Required Before Implementation
|
||||
- **Story 1.1:** Database schema must include:
|
||||
- `users.status` column (enum: 'active', 'deactivated')
|
||||
- `users.user_type` column (enum: 'individual', 'company', 'admin')
|
||||
- `admin_logs` table with columns: `admin_id`, `action_type`, `target_type`, `target_id`, `old_values`, `new_values`, `ip_address`
|
||||
- **Story 1.2:** Authentication system with admin role, AdminLog model
|
||||
- **Story 2.1:** Individual client management (establishes CRUD patterns)
|
||||
- **Story 2.2:** Company client management
|
||||
- **Epic 3:** Consultations (cascade delete)
|
||||
- **Epic 4:** Timelines (cascade delete)
|
||||
|
||||
### Soft Dependencies (Can Be Empty/Stubbed)
|
||||
- **Epic 3:** Consultations table (cascade delete - can be empty if not yet implemented)
|
||||
- **Epic 4:** Timelines table (cascade delete - can be empty if not yet implemented)
|
||||
|
||||
### Notification Classes (Created in This Story)
|
||||
This story creates the following notification classes:
|
||||
- `App\Notifications\AccountReactivatedNotification` - Sent when account is reactivated
|
||||
- `App\Notifications\PasswordResetByAdminNotification` - Sent with new credentials after admin password reset
|
||||
|
||||
> **Note:** These are simple notifications. Full email infrastructure (templates, queuing) is handled in Epic 8. These notifications will use Laravel's default mail driver.
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
|
||||
Reference in New Issue
Block a user