# Auth Schema Improvements - Explanation

## Problems Identified and Fixed

### 1. **`z.unknown()` Type Safety Issue** ❌ → ✅

**Problem:**

```typescript
// BEFORE - NO TYPE SAFETY
export const signupResultSchema = z.object({
  user: z.unknown(), // ❌ Loses all type information and validation
  tokens: authTokensSchema,
});
```

**Why it was wrong:**

- `z.unknown()` provides **zero validation** at runtime
- TypeScript can't infer proper types from it
- Defeats the purpose of schema-first architecture
- Any object could pass validation, even malformed data

**Solution:**

```typescript
// AFTER - FULL TYPE SAFETY
export const userProfileSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  role: z.enum(["USER", "ADMIN"]),
  // ... all fields properly typed
});

export const signupResultSchema = z.object({
  user: userProfileSchema, // ✅ Full validation and type inference
  tokens: authTokensSchema,
});
```

**Benefits:**

- Runtime validation of user data structure
- Proper TypeScript type inference
- Catches invalid data early
- Self-documenting API contract

---

### 2. **Email Validation Issues** ❌ → ✅

**Problem:**
The `z.string().email()` in `checkPasswordNeededResponseSchema` was correct, but using `z.unknown()` elsewhere meant emails weren't being validated in user objects.

**Solution:**

```typescript
export const userProfileSchema = z.object({
  email: z.string().email(), // ✅ Validates email format
  // ...
});
```

Now all user objects have their emails properly validated.

---

### 3. **UserProfile Alias Confusion** 🤔 → ✅

**Problem:**

```typescript
export type UserProfile = AuthenticatedUser;
```

This created confusion about why we have two names for the same thing.

**Solution - Added Clear Documentation:**

```typescript
/**
 * UserProfile type alias
 *
 * Note: This is an alias for backward compatibility.
 * Both types represent the same thing: a complete user profile with auth state.
 *
 * Architecture:
 * - PortalUser: Only auth state from portal DB (id, email, role, emailVerified, etc.)
 * - CustomerProfile: Profile data from WHMCS (firstname, lastname, address, etc.)
 * - AuthenticatedUser/UserProfile: CustomerProfile + auth state = complete user
 */
export type UserProfile = AuthenticatedUser;
```

**Why the alias exists:**

- **Backward compatibility**: Code may use either name
- **Domain language**: "UserProfile" is more business-friendly than "AuthenticatedUser"
- **Convention**: Many authentication libraries use "UserProfile"

---

## Architecture Explanation

### Three-Layer User Model

```
┌─────────────────────────────────────────────┐
│         AuthenticatedUser / UserProfile     │
│              (Complete User)                │
│  ┌────────────────────────────────────────┐ │
│  │      CustomerProfile (WHMCS)           │ │
│  │  - firstname, lastname                 │ │
│  │  - address, phone                      │ │
│  │  - language, currency                  │ │
│  └────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────┐ │
│  │      PortalUser (Portal DB)            │ │
│  │  - id, email                           │ │
│  │  - role, emailVerified, mfaEnabled     │ │
│  │  - lastLoginAt                         │ │
│  └────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```

### 1. **PortalUser** (Portal Database)

- **Purpose**: Authentication state only
- **Source**: Portal's Prisma database
- **Fields**: id, email, role, emailVerified, mfaEnabled, lastLoginAt
- **Schema**: `portalUserSchema`
- **Use Cases**: JWT validation, token refresh, auth checks

### 2. **CustomerProfile** (WHMCS)

- **Purpose**: Business profile data
- **Source**: WHMCS API (single source of truth for profile data)
- **Fields**: firstname, lastname, address, phone, language, currency
- **Schema**: Interface only (external system)
- **Use Cases**: Displaying user info, profile updates

### 3. **AuthenticatedUser / UserProfile** (Combined)

- **Purpose**: Complete user representation
- **Source**: Portal DB + WHMCS (merged)
- **Fields**: All fields from PortalUser + CustomerProfile
- **Schema**: `userProfileSchema` (for validation)
- **Use Cases**: API responses, full user context

---

## Why This Matters

### Before (with `z.unknown()`):

```typescript
// Could pass completely invalid data ❌
const badData = {
  user: { totally: "wrong", structure: true },
  tokens: {
    /* ... */
  },
};
// Would validate successfully! ❌
```

### After (with proper schema):

```typescript
// Validates structure correctly ✅
const goodData = {
  user: {
    id: "uuid-here",
    email: "valid@email.com",
    role: "USER",
    // ... all required fields
  },
  tokens: {
    /* ... */
  },
};
// Validates ✅

const badData = {
  user: { wrong: "structure" },
  tokens: {
    /* ... */
  },
};
// Throws validation error ✅
```

---

## Implementation Details

### Schema Definition Location

The `userProfileSchema` is defined **before** it's used:

```typescript
// 1. First, define the schema
export const userProfileSchema = z.object({
  // All fields defined
});

// 2. Then use it in response schemas
export const authResponseSchema = z.object({
  user: userProfileSchema, // ✅ Now defined
  tokens: authTokensSchema,
});
```

### Type Inference

TypeScript now properly infers types:

```typescript
// Type is inferred from schema
type InferredUser = z.infer<typeof userProfileSchema>;

// Results in proper type:
// {
//   id: string;
//   email: string;
//   role: "USER" | "ADMIN";
//   emailVerified: boolean;
//   // ... etc
// }
```

---

## Migration Impact

### ⚠️ Potential Breaking Change (Security Improvement)

Auth endpoints now return **session metadata** instead of **token strings**:

- **Before**: `{ user, tokens: { accessToken, refreshToken, expiresAt, refreshExpiresAt } }`
- **After**: `{ user, session: { expiresAt, refreshExpiresAt } }`

Token strings are delivered via **httpOnly cookies** only.

### ✅ Improved Type Safety

- Better autocomplete in IDEs
- Compile-time error checking
- Runtime validation of API responses

### ✅ Better Documentation

- Schema serves as living documentation
- Clear separation of concerns
- Self-describing data structures

---

## Summary

| Issue               | Before           | After                  |
| ------------------- | ---------------- | ---------------------- |
| User validation     | `z.unknown()` ❌ | `userProfileSchema` ✅ |
| Type safety         | None             | Full                   |
| Runtime validation  | None             | Complete               |
| Documentation       | Unclear          | Self-documenting       |
| Email validation    | Partial          | Complete               |
| UserProfile clarity | Confusing        | Documented             |

**Result**: Proper schema-first architecture with full type safety and validation! 🎉
