website refactor
This commit is contained in:
@@ -148,10 +148,11 @@ Purpose: eliminate exceptions and provide explicit error paths.
|
||||
|
||||
Rules:
|
||||
|
||||
- All PageQueries return `Result<ApiDto, string>`
|
||||
- All Mutations return `Result<void, string>`
|
||||
- Use `ResultFactory.ok(value)` for success
|
||||
- Use `ResultFactory.error(message)` for errors
|
||||
- All PageQueries return `Result<ViewData, PresentationError>`
|
||||
- All Mutations return `Result<void, MutationError>`
|
||||
- All Services return `Result<ApiDto, DomainError>`
|
||||
- Use `Result.ok(value)` for success
|
||||
- Use `Result.err(error)` for errors
|
||||
- Never throw exceptions
|
||||
|
||||
See [`Result.ts`](apps/website/lib/contracts/Result.ts:1).
|
||||
@@ -183,13 +184,19 @@ Canonical placement in this repo:
|
||||
```text
|
||||
RSC page.tsx
|
||||
↓
|
||||
PageQuery.execute()
|
||||
PageQuery (manual construction)
|
||||
↓
|
||||
API client (infra)
|
||||
Service (creates own API Client, Logger, ErrorReporter)
|
||||
↓
|
||||
API Client (makes HTTP calls)
|
||||
↓
|
||||
API Transport DTO
|
||||
↓
|
||||
Result<ApiDto, string>
|
||||
Result<ApiDto, DomainError>
|
||||
↓
|
||||
PageQuery (maps DomainError → PresentationError)
|
||||
↓
|
||||
Result<ViewData, PresentationError>
|
||||
↓
|
||||
ViewData Builder (lib/builders/view-data/)
|
||||
↓
|
||||
@@ -198,6 +205,13 @@ ViewData
|
||||
Template
|
||||
```
|
||||
|
||||
**Key Points:**
|
||||
- PageQuery constructs Service
|
||||
- Service creates its own dependencies
|
||||
- Service returns Result<ApiDto, DomainError>
|
||||
- PageQuery maps errors to presentation layer
|
||||
- Builder transforms API DTO to ViewData
|
||||
|
||||
### Client Components
|
||||
```text
|
||||
Client Component
|
||||
@@ -241,40 +255,55 @@ Allowed:
|
||||
import { AdminService } from '@/lib/services/admin/AdminService';
|
||||
|
||||
export async function updateUserStatus(userId: string, status: string) {
|
||||
const service = new AdminService(...);
|
||||
const service = new AdminService();
|
||||
await service.updateUserStatus(userId, status); // ❌ Should use mutation
|
||||
}
|
||||
|
||||
// ✅ CORRECT - Mutation usage
|
||||
'use server';
|
||||
import { AdminUserMutation } from '@/lib/mutations/admin/AdminUserMutation';
|
||||
import { UpdateUserStatusMutation } from '@/lib/mutations/UpdateUserStatusMutation';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function updateUserStatus(userId: string, status: string) {
|
||||
const mutation = new AdminUserMutation();
|
||||
const result = await mutation.updateUserStatus(userId, status);
|
||||
export async function updateUserStatus(input: UpdateUserStatusInput) {
|
||||
const mutation = new UpdateUserStatusMutation();
|
||||
const result = await mutation.execute(input);
|
||||
|
||||
if (result.isErr()) {
|
||||
console.error('updateUserStatus failed:', result.getError());
|
||||
throw new Error('Failed to update user status');
|
||||
console.error('updateUserStatus failed:', result.error);
|
||||
return { success: false, error: result.error };
|
||||
}
|
||||
|
||||
revalidatePath('/admin/users');
|
||||
return { success: true };
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern**:
|
||||
1. Server Action (thin wrapper) - handles framework concerns (revalidation)
|
||||
2. Mutation (framework-agnostic) - creates infrastructure, calls service
|
||||
3. Service (business logic) - orchestrates API calls
|
||||
4. API Client (infrastructure) - makes HTTP requests
|
||||
5. Result - type-safe error handling
|
||||
1. **Server Action** (thin wrapper) - handles framework concerns (revalidation, returns to client)
|
||||
2. **Mutation** (framework-agnostic) - constructs Service, calls service methods
|
||||
3. **Service** - constructs own dependencies (API Client, Logger), returns Result
|
||||
4. **API Client** (infrastructure) - makes HTTP requests, throws HTTP errors
|
||||
5. **Result** - type-safe error handling at every layer
|
||||
|
||||
**Dependency Flow**:
|
||||
```
|
||||
Server Action
|
||||
↓ (constructs)
|
||||
Mutation
|
||||
↓ (constructs)
|
||||
Service (creates API Client, Logger, ErrorReporter)
|
||||
↓ (calls)
|
||||
API Client
|
||||
↓ (HTTP)
|
||||
Backend API
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Mutations are framework-agnostic (can be tested without Next.js)
|
||||
- Consistent pattern with PageQueries
|
||||
- Type-safe error handling with Result
|
||||
- Makes infrastructure explicit and testable
|
||||
- Manual construction (no DI container issues)
|
||||
|
||||
See [`MUTATIONS.md`](docs/architecture/website/MUTATIONS.md:1) and [`SERVICES.md`](docs/architecture/website/SERVICES.md:1).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user