website refactor

This commit is contained in:
2026-01-13 02:38:49 +01:00
parent e981ebd9e9
commit 38b25bafe1
20 changed files with 1138 additions and 80 deletions

View File

@@ -2,25 +2,39 @@ import { Result } from "../Result";
/**
* PageQuery contract interface
*
*
* Defines the canonical contract for all server-side page queries.
*
* Based on WEBSITE_PAGE_QUERIES.md:
*
* Architecture:
* - Server-side composition classes
* - Call services that call apps/api
* - Assemble a Page DTO
* - Explicit result describing route outcome
* - Construct Services manually (no DI container)
* - Services create their own dependencies (API Client, Logger, ErrorReporter)
* - Services return Result<ApiDto, DomainError>
* - PageQuery maps DomainError → PresentationError
* - PageQuery returns Result<ViewData, PresentationError>
* - Do not implement business rules
*
* @template TApiDto - The API DTO type this query produces
*
* @template TViewData - The ViewData type this query produces for templates
* @template TParams - The parameters required to execute this query
* @template TError - The error type (default: string for backward compatibility)
*/
export interface PageQuery<TApiDto, TParams = void> {
export interface PageQuery<TViewData, TParams = void, TError = string> {
/**
* Execute the page query
*
*
* Manual construction pattern:
* ```typescript
* const service = new MyService();
* const result = await service.getData();
* if (result.isErr()) {
* return Result.err(mapToPresentationError(result.error));
* }
* const viewData = MyViewDataBuilder.build(result.value);
* return Result.ok(viewData);
* ```
*
* @param params - Parameters required for query execution
* @returns Promise resolving to a Result
* @returns Promise<Result<ViewData, TError>>
*/
execute(params: TParams): Promise<Result<TApiDto, string>>;
execute(params: TParams): Promise<Result<TViewData, TError>>;
}

View File

@@ -0,0 +1,42 @@
/**
* Presentation Error Type
*
* Errors that can be handled by the presentation layer (RSC pages, templates).
* These are mapped from DomainErrors by PageQueries.
*/
export type PresentationError =
| 'notFound' // Resource not found - show 404 page
| 'redirect' // Redirect to another page (e.g., login)
| 'unauthorized' // Not authorized - show access denied
| 'serverError' // Generic server error
| 'networkError' // Network/communication error
| 'validationError' // Invalid input data
| 'unknown'; // Unknown error
// Helper to map DomainError to PresentationError
export function mapToPresentationError(domainError: any): PresentationError {
const errorType = domainError?.type || domainError?.name || 'unknown';
switch (errorType) {
case 'notFound':
case 'NotFoundError':
return 'notFound';
case 'unauthorized':
case 'UnauthorizedError':
case 'ForbiddenError':
return 'unauthorized';
case 'serverError':
case 'ServerError':
case 'HttpServerError':
return 'serverError';
case 'networkError':
case 'NetworkError':
return 'networkError';
case 'validationError':
case 'ValidationError':
return 'validationError';
default:
return 'unknown';
}
}