# Website RSC Presentation Architecture (Strict)

This document defines the only allowed presentation architecture for `apps/website` (Next.js App Router).

It is **website-only** and does not change `apps/api` or `core` architecture.

Authoritative contract: [`WEBSITE_CONTRACT.md`](docs/architecture/website/WEBSITE_CONTRACT.md:1).

## 1) Core rule: API owns business truth

- `apps/api` is the only source of truth for business rules and canonical filtering/sorting.
- `apps/website` is presentation infrastructure: composition, routing, caching, and rendering.

## 2) The three website presentation data types

### 2.1 Page DTO

**Purpose:** server-to-client payload.

**Rules:**

- JSON-serializable only.
- Contains raw values only (ISO date strings, numbers, codes).
- MUST NOT contain class instances.

### 2.2 ViewModel

**Purpose:** client-only presentation model.

**Rules:**

- Class-based.
- Instantiated only in `'use client'` modules.
- Composes Display Objects.
- NEVER passed into Templates.

### 2.3 ViewData

**Purpose:** Template input.

**Rules:**

- JSON-serializable only.
- Contains only values ready to render (mostly strings/numbers).
- Built from API DTO directly in RSC.

The mapping between API DTO and ViewData is performed by ViewData Builders.
See [`BUILDERS.md`](docs/architecture/website/BUILDERS.md:1).

## 3) Required per-route structure

### Server Components (RSC)
Every RSC route MUST follow:

1) `page.tsx`: calls a PageQuery
2) `page.tsx`: builds ViewData using ViewDataBuilder
3) `page.tsx`: renders Template with ViewData

Example:
```typescript
export default async function AdminDashboardPage() {
  const apiDto = await AdminDashboardPageQuery.execute();
  const viewData = AdminDashboardViewDataBuilder.build(apiDto);
  return <AdminDashboardTemplate viewData={viewData} />;
}
```

### Client Components
Client components that need API data MUST follow:

1) `*Client.tsx`: fetches API DTO
2) `*Client.tsx`: builds ViewModel using ViewModelBuilder
3) `*Client.tsx`: renders Template with ViewModel

Example:
```typescript
'use client';

export function AdminDashboardClient() {
  const [viewModel, setViewModel] = useState<AdminDashboardViewModel | null>(null);
  
  useEffect(() => {
    const apiDto = await adminApiClient.getDashboard();
    const vm = AdminDashboardViewModelBuilder.build(apiDto);
    setViewModel(vm);
  }, []);
  
  return viewModel ? <AdminDashboardTemplate viewModel={viewModel} /> : null;
}
```

All writes enter through Server Actions.
See [`FORM_SUBMISSION.md`](docs/architecture/website/FORM_SUBMISSION.md:1).

## 4) Authoritative specification

This document is an entry point only.

The authoritative, test-enforced spec lives at:

- [plans/nextjs-rsc-viewmodels-concept.md](plans/nextjs-rsc-viewmodels-concept.md:1)

Final contract:

- [`WEBSITE_CONTRACT.md`](docs/architecture/website/WEBSITE_CONTRACT.md:1)
