website refactor

This commit is contained in:
2026-01-13 23:33:07 +01:00
parent 87572f5b1f
commit 8d7c709e0c
4 changed files with 318 additions and 25 deletions

View File

@@ -73,6 +73,7 @@
],
"rules": {
"gridpilot-rules/mutation-contract": "error",
"gridpilot-rules/mutation-must-use-builders": "error",
"gridpilot-rules/filename-service-match": "error"
}
},
@@ -117,7 +118,20 @@
"gridpilot-rules/rsc-no-di": "error",
"gridpilot-rules/rsc-no-local-helpers": "error",
"gridpilot-rules/rsc-no-object-construction": "error",
"gridpilot-rules/rsc-no-container-manager-calls": "error"
"gridpilot-rules/rsc-no-container-manager-calls": "error",
"gridpilot-rules/no-hardcoded-search-params": "error",
"gridpilot-rules/no-next-cookies-in-pages": "error"
}
},
{
"files": [
"lib/services/**/*.ts",
"lib/page-queries/**/*.ts",
"lib/mutations/**/*.ts",
"middleware.ts"
],
"rules": {
"gridpilot-rules/no-direct-process-env": "error"
}
},
{
@@ -150,17 +164,6 @@
"gridpilot-rules/no-hardcoded-search-params": "error"
}
},
{
"files": [
"lib/mutations/**/*.ts"
],
"rules": {
"gridpilot-rules/mutation-contract": "error",
"gridpilot-rules/clean-error-handling": "error",
"gridpilot-rules/single-export-per-file": "error",
"gridpilot-rules/filename-matches-export": "error"
}
},
{
"files": [
"templates/**/*.ts",
@@ -190,7 +193,9 @@
"rules": {
"gridpilot-rules/client-only-no-server-code": "error",
"gridpilot-rules/client-only-must-have-directive": "error",
"gridpilot-rules/server-actions-must-use-mutations": "error"
"gridpilot-rules/server-actions-must-use-mutations": "error",
"gridpilot-rules/server-actions-return-result": "error",
"gridpilot-rules/server-actions-interface": "error"
}
},
{
@@ -220,6 +225,18 @@
"gridpilot-rules/lib-no-next-imports": "error"
}
},
{
"files": [
"app/onboarding/**/*.ts",
"app/onboarding/**/*.tsx",
"lib/auth/RouteGuard.ts",
"lib/auth/AuthFlowRouter.ts",
"middleware.ts"
],
"rules": {
"gridpilot-rules/no-console": "error"
}
},
{
"files": [
"app/**/*.tsx",
@@ -237,7 +254,9 @@
"app/**/actions/*.ts"
],
"rules": {
"gridpilot-rules/no-hardcoded-routes": "error"
"gridpilot-rules/no-hardcoded-routes": "error",
"gridpilot-rules/server-actions-return-result": "error",
"gridpilot-rules/server-actions-interface": "error"
}
},
{
@@ -268,7 +287,6 @@
],
"rules": {
"gridpilot-rules/service-function-format": "error",
"gridpilot-rules/services-must-be-marked": "error",
"gridpilot-rules/services-must-be-pure": "error",
"gridpilot-rules/services-no-external-api": "error",
"gridpilot-rules/services-implement-contract": "error",

View File

@@ -18,7 +18,6 @@
* - They return Result<ApiDto, DomainError>
*/
import { Result } from '@/lib/contracts/Result';
/**
* Domain error type for services
@@ -35,16 +34,19 @@ export type DomainError =
/**
* Service interface for orchestration operations
* All service methods must return Result with domain errors
*
* Design Decision: Services with multiple methods CANNOT use a single generic type
* because each method may return different DTOs. Instead:
*
* 1. Single-method services (PageQueries, Mutations): Use Service<TApiDto, TError>
* 2. Multi-method services: Don't implement this interface, just follow the pattern
*
* All service methods must return Promise<Result<T, DomainError>> for type-safe error handling.
*
* Type Parameters:
* - TApiDto: The API Transport DTO type returned on success
* - TError: The domain error type (defaults to DomainError)
*/
export interface Service<TApiDto = unknown, TError extends DomainError = DomainError> {
/**
* Execute a service operation
* Returns Result with API DTO or Domain Error
*/
execute(...args: unknown[]): Promise<Result<TApiDto, TError>>;
export interface Service {
// No specific methods - just a marker type
}

View File

@@ -4,6 +4,7 @@ import { SessionGateway } from '@/lib/gateways/SessionGateway';
import { handleAuthFlow } from '@/lib/auth/AuthFlowRouter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
import { routeMatchers } from '@/lib/routing/RouteConfig';
import { SearchParamBuilder } from '@/lib/routing/search-params/SearchParamBuilder';
const logger = new ConsoleLogger();
@@ -78,7 +79,7 @@ export async function middleware(request: NextRequest) {
} catch (error) {
logger.error('[MIDDLEWARE] Error in auth flow', error instanceof Error ? error : new Error(String(error)));
// Fallback: redirect to login if there's an error
return NextResponse.redirect(new URL(`/auth/login?returnTo=${encodeURIComponent(pathname)}`, request.url));
return NextResponse.redirect(new URL(`/auth/login${SearchParamBuilder.auth(pathname)}`, request.url));
}
logger.info('[MIDDLEWARE] Decision summary', {
@@ -121,4 +122,4 @@ export const config = {
*/
'/((?!_next/static|_next/image|_next/data|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|mp4|webm|mov|avi)$).*)',
],
};
};