# Deployment Checklist - Mandatory Password Change Feature

**Status**: Ready for Live Deployment  
**Date**: September 1, 2026  
**Feature**: Mandatory password change on first client login

---

## 📋 Files Changed/Created

### 1. **Database Migration** (MUST RUN)
**File**: `database/migrations/2026_09_01_141422_add_password_changed_to_users.php`

**What it does**: Adds `password_changed_at` column to users table

**Action**: 
```bash
php artisan migrate
```

**SQL Generated**:
```sql
ALTER TABLE users ADD password_changed_at TIMESTAMP NULL AFTER password;
```

---

### 2. **New Middleware File** (COPY TO SERVER)
**File**: `app/Http/Middleware/CheckPasswordChanged.php`

**Size**: ~26 lines  
**Purpose**: Intercepts client requests and redirects first-time users to change password  
**Action**: Copy file as-is to live server

---

### 3. **Controller Changes** (COPY TO SERVER)
**File**: `app/Http/Controllers/ClientController.php`

**Changes Made**:
- Added method: `showChangePassword()` (Lines: ~15 lines)
- Added method: `updatePassword()` (Lines: ~40 lines)

**Location**: End of file, before final closing brace

**Action**: Copy updated file to live server

---

### 4. **Model Changes** (COPY TO SERVER)
**File**: `app/Models/User.php`

**Changes Made**:
- Line 50: Added `'password_changed_at'` to `$fillable` array
- Line 73: Added `'password_changed_at' => 'datetime'` to `casts` array

**Action**: Copy updated file to live server

---

### 5. **Routes Changes** (COPY TO SERVER)
**File**: `routes/web.php`

**Changes Made**:
- Line 1098: Updated middleware array to include `\App\Http\Middleware\CheckPasswordChanged::class`
  - From: `Route::prefix('client')->middleware(['auth', 'role:client'])->group(function () {`
  - To: `Route::prefix('client')->middleware(['auth', 'role:client', \App\Http\Middleware\CheckPasswordChanged::class])->group(function () {`

- Lines 1106-1108: Added password change routes
  ```php
  // Password Change Routes - Mandatory on first login
  Route::get('/change-password', [ClientController::class, 'showChangePassword'])->name('client.change-password');
  Route::post('/change-password', [ClientController::class, 'updatePassword'])->name('client.update-password');
  ```

**Action**: Copy updated file to live server

---

### 6. **View/UI File** (COPY TO SERVER)
**File**: `resources/views/client/change-password.blade.php`

**Size**: ~168 lines  
**Purpose**: Beautiful password change form for clients  
**Features**:
- Warning alert on first login
- Current password field
- New password field with visibility toggle
- Confirm password field with real-time match checking
- Password requirements indicator
- Error message handling

**Action**: Copy file as-is to live server

---

## 🚀 Deployment Steps

### Step 1: Backup Database (RECOMMENDED)
```bash
# Create backup before running migration
mysqldump -u [username] -p [database_name] > backup_$(date +%Y%m%d_%H%M%S).sql
```

### Step 2: Copy Files to Live Server
Copy all files listed below to live server:

```
1. app/Http/Middleware/CheckPasswordChanged.php (NEW FILE)
2. app/Http/Controllers/ClientController.php (UPDATED)
3. app/Models/User.php (UPDATED)
4. routes/web.php (UPDATED)
5. resources/views/client/change-password.blade.php (NEW FILE)
6. database/migrations/2026_09_01_141422_add_password_changed_to_users.php (NEW FILE)
```

### Step 3: Run Migration on Live Server
```bash
cd /path/to/will
php artisan migrate
```

**Output should show:**
```
2026_09_01_141422_add_password_changed_to_users ... DONE
```

### Step 4: Clear Cache (IMPORTANT)
```bash
php artisan cache:clear
php artisan config:cache
php artisan route:cache
php artisan view:clear
```

### Step 5: Verify Routes Registered
```bash
php artisan route:list | grep change-password
```

**Should output:**
```
GET|HEAD  client/change-password                    client.change-password
POST      client/change-password                    client.update-password
```

### Step 6: Test on Live
1. Create a test client
2. Log in with email + IC number
3. Should redirect to change password page
4. Change password
5. Log out
6. Log in with new password
7. Should have full portal access

---

## ✅ File Checklist for Deployment

| File | Type | Status | Action |
|------|------|--------|--------|
| `database/migrations/2026_09_01_141422_add_password_changed_to_users.php` | NEW | ✅ Ready | Copy & Run Migration |
| `app/Http/Middleware/CheckPasswordChanged.php` | NEW | ✅ Ready | Copy to Server |
| `app/Http/Controllers/ClientController.php` | UPDATED | ✅ Ready | Copy to Server |
| `app/Models/User.php` | UPDATED | ✅ Ready | Copy to Server |
| `routes/web.php` | UPDATED | ✅ Ready | Copy to Server |
| `resources/views/client/change-password.blade.php` | NEW | ✅ Ready | Copy to Server |

---

## 📊 Database Changes Summary

**Table**: `users`

**New Column Added**:
```sql
password_changed_at TIMESTAMP NULL
```

**Constraints**:
- Type: TIMESTAMP
- Nullable: YES (NULL = password never changed)
- Position: After `password` column
- Index: No index needed

**Impact**:
- Non-breaking change (all existing users' `password_changed_at` will be NULL)
- No data loss
- Can be rolled back if needed

---

## 🔄 Rollback Plan (If Needed)

**If something goes wrong**:

### Rollback Database
```bash
php artisan migrate:rollback --step=1
```

### Rollback Files
Simply restore previous versions of:
- `app/Http/Controllers/ClientController.php`
- `app/Models/User.php`
- `routes/web.php`

### Clean Up
```bash
rm app/Http/Middleware/CheckPasswordChanged.php
rm resources/views/client/change-password.blade.php
rm database/migrations/2026_09_01_141422_add_password_changed_to_users.php
```

---

## 🧪 Testing Checklist

After deployment, verify:

- [ ] Database migration ran successfully
- [ ] No errors in Laravel logs
- [ ] Routes registered correctly
- [ ] New client can be created
- [ ] First-time client login redirects to change password
- [ ] Password change form loads correctly
- [ ] Current password validation works
- [ ] Strong password validation works
- [ ] Password confirmation matching works
- [ ] Password change saves to database
- [ ] `password_changed_at` timestamp is set
- [ ] Subsequent login doesn't redirect
- [ ] Old password no longer works
- [ ] New password works for login

---

## 📝 Important Notes

1. **No Downtime Required**: Changes are backward compatible
2. **Existing Users**: Won't be affected (password_changed_at will be NULL, but they already have changed passwords)
3. **New Clients**: Will be forced to change password on first login
4. **Database Backups**: Highly recommended before running migration
5. **Clear Cache**: MUST run cache clear commands after deployment

---

## 🆘 Troubleshooting

**Q: Migration fails with "column already exists"**
- A: Column may have been added manually. Check with: `DESC users;`

**Q: Routes not showing after deployment**
- A: Run: `php artisan route:cache` to rebuild route cache

**Q: Clients not redirected to change password**
- A: Check middleware is in routes/web.php and cache is cleared

**Q: "Password confirmation does not match" error**
- A: Normal - client needs to re-enter matching password

**Q: Database rollback needed**
- A: Run: `php artisan migrate:rollback --step=1`

---

## 📞 Support Information

If issues occur during deployment:

1. Check `storage/logs/laravel.log` for errors
2. Verify all files were copied correctly
3. Ensure migration ran: `php artisan migrate:status`
4. Check middleware is registered: `grep CheckPasswordChanged routes/web.php`
5. Verify column exists: `DESC users;`

---

## 🎯 Success Criteria

Deployment is successful when:

✅ All files are copied to live server  
✅ Migration runs without errors  
✅ Routes are registered correctly  
✅ New clients forced to change password on first login  
✅ Password change works without errors  
✅ Existing clients not affected  
✅ No errors in Laravel logs  

---

