# Mutations (Strict)

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

Mutations exist to provide framework-agnostic write operations.

## 1) Definition

A **Mutation** is a framework-agnostic operation that orchestrates writes.

Mutations are the write equivalent of PageQueries.

## 2) Relationship to Next.js Server Actions

**Server Actions are the entry point**, but they should be thin wrappers:

```typescript
// app/admin/actions.ts (Next.js framework code)
'use server';

import { AdminUserMutation } from '@/lib/mutations/admin/AdminUserMutation';
import { revalidatePath } from 'next/cache';

export async function updateUserStatus(userId: string, status: string) {
  const mutation = new AdminUserMutation();
  const result = await mutation.updateUserStatus(userId, status);
  
  if (result.isErr()) {
    console.error('updateUserStatus failed:', result.getError());
    throw new Error('Failed to update user status');
  }
  
  revalidatePath('/admin/users');
}
```

## 3) Mutation Structure

```typescript
// lib/mutations/admin/AdminUserMutation.ts
import { Result, ResultFactory } from '@/lib/contracts/Result';

export class AdminUserMutation {
  private service: AdminService;
  
  constructor() {
    // Manual DI for serverless
    const logger = new ConsoleLogger();
    const errorReporter = new EnhancedErrorReporter(logger, {
      showUserNotifications: true,
      logToConsole: true,
      reportToExternal: process.env.NODE_ENV === 'production',
    });
    const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
    const apiClient = new AdminApiClient(baseUrl, errorReporter, logger);
    this.service = new AdminService(apiClient);
  }
  
  async updateUserStatus(userId: string, status: string): Promise<Result<void, string>> {
    try {
      await this.service.updateUserStatus(userId, status);
      return ResultFactory.ok(undefined);
    } catch (error) {
      return ResultFactory.error('UPDATE_USER_STATUS_FAILED');
    }
  }
  
  async deleteUser(userId: string): Promise<Result<void, string>> {
    try {
      await this.service.deleteUser(userId);
      return ResultFactory.ok(undefined);
    } catch (error) {
      return ResultFactory.error('DELETE_USER_FAILED');
    }
  }
}
```

## 4) Why This Pattern?

**Benefits:**

1. **Framework independence** - Mutations can be tested without Next.js
2. **Consistent pattern** - Mirrors PageQueries for reads/writes
3. **Easy migration** - Can switch frameworks without rewriting business logic
4. **Testable** - Can unit test mutations in isolation
5. **Reusable** - Can be called from other contexts (cron jobs, etc.)

## 5) Naming Convention

- Mutations: `*Mutation.ts`
- Server Actions: `actions.ts` (thin wrappers)

## 6) File Structure

```
lib/
  mutations/
    admin/
      AdminUserMutation.ts
      AdminLeagueMutation.ts
    league/
      LeagueJoinMutation.ts
    team/
      TeamUpdateMutation.ts
```

## 7) Non-negotiable Rules

1. **Server Actions are thin wrappers** - They only handle framework concerns (revalidation, redirects)
2. **Mutations handle infrastructure** - They create services, handle errors
3. **Services handle business logic** - They orchestrate API calls
4. **Mutations are framework-agnostic** - No Next.js imports except in tests
5. **Mutations must be deterministic** - Same inputs = same outputs

## 8) Comparison with PageQueries

| Aspect | PageQuery | Mutation |
|--------|-----------|----------|
| Purpose | Read data | Write data |
| Location | `lib/page-queries/` | `lib/mutations/` |
| Framework | Called from RSC | Called from Server Actions |
| Infrastructure | Manual DI | Manual DI |
| Returns | `Result<ApiDto, string>` | `Result<void, string>` |
| Revalidation | N/A | Server Action handles it |

## 9) Example Flow

**Read (RSC):**
```
RSC page.tsx
  ↓
PageQuery.execute()
  ↓
Service
  ↓
API Client
  ↓
Result<ApiDto, string>
  ↓
ViewDataBuilder
  ↓
Template
```

**Write (Server Action):**
```
Client Component
  ↓
Server Action
  ↓
Mutation.execute()
  ↓
Service
  ↓
API Client
  ↓
Result<void, string>
  ↓
Revalidation
```

## 10) Enforcement

ESLint rules should enforce:
- Server Actions must call Mutations (not Services directly)
- Mutations must not import Next.js (except in tests)
- Mutations must use services

See `docs/architecture/website/WEBSITE_GUARDRAILS.md` for details.