website refactor

This commit is contained in:
2026-01-12 01:01:49 +01:00
parent 5ca6023a5a
commit fefd8d1cd6
294 changed files with 4628 additions and 4991 deletions

View File

@@ -3,225 +3,245 @@
"es2022": true,
"node": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2022
},
"ignorePatterns": ["**/dist/**", "**/*.d.ts"],
"settings": {
"import/resolver": {
"typescript": {}
},
"boundaries/elements": [
{
"type": "website",
"pattern": "apps/website/**/*"
},
{
"type": "api",
"pattern": "apps/api/**/*"
},
{
"type": "adapters",
"pattern": ["adapters/**/*", "@adapters/**/*"]
},
{
"type": "core",
"pattern": ["core/**/*", "@core/**/*"]
}
]
},
"ignorePatterns": [
"**/dist/**",
"**/*.d.ts"
],
"overrides": [
{
"files": ["**/index.ts", "**/index.tsx"],
"files": [
"**/index.ts",
"**/index.tsx"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "index.ts files are forbidden. Use explicit file names instead (e.g., UserService.ts, not index.ts)."
"message": "index.ts files are forbidden. Use explicit file names instead (e.g., UserService.ts, not index.ts).",
"selector": "Program"
}
]
}
},
{
"files": ["core/*/application/ports/*/*.ts"],
"files": [
"core/*/application/ports/*/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSInterfaceDeclaration[id.name=/^Get.*Port$/]",
"message": "Port interface names should not start with 'Get'. Use descriptive names without the 'Get' prefix."
"message": "Port interface names should not start with 'Get'. Use descriptive names without the 'Get' prefix.",
"selector": "TSInterfaceDeclaration[id.name=/^Get.*Port$/]"
}
]
}
},
{
"files": ["core/**/*.ts"],
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/Blocker$/], TSInterfaceDeclaration[id.name=/Blocker$/]",
"message": "Blocker classes/interfaces are not allowed in core. Use Guards in backend."
"message": "Blocker classes/interfaces are not allowed in core. Use Guards in backend.",
"selector": "TSClassDeclaration[id.name=/Blocker$/], TSInterfaceDeclaration[id.name=/Blocker$/]"
},
{
"selector": "TSClassDeclaration[id.name=/Presenter$/], TSInterfaceDeclaration[id.name=/Presenter$/]",
"message": "Presenter classes/interfaces are not allowed in core. Presenters belong in API or frontend layers."
"message": "Presenter classes/interfaces are not allowed in core. Presenters belong in API or frontend layers.",
"selector": "TSClassDeclaration[id.name=/Presenter$/], TSInterfaceDeclaration[id.name=/Presenter$/]"
},
{
"selector": "TSClassDeclaration[id.name=/Dto$/], TSInterfaceDeclaration[id.name=/Dto$/]",
"message": "DTO classes/interfaces are not allowed in core. DTOs belong in API or frontend layers."
"message": "DTO classes/interfaces are not allowed in core. DTOs belong in API or frontend layers.",
"selector": "TSClassDeclaration[id.name=/Dto$/], TSInterfaceDeclaration[id.name=/Dto$/]"
},
{
"selector": "TSClassDeclaration[id.name=/ViewModel$/], TSInterfaceDeclaration[id.name=/ViewModel$/]",
"message": "ViewModel classes/interfaces are not allowed in core. View Models belong in frontend."
"message": "ViewModel classes/interfaces are not allowed in core. View Models belong in frontend.",
"selector": "TSClassDeclaration[id.name=/ViewModel$/], TSInterfaceDeclaration[id.name=/ViewModel$/]"
},
{
"selector": "TSClassDeclaration[id.name=/CommandModel$/], TSInterfaceDeclaration[id.name=/CommandModel$/]",
"message": "CommandModel classes/interfaces are not allowed in core. Command Models belong in frontend."
"message": "CommandModel classes/interfaces are not allowed in core. Command Models belong in frontend.",
"selector": "TSClassDeclaration[id.name=/CommandModel$/], TSInterfaceDeclaration[id.name=/CommandModel$/]"
}
]
}
},
{
"files": ["core/**/application/dto/**/*.ts", "core/**/application/dtos/**/*.ts"],
"files": [
"core/**/application/dto/**/*.ts",
"core/**/application/dtos/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/application/dto is forbidden. Use application result models + output ports; DTOs belong in API/website layers."
"message": "core/*/application/dto is forbidden. Use application result models + output ports; DTOs belong in API/website layers.",
"selector": "Program"
}
]
}
},
{
"files": ["core/**/infrastructure/**/*.ts"],
"files": [
"core/**/infrastructure/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/infrastructure is forbidden. Implementations must live in adapters/ and be wired in apps/."
"message": "core/*/infrastructure is forbidden. Implementations must live in adapters/ and be wired in apps/.",
"selector": "Program"
}
]
}
},
{
"files": ["core/**/domain/ports/**/*.ts"],
"files": [
"core/**/domain/ports/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/domain/ports is forbidden. Ports belong in application/ports (or shared application layer), not domain."
"message": "core/*/domain/ports is forbidden. Ports belong in application/ports (or shared application layer), not domain.",
"selector": "Program"
}
]
}
},
{
"files": ["core/**/shared/presentation/**/*.ts"],
"files": [
"core/**/shared/presentation/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/shared/presentation is forbidden. Presentation belongs in API or website layers."
"message": "core/shared/presentation is forbidden. Presentation belongs in API or website layers.",
"selector": "Program"
}
]
}
},
{
"files": ["apps/website/**/*.ts"],
"files": [
"apps/website/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/Guard$/], TSInterfaceDeclaration[id.name=/Guard$/]",
"message": "Guard classes/interfaces are not allowed in frontend. Use Blockers in frontend."
"message": "Guard classes/interfaces are not allowed in frontend. Use Blockers in frontend.",
"selector": "TSClassDeclaration[id.name=/Guard$/], TSInterfaceDeclaration[id.name=/Guard$/]"
}
]
}
},
{
"files": ["apps/api/**/*.ts", "apps/website/lib/dtos/**/*.ts"],
"files": [
"apps/api/**/*.ts",
"apps/website/lib/dtos/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSEnumDeclaration[id.name=/^(?!.*Enum$).+/]",
"message": "Transport enums must end with 'Enum'."
"message": "Transport enums must end with 'Enum'.",
"selector": "TSEnumDeclaration[id.name=/^(?!.*Enum$).+/]"
}
]
}
},
{
"files": ["core/*/application/use-cases/*.ts"],
"files": [
"core/*/application/use-cases/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/^(?!.*UseCase$).+/]",
"message": "Use Case classes must end with 'UseCase'."
"message": "Use Case classes must end with 'UseCase'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*UseCase$).+/]"
}
]
}
},
{
"files": ["core/*/application/services/*.ts"],
"files": [
"core/*/application/services/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/^(?!.*Service$).+/]",
"message": "Application Service classes must end with 'Service'."
"message": "Application Service classes must end with 'Service'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*Service$).+/]"
}
]
}
},
{
"files": ["apps/website/lib/view-models/*.ts"],
"files": [
"apps/website/lib/view-models/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/^(?!.*ViewModel$).+/]",
"message": "View Model classes must end with 'ViewModel'."
"message": "View Model classes must end with 'ViewModel'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*ViewModel$).+/]"
}
]
}
},
{
"files": ["apps/website/lib/commands/*.ts"],
"files": [
"apps/website/lib/commands/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSClassDeclaration[id.name=/^(?!.*CommandModel$).+/]",
"message": "Command Model classes must end with 'CommandModel'."
"message": "Command Model classes must end with 'CommandModel'.",
"selector": "TSClassDeclaration[id.name=/^(?!.*CommandModel$).+/]"
}
]
}
},
{
"files": ["apps/website/app/**/page.tsx", "apps/website/app/**/page.ts", "apps/website/app/**/layout.tsx", "apps/website/app/**/layout.ts"],
"files": [
"apps/website/app/**/page.tsx",
"apps/website/app/**/page.ts",
"apps/website/app/**/layout.tsx",
"apps/website/app/**/layout.ts"
],
"rules": {
"import/no-default-export": "off",
"no-restricted-syntax": [
"error",
{
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]",
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor')."
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor').",
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]"
}
]
}
},
{
"files": ["**/*.ts", "**/*.tsx"],
"extends": [
"plugin:import/recommended",
"plugin:import/typescript"
],
"files": [
"**/*.ts",
"**/*.tsx"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "boundaries", "import"],
"extends": ["plugin:import/recommended", "plugin:import/typescript"],
"plugins": [
"@typescript-eslint",
"boundaries",
"import"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": "error",
@@ -231,20 +251,39 @@
"default": "disallow",
"rules": [
{
"from": ["website"],
"allow": ["website"]
"allow": [
"website"
],
"from": [
"website"
]
},
{
"from": ["api"],
"allow": ["api", "adapters", "core"]
"allow": [
"api",
"adapters",
"core"
],
"from": [
"api"
]
},
{
"from": ["adapters"],
"allow": ["adapters", "core"]
"allow": [
"adapters",
"core"
],
"from": [
"adapters"
]
},
{
"from": ["core"],
"allow": ["core"]
"allow": [
"core"
],
"from": [
"core"
]
}
]
}
@@ -254,171 +293,240 @@
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Default exports are forbidden. Use named exports instead."
"message": "Default exports are forbidden. Use named exports instead.",
"selector": "ExportDefaultDeclaration"
},
{
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]",
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor')."
"message": "Interface names should not start with 'I'. Use descriptive names without the 'I' prefix (e.g., 'LiverCompositor' instead of 'ILiveryCompositor').",
"selector": "TSInterfaceDeclaration[id.name=/^I[A-Z]/]"
}
]
}
},
{
"files": ["core/**/*.ts"],
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Default exports are forbidden. Use named exports instead."
"message": "Default exports are forbidden. Use named exports instead.",
"selector": "ExportDefaultDeclaration"
}
]
}
},
{
"files": ["apps/website/**/*.tsx", "apps/website/**/*.ts"],
"files": [
"apps/website/**/*.tsx",
"apps/website/**/*.ts"
],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "TSInterfaceDeclaration[id.name=/ViewModel$/], TSTypeAliasDeclaration[id.name=/ViewModel$/], TSClassDeclaration[id.name=/ViewModel$/]",
"message": "ViewModel types must be defined in apps/website/lib/view-models, not in components."
},
{
"selector": "TSInterfaceDeclaration[id.name=/DTO$/], TSTypeAliasDeclaration[id.name=/DTO$/], TSClassDeclaration[id.name=/DTO$/]",
"message": "DTO types are forbidden in website components. Use ViewModels instead."
}
],
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "@core/racing",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/racing"
},
{
"name": "@core/analytics",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/analytics"
},
{
"name": "@core/identity",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/identity"
},
{
"name": "@core/media",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/media"
},
{
"name": "@core/notifications",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/notifications"
},
{
"name": "@core/payments",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/payments"
},
{
"name": "@core/shared",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/shared"
},
{
"name": "@core/social",
"message": "Imports from @core are forbidden in website components"
"message": "Imports from @core are forbidden in website components",
"name": "@core/social"
},
{
"name": "@adapters",
"message": "Imports from @adapters are forbidden in website components"
"message": "Imports from @adapters are forbidden in website components",
"name": "@adapters"
},
{
"name": "@api",
"message": "Imports from @api are forbidden in website components"
"message": "Imports from @api are forbidden in website components",
"name": "@api"
}
],
"patterns": [
{
"group": ["@core/*"],
"group": [
"@core/*"
],
"message": "Imports from @core are forbidden in website components"
},
{
"group": ["@adapters/*"],
"group": [
"@adapters/*"
],
"message": "Imports from @adapters are forbidden in website components"
},
{
"group": ["@api/*"],
"group": [
"@api/*"
],
"message": "Imports from @api are forbidden in website components"
}
]
}
],
"no-restricted-syntax": [
"error",
{
"message": "ViewModel types must be defined in apps/website/lib/view-models, not in components.",
"selector": "TSInterfaceDeclaration[id.name=/ViewModel$/], TSTypeAliasDeclaration[id.name=/ViewModel$/], TSClassDeclaration[id.name=/ViewModel$/]"
},
{
"message": "DTO types are forbidden in website components. Use ViewModels instead.",
"selector": "TSInterfaceDeclaration[id.name=/DTO$/], TSTypeAliasDeclaration[id.name=/DTO$/], TSClassDeclaration[id.name=/DTO$/]"
}
]
}
},
{
"files": [
"apps/api/**/*.test.ts",
"apps/api/**/*.test.tsx"
],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"no-restricted-syntax": "error"
}
},
{
"files": [
"tests/**/*.ts"
],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Integration tests must use in-memory adapters, not core directly",
"name": "@core/*"
},
{
"message": "Integration tests must use in-memory adapters only",
"name": "@adapters/*"
}
]
}
]
}
},
{
"files": ["apps/api/**/*.test.ts", "apps/api/**/*.test.tsx"],
"files": [
"tests/e2e/**/*.ts"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"no-restricted-syntax": "off"
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": [
"**/inmemory/**"
],
"message": "E2E tests must use TypeORM/PostgreSQL, not in-memory adapters"
}
]
}
]
}
},
{
"files": ["tests/**/*.ts"],
"files": [
"core/**/*.ts"
],
"rules": {
"no-restricted-imports": ["error", {
"paths": [
{
"name": "@core/*",
"message": "Integration tests must use in-memory adapters, not core directly"
},
{
"name": "@adapters/*",
"message": "Integration tests must use in-memory adapters only"
}
]
}]
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Use @testing/* from adapters/testing",
"name": "testing"
},
{
"message": "Core layer should not depend on testing utilities",
"name": "@testing/*"
}
]
}
]
}
},
{
"files": ["tests/e2e/**/*.ts"],
"files": [
"adapters/**/*.ts"
],
"rules": {
"no-restricted-imports": ["error", {
"patterns": [
{
"group": ["**/inmemory/**"],
"message": "E2E tests must use TypeORM/PostgreSQL, not in-memory adapters"
}
]
}]
}
},
{
"files": ["core/**/*.ts"],
"rules": {
"no-restricted-imports": ["error", {
"paths": [
{
"name": "testing",
"message": "Use @testing/* from adapters/testing"
},
{
"name": "@testing/*",
"message": "Core layer should not depend on testing utilities"
}
]
}]
}
},
{
"files": ["adapters/**/*.ts"],
"rules": {
"no-restricted-imports": ["error", {
"paths": [
{
"name": "testing",
"message": "Use @testing/* from adapters/testing"
}
]
}]
"no-restricted-imports": [
"error",
{
"paths": [
{
"message": "Use @testing/* from adapters/testing",
"name": "testing"
}
]
}
]
}
}
]
],
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module"
},
"settings": {
"boundaries/elements": [
{
"pattern": "apps/website/**/*",
"type": "website"
},
{
"pattern": "apps/api/**/*",
"type": "api"
},
{
"pattern": [
"adapters/**/*",
"@adapters/**/*"
],
"type": "adapters"
},
{
"pattern": [
"core/**/*",
"@core/**/*"
],
"type": "core"
}
],
"import/resolver": {
"typescript": {}
}
}
}