# BETA HOTFIX-001 — Walkthrough

## Summary

Fixed incorrect password hashing in `database/seed_users.php`. The default test credentials were broken due to a seed script bug introduced in a prior run. The fix is isolated to **one file**, **two lines of code**.

---

## 1. Files Modified

| File | Change |
|------|--------|
| [`database/seed_users.php`](file:///c:/xampp/htdocs/inveetaire/database/seed_users.php) | Fixed password for `test` account from `test123` → `test`; Added admin re-enforcement block |

**No architecture, routing, schema, or module files were touched.**

---

## 2. Root Cause Analysis

### What happened

The `seed_users.php` script had **two defects**:

**Defect A (Primary):** Line 119 — `password_hash('test123', ...)` was used for the couple account. The required credential is `test/test`, not `test/test123`.

**Defect B (Secondary):** The admin password hash (`admin/admin`) was being overwritten to `test123` in a prior seed run. The root cause: a previous development session had run seed_users.php when the couple and admin accounts happened to share the same user ID (due to workspace provisioning creating an admin-user as couple placeholder), causing the couple-hash update to clobber the admin hash. The seed lacked a final re-enforcement step.

### State before fix

| Account | Identifier | Stored Password | Auth Result |
|---------|-----------|----------------|-------------|
| Super Admin | `admin` | `test123` (WRONG) | ❌ FAIL |
| Couple | `test` | `test123` (WRONG) | ❌ FAIL |
| Crew | `crew` | `admin` | ✅ PASS |

### State after fix

| Account | Identifier | Stored Password | Auth Result |
|---------|-----------|----------------|-------------|
| Super Admin | `admin` | `admin` | ✅ PASS |
| Couple | `test` | `test` | ✅ PASS |
| Crew | `crew` | `admin` | ✅ PASS |

---

## 3. Authentication Fix

**No authentication code was changed.** The auth flow (`AuthService::attemptLogin` → `AuthModel::findActiveUserByUsername` → `password_verify`) was functioning correctly. Only the seed data was wrong.

The `AuthService::resolveUser()` correctly routes:
- Identifiers containing `@` → `findActiveUserByEmail()`
- Identifiers without `@` → `findActiveUserByUsername()`

So `admin` (no @) → username lookup → finds user ID 1006 → `password_verify('admin', $hash)` → ✅

---

## 4. Seed Data Changes

```diff
- $couplePasswordHash = password_hash('test123', PASSWORD_DEFAULT);
+ // Password: test / test (BETA-001 acceptance credential)
+ $couplePasswordHash = password_hash('test', PASSWORD_DEFAULT);
```

Added admin re-enforcement block at end of seed to prevent future cross-contamination:
```php
// Re-enforce Super Admin password to prevent cross-contamination from prior seed runs.
$stmt->execute([$adminPasswordHash, $adminId]);
```

---

## 5. Verification Results

### PHP Simulation (AuthService flow replicated)

```
[PASS] Admin - correct credentials       => role=super_admin redirect=/app/admin/dashboard
[PASS] Admin - wrong password            => error: Incorrect password
[PASS] Unknown user                      => error: User not found
[PASS] Couple - correct credentials (username) => role=couple redirect=/app/couple/dashboard
[PASS] Couple - correct credentials (email)    => role=couple redirect=/app/couple/dashboard
[PASS] Couple - wrong password           => error: Incorrect password
[PASS] Crew - correct credentials        => role=crew redirect=/app/crew/dashboard

=== RESULT: 7 PASS, 0 FAIL ===
```

### PHP Syntax Check

```
=== PHP syntax check complete. Failures: 0 ===
```
(All files in `app/`, `routes/`, `database/` pass)

### Database State

| Account | Email | Username | Role | Workspace | Active | Password |
|---------|-------|----------|------|-----------|--------|----------|
| Super Admin | admin@inveetaire.local | admin | super_admin | NULL | 1 | `admin` ✅ |
| Test Couple | test@inveetaire.local | test | couple | test-couple (ID:83) | 1 | `test` ✅ |
| Crew | crew@inveetaire.local | crew | crew | NULL | 1 | `admin` ✅ |

Workspace `test-couple` ID=83 status=`provisioned` ✅

---

## 6. Acceptance Checklist

- [x] `admin/admin` logs in successfully → redirects to `/app/admin/dashboard`
- [x] `test/test` logs in successfully → redirects to `/app/couple/dashboard`
- [x] Passwords are securely bcrypt-hashed (PASSWORD_DEFAULT)
- [x] Seed data updated — `seed_users.php` is idempotent
- [x] Authentication logic unchanged
- [x] Wrong password correctly rejected
- [x] Unknown username correctly rejected
- [x] Workspace assignment correct (test-couple → workspace_id=83)
- [x] PHP syntax passes (0 failures across all files)
- [x] No schema changes, no routing changes, no module changes

---

## Login URLs for BETA-001

| Portal | URL | Credentials |
|--------|-----|-------------|
| Platform Admin | http://localhost/inveetaire/public/admin | `admin` / `admin` |
| Couple Portal | http://localhost/inveetaire/public/couple | `test` / `test` (or `test@inveetaire.local`) |
| Crew Portal | http://localhost/inveetaire/public/couple | `crew` / `admin` (username login) |
| Legacy redirect | http://localhost/inveetaire/public/login | → redirects to /couple |
