# Builders (Strict)

This document defines the **Builder** pattern for `apps/website`.

Builders exist to transform data between presentation model types.

## 1) Definition

A **Builder** is a deterministic, side-effect free transformation between website presentation models.

There are two types of builders:

### 1.1 ViewModel Builders
Transform API Transport DTOs into ViewModels.

**Purpose**: Prepare raw API data for client-side state management.

**Location**: `apps/website/lib/builders/view-models/**`

**Pattern**:
```typescript
export class AdminViewModelBuilder {
  static build(dto: UserDto): AdminUserViewModel {
    return new AdminUserViewModel(dto);
  }
}
```

### 1.2 ViewData Builders
Transform API DTOs directly into ViewData for templates.

**Purpose**: Prepare API data for server-side rendering without ViewModels.

**Location**: `apps/website/lib/builders/view-data/**`

**Pattern**:
```typescript
export class LeagueViewDataBuilder {
  static build(apiDto: LeagueApiDto): LeagueDetailViewData {
    return {
      leagueId: apiDto.id,
      name: apiDto.name,
      // ... more fields
    };
  }
}
```

## 2) Non-negotiable rules

### ViewModel Builders
1. MUST be deterministic
2. MUST be side-effect free
3. MUST NOT perform HTTP
4. MUST NOT call API clients
5. MUST NOT access cookies/headers
6. Input: API Transport DTO
7. Output: ViewModel
8. MUST live in `lib/builders/view-models/**`

### ViewData Builders
1. MUST be deterministic
2. MUST be side-effect free
3. MUST NOT perform HTTP
4. MUST NOT call API clients
5. MUST NOT access cookies/headers
6. Input: API DTO
7. Output: ViewData
8. MUST live in `lib/builders/view-data/**`

## 3) Why two builder types?

**ViewModel Builders** (API → Client State):
- Bridge the API boundary
- Convert transport types to client classes
- Add client-only fields if needed
- Run in client code

**ViewData Builders** (API → Render Data):
- Bridge the presentation boundary
- Transform API data directly for templates
- Format values for display
- Run in server code (RSC)

## 4) Relationship to other patterns

```
API Transport DTO
    ↓
ViewModel Builder (lib/builders/view-models/)
    ↓
ViewModel (lib/view-models/)
    ↓
    (for client components)

API Transport DTO
    ↓
ViewData Builder (lib/builders/view-data/)
    ↓
ViewData (lib/templates/)
    ↓
Template (lib/templates/)
```

## 5) Naming convention

**ViewModel Builders**: `*ViewModelBuilder`
- `AdminViewModelBuilder`
- `RaceViewModelBuilder`

**ViewData Builders**: `*ViewDataBuilder`
- `LeagueViewDataBuilder`
- `RaceViewDataBuilder`

## 6) File structure

```
lib/
  builders/
    view-models/
      AdminViewModelBuilder.ts
      RaceViewModelBuilder.ts
      index.ts
      
    view-data/
      LeagueViewDataBuilder.ts
      RaceViewDataBuilder.ts
      index.ts
```

## 7) Usage examples

### ViewModel Builder (Client Component)
```typescript
'use client';

import { AdminViewModelBuilder } from '@/lib/builders/view-models/AdminViewModelBuilder';
import { AdminApiClient } from '@/lib/api/admin/AdminApiClient';

export function AdminPage() {
  const [users, setUsers] = useState<AdminUserViewModel[]>([]);
  
  useEffect(() => {
    const apiClient = new AdminApiClient();
    const dto = await apiClient.getUsers();
    const viewModels = dto.map(d => AdminViewModelBuilder.build(d));
    setUsers(viewModels);
  }, []);
  
  // ... render with viewModels
}
```

### ViewData Builder (Server Component)
```typescript
import { LeagueViewDataBuilder } from '@/lib/builders/view-data/LeagueViewDataBuilder';
import { LeagueDetailPageQuery } from '@/lib/page-queries/LeagueDetailPageQuery';

export default async function LeagueDetailPage({ params }) {
  const apiDto = await LeagueDetailPageQuery.execute(params.id);
  const viewData = LeagueViewDataBuilder.build(apiDto);
  
  return <LeagueDetailTemplate viewData={viewData} />;
}
```

## 8) Common mistakes

❌ **Wrong**: Using "Presenter" for DTO → ViewModel
```typescript
// DON'T
export class AdminPresenter {
  static createViewModel(dto: UserDto): AdminUserViewModel { ... }
}
```

✅ **Correct**: Use ViewModelBuilder
```typescript
export class AdminViewModelBuilder {
  static build(dto: UserDto): AdminUserViewModel { ... }
}
```

❌ **Wrong**: Using "Transformer" for ViewModel → ViewData
```typescript
// DON'T
export class RaceResultsDataTransformer {
  static transform(...): TransformedData { ... }
}
```

✅ **Correct**: Use ViewDataBuilder
```typescript
export class RaceResultsViewDataBuilder {
  static build(...): RaceResultsViewData { ... }
}
```

## 9) Enforcement

These rules are enforced by ESLint:
- `gridpilot-rules/view-model-builder-contract`
- `gridpilot-rules/view-data-builder-contract`
- `gridpilot-rules/filename-view-model-builder-match`
- `gridpilot-rules/filename-view-data-builder-match`

See [`docs/architecture/website/WEBSITE_GUARDRAILS.md`](WEBSITE_GUARDRAILS.md) for details.