# Planning Document: Task #11 - Implement Account Recovery

**Date:** 2025-01-11
**Status:** ⏸️ TABLED - Deferred for Future Implementation
**Estimated Effort:** 1 week
**Priority:** Medium (post-launch enhancement)

---

## Decision Summary

**Status:** Task #11 is **TABLED** for now.

**Rationale:**
- Core sign in/registration features are complete
- OAuth providers (Google/Apple) handle most account recovery scenarios
- Can be added as enhancement after launch
- Should be scoped more specifically based on actual user needs

**Potential Relevance to Sign In/Registration:**
- ✅ Password reset (if we add password auth in future)
- ✅ Account unlock after suspicious activity
- ✅ Email verification recovery
- ✅ Handling locked accounts due to failed payments
- ✅ OAuth provider access issues

**Next Steps:**
1. Monitor user support tickets post-launch
2. Identify common account recovery scenarios
3. Prioritize features based on actual needs
4. Revisit this document when ready to implement

---

## Task Definition

Implement comprehensive account recovery workflows for dealers who have lost access to their accounts.

### Current State

**What's Already Handled:**

1. **OAuth Provider Recovery**
   - Google and Apple handle password resets
   - Dealers recover via "Forgot Password" on Google/Apple
   - No password reset needed in our app

2. **Session Management**
   - 30-day JWT sessions with 24-hour sliding window
   - Automatic session refresh
   - Manual logout available

3. **Payment Recovery**
   - Stripe Customer Portal for payment method updates
   - Webhooks handle payment failures
   - Grace period before suspension

**What's Missing:**

1. **Account Locked Scenarios**
   - No unlock mechanism if account suspended manually
   - No self-service reactivation after cancellation
   - No recovery if OAuth provider access lost

2. **Email Verification**
   - No email verification flow currently
   - Relies solely on OAuth provider email verification

3. **Support-Assisted Recovery**
   - No admin tools to help dealers recover accounts
   - Manual database updates required

---

## Potential Account Recovery Scenarios

### Scenario 1: Lost Access to OAuth Provider

**Problem:**
- Dealer used Google Sign In
- Google account compromised or deleted
- Dealer cannot log into our app

**Current Solution:**
- Contact support
- Support manually updates email in database
- Dealer signs in with new OAuth account
- Support links new account to existing dealer record

**Potential Enhancement:**
- Self-service email change with verification
- Link multiple OAuth providers to one account
- Backup email for recovery

### Scenario 2: Account Suspended Due to Payment

**Problem:**
- Payment fails repeatedly
- Account status set to "suspended"
- Dealer updates payment in Stripe portal
- Account still shows suspended

**Current Solution:**
- Webhook should auto-reactivate on successful payment
- If webhook fails, manual database update needed

**Potential Enhancement:**
- Self-service reactivation button after payment fixed
- Clear messaging about reactivation timeline
- Manual "Check Payment Status" button

### Scenario 3: Account Cancelled, Want to Reactivate

**Problem:**
- Dealer cancelled subscription via Stripe portal
- Status set to "cancelled"
- Dealer wants to resubscribe
- Cannot access dashboard (middleware blocks cancelled accounts?)

**Current Solution:**
- Unclear - depends on middleware implementation
- May need to go through registration flow again
- Or contact support for reactivation

**Potential Enhancement:**
- Reactivation flow for cancelled accounts
- "Resubscribe" button on login for cancelled dealers
- Skip onboarding if dealer data exists

### Scenario 4: Forgot Which Email Used

**Problem:**
- Dealer has multiple emails
- Doesn't remember which one used for registration
- Cannot log in

**Current Solution:**
- Contact support
- Support searches database by business name/phone
- Support provides correct email to dealer

**Potential Enhancement:**
- "Find My Account" tool on login page
- Search by business name, phone, or subdomain
- Returns email hint (b***@example.com)

### Scenario 5: Account Locked After Suspicious Activity

**Problem:**
- Multiple failed login attempts
- Account temporarily locked for security
- Dealer cannot access account

**Current Solution:**
- No account locking mechanism currently implemented
- Rate limiting prevents brute force but doesn't lock accounts

**Potential Enhancement:**
- Implement account locking after N failed attempts
- Timed unlock (30 minutes) or manual unlock
- Email notification when account locked
- Self-service unlock via email link

### Scenario 6: OAuth Provider Changes Email

**Problem:**
- Dealer changes email in Google account
- OAuth returns new email
- Our system doesn't recognize it
- Creates new account instead of linking to existing

**Current Solution:**
- Email normalization helps (removes +tags)
- But doesn't handle complete email changes

**Potential Enhancement:**
- Link multiple emails to one dealer account
- Prompt to merge accounts if detected
- Email change verification flow

---

## Proposed Implementation Phases

### Phase 1: Critical Recovery Flows (3-4 days)

#### 1.1 Payment Recovery Button
**File:** `app/dashboard/subscription/page.tsx`

```typescript
{dealer.status === 'suspended' && (
  <div className="alert alert-warning">
    <p>Your account is suspended due to payment issues.</p>
    <button onClick={checkPaymentStatus}>
      Check Payment Status & Reactivate
    </button>
  </div>
)}
```

**API:** `POST /api/account/reactivate`
- Checks Stripe for valid payment method
- Checks for successful recent payment
- Updates dealer.status to "active" if all good
- Returns error if payment still failing

#### 1.2 Reactivation for Cancelled Accounts
**File:** `app/auth/signin/page.tsx` (or similar)

```typescript
// If dealer logs in but status is "cancelled"
if (dealer.status === 'cancelled') {
  redirect('/reactivate');
}
```

**File:** `app/reactivate/page.tsx`
- Shows: "Your account was cancelled"
- Button: "Resubscribe Now"
- Redirects to Stripe checkout
- Uses existing dealer data (skip onboarding)

#### 1.3 Find My Account Tool
**File:** `app/auth/find-account/page.tsx`

```typescript
<form onSubmit={findAccount}>
  <input name="businessName" placeholder="Business Name" />
  <input name="phone" placeholder="Phone Number" />
  <button>Find My Account</button>
</form>
```

**API:** `POST /api/auth/find-account`
- Searches dealers by business name + phone
- Returns email hint: "Your account email is: j***@example.com"
- Rate limited to prevent enumeration attacks

### Phase 2: Email Management (2-3 days)

#### 2.1 Change Email Address
**File:** `app/dashboard/settings/page.tsx` (if Task #7 implemented)

```typescript
<form onSubmit={changeEmail}>
  <input name="newEmail" placeholder="New Email" />
  <button>Change Email</button>
</form>
```

**Flow:**
1. Dealer enters new email
2. Send verification code to NEW email
3. Dealer enters code
4. Update User.email in database
5. Re-authenticate with new email

#### 2.2 Link Multiple OAuth Providers
**Enhancement:** Allow dealers to link both Google AND Apple to same account

```typescript
// app/dashboard/settings/page.tsx
<section>
  <h3>Connected Accounts</h3>
  <div>Google: ✓ Connected</div>
  <div>Apple: <button>Connect Apple</button></div>
</section>
```

**Benefits:**
- Dealer can sign in with either provider
- Backup if one provider has issues
- Flexibility for dealers

### Phase 3: Admin Recovery Tools (2-3 days)

#### 3.1 Admin Account Management
**File:** `app/admin/dealers/[id]/page.tsx`

Admin can:
- View dealer account status
- Manually unlock account
- Change email address (with audit log)
- Reset account status
- View login history
- Force logout

#### 3.2 Support Dashboard
**File:** `app/admin/support/page.tsx`

- Search dealers by email, name, phone, subdomain
- View recent support tickets (if integrated)
- Quick actions: unlock, reactivate, reset
- Audit log of all admin actions

---

## Technical Implementation Details

### Database Schema Changes

**Add fields to User table:**
```prisma
model User {
  // Existing fields...

  // Account Recovery
  accountLocked       Boolean   @default(false)
  lockedAt            DateTime?
  lockedReason        String?
  unlockToken         String?   @unique
  unlockTokenExpiry   DateTime?

  // Email Verification
  emailVerified       Boolean   @default(false)
  verificationToken   String?   @unique
  verificationExpiry  DateTime?

  // Audit
  lastLoginAt         DateTime?
  failedLoginAttempts Int       @default(0)
  lastFailedLoginAt   DateTime?
}
```

**Add Account table for linked OAuth:**
```prisma
model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String  // "oauth"
  provider          String  // "google" | "apple"
  providerAccountId String

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}
```

### API Endpoints

#### POST /api/account/reactivate
**Purpose:** Reactivate suspended account after payment fixed

**Auth:** Required

**Logic:**
1. Verify dealer is suspended
2. Check Stripe for valid payment method
3. Check for recent successful payment
4. Update dealer.status = "active"
5. Log reactivation

**Response:**
```json
{
  "success": true,
  "status": "active",
  "message": "Your account has been reactivated"
}
```

#### POST /api/auth/find-account
**Purpose:** Find dealer account by business info

**Auth:** Not required (public)

**Rate Limit:** 5 requests/min per IP

**Request:**
```json
{
  "businessName": "Bob's Oil",
  "phone": "555-1234"
}
```

**Response:**
```json
{
  "found": true,
  "emailHint": "b***@example.com",
  "message": "We found your account. Please sign in with the email shown above."
}
```

#### POST /api/account/unlock
**Purpose:** Unlock account after security lock

**Auth:** Not required (uses unlock token)

**Request:**
```json
{
  "token": "unlock_abc123..."
}
```

**Response:**
```json
{
  "success": true,
  "message": "Your account has been unlocked. You may now sign in."
}
```

#### POST /api/account/change-email
**Purpose:** Change account email address

**Auth:** Required

**Flow:**
1. Send verification code to new email
2. Verify code
3. Update email
4. Log change

**Request:**
```json
{
  "newEmail": "newemail@example.com",
  "verificationCode": "123456"
}
```

---

## Security Considerations

### Email Enumeration Prevention
- Don't reveal if email exists during "Find Account" search
- Use generic messages: "If account exists, you'll receive an email"
- Rate limit all lookup endpoints

### Account Locking
- Lock after 5 failed login attempts (OAuth failures)
- Auto-unlock after 30 minutes
- Email notification when locked
- Unlock token sent via email

### Email Verification
- Verification codes expire after 15 minutes
- 6-digit codes (easy to type)
- Rate limit verification attempts
- Lock account after 10 failed verification attempts

### Admin Actions Audit
- Log all admin account modifications
- Include: admin user ID, timestamp, action, reason
- Display audit log to dealer (transparency)
- Notify dealer via email when admin modifies account

### Token Security
- Unlock tokens: random, cryptographically secure, expire
- Verification codes: random, rate-limited
- Store tokens hashed in database
- Single-use tokens (invalidate after use)

---

## User Experience

### Clear Messaging

**Account Locked:**
```
⚠️ Your account has been temporarily locked for security reasons.

We've sent an unlock link to your email: j***@example.com

Didn't receive the email? [Resend Unlock Link]
```

**Payment Suspended:**
```
🚫 Your account is suspended due to payment issues.

Please update your payment method in the billing portal, then click the button below.

[Update Payment Method] [Check Status & Reactivate]
```

**Account Cancelled:**
```
ℹ️ Your account was cancelled.

Want to come back? We'd love to have you!

[Resubscribe Now] [Contact Support]
```

### Email Notifications

**Account Locked Email:**
```
Subject: Your AMSOIL Dealer Pages account has been locked

Hi [Name],

Your account has been temporarily locked after multiple failed sign-in attempts.

To unlock your account, click here: [Unlock Link]

This link expires in 1 hour.

If you didn't attempt to sign in, please contact us immediately.
```

**Account Unlocked Email:**
```
Subject: Your account has been unlocked

Hi [Name],

Your AMSOIL Dealer Pages account has been unlocked and is ready to use.

[Sign In Now]

If you didn't request this, please contact us immediately.
```

---

## Testing Strategy

### Test Scenarios

1. **Payment Recovery**
   - Suspend account (set status to "suspended")
   - Update payment method in Stripe
   - Click "Reactivate" button
   - Verify status changes to "active"

2. **Find Account**
   - Search by business name + phone
   - Verify email hint returned
   - Test with non-existent business
   - Test rate limiting (>5 requests)

3. **Account Locking**
   - Trigger 5 failed OAuth attempts
   - Verify account locked
   - Verify email sent
   - Click unlock link
   - Verify account unlocked

4. **Reactivation After Cancellation**
   - Cancel subscription via Stripe portal
   - Log out and log back in
   - Verify redirect to reactivation page
   - Click "Resubscribe"
   - Verify checkout flow works
   - Verify existing dealer data preserved

---

## Dependencies

### Technical Dependencies
- NextAuth.js (already implemented)
- Email service (for notifications) - **NOT YET IMPLEMENTED**
- Stripe API (already implemented)
- Database migrations (for new fields)

### Business Dependencies
- Email sending service (SendGrid, AWS SES, etc.)
- Support process documentation
- Admin training on recovery tools

---

## Success Criteria

Account recovery is complete when:

✅ **Self-Service Recovery Works**
- Dealers can reactivate after payment fixed
- Dealers can find their account if email forgotten
- Dealers can resubscribe after cancellation

✅ **Security is Maintained**
- Rate limiting prevents abuse
- Account locking works correctly
- Email verification is secure
- Admin actions are audited

✅ **Documentation Complete**
- User-facing help docs written
- Admin recovery procedures documented
- Support team trained

✅ **Testing Complete**
- All scenarios tested
- Edge cases handled
- Error messages are clear

---

## Future Enhancements

### Phase 4: Advanced Recovery (Future)

1. **Two-Factor Authentication**
   - Add 2FA for extra security
   - Recovery codes for 2FA lockout

2. **Account Backup Contacts**
   - Designate emergency contact
   - Contact can help recover account

3. **Identity Verification**
   - Photo ID upload for recovery
   - Video verification call

4. **Automated Support**
   - Chatbot for common recovery scenarios
   - Reduce support ticket volume

---

## Related Documents

- Task #7: Account Settings (email change UI)
- Task #12: Admin Dashboard (admin recovery tools)
- Task #13: Monitoring (alert on account lockouts)
- `/docs/STRIPE_CUSTOMER_PORTAL.md` (payment recovery)

---

## Estimated Timeline

| Phase | Features | Effort |
|-------|----------|--------|
| Phase 1 | Payment recovery, reactivation, find account | 3-4 days |
| Phase 2 | Email management, multiple OAuth | 2-3 days |
| Phase 3 | Admin recovery tools | 2-3 days |
| **Total** | | **7-10 days** |

---

## Notes for Implementation

When ready to implement:

1. **Start with most common scenarios**
   - Payment recovery is likely #1 issue
   - Implement that first

2. **Integrate with existing flows**
   - Use existing subscription page for reactivation
   - Use existing OAuth for email changes

3. **Test thoroughly**
   - Account recovery is security-sensitive
   - Edge cases can create vulnerabilities

4. **Monitor user behavior**
   - Track which recovery flows are used
   - Optimize based on actual usage

5. **Document everything**
   - Users need clear instructions
   - Support needs recovery procedures

---

**Status:** Tabled pending completion of core features and user feedback
**Next Review:** 1-2 months post-launch
**Owner:** TBD
