feat(eslint-config): add boundaries plugin enforcing app→feature→core graph

- Install eslint-plugin-boundaries@^4.2.2 to enforce three-tag boundary model
- Configure element types: app, core-composition (core-api/core-cms), core, feature, tooling
- Enforce unidirectional dependency graph: apps→features→core, core-composition→features
- Add eslint.config.js to all 17 packages and apps (required for ESLint 9 flat config)
- Fix pre-existing linting issues to achieve clean lint pass

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 09:21:01 +02:00
parent acae859773
commit 22bee5362f
24 changed files with 167 additions and 7 deletions

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" /> /// <reference path="./.next/types/routes.d.ts" />

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" /> /// <reference path="./.next/types/routes.d.ts" />

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -6,6 +6,7 @@ import type { SanitizedConfig as _SanitizedConfig } from "payload";
// //
// Until then it's a no-op that intentionally accepts (and ignores) the // Until then it's a no-op that intentionally accepts (and ignores) the
// SanitizedConfig argument so app-boot code can call it uniformly. // SanitizedConfig argument so app-boot code can call it uniformly.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function bindProductionAuth(_config: _SanitizedConfig): void { export function bindProductionAuth(_config: _SanitizedConfig): void {
// Default mock bindings from `module.ts` already loaded by container.ts; // Default mock bindings from `module.ts` already loaded by container.ts;
// nothing to swap. // nothing to swap.

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -1,7 +1,3 @@
import type { AuthRouter } from "@repo/auth";
import type { BlogRouter } from "@repo/blog";
import type { MarketingPagesRouter } from "@repo/marketing-pages";
import type { NavigationRouter } from "@repo/navigation";
import { router } from "@repo/core-shared/trpc/init"; import { router } from "@repo/core-shared/trpc/init";
import { authRouter } from "@repo/auth/api"; import { authRouter } from "@repo/auth/api";
import { blogRouter } from "@repo/blog/api"; import { blogRouter } from "@repo/blog/api";

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -1,7 +1,7 @@
import { forwardRef, type InputHTMLAttributes } from "react"; import { forwardRef, type InputHTMLAttributes } from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../lib/utils";
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {} export type InputProps = InputHTMLAttributes<HTMLInputElement>;
export const Input = forwardRef<HTMLInputElement, InputProps>( export const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => { ({ className, type, ...props }, ref) => {

View File

@@ -1,7 +1,7 @@
import { forwardRef, type LabelHTMLAttributes } from "react"; import { forwardRef, type LabelHTMLAttributes } from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../lib/utils";
export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {} export type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;
export const Label = forwardRef<HTMLLabelElement, LabelProps>( export const Label = forwardRef<HTMLLabelElement, LabelProps>(
({ className, ...props }, ref) => { ({ className, ...props }, ref) => {

View File

@@ -2,9 +2,10 @@ import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier"; import eslintConfigPrettier from "eslint-config-prettier";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
import turboPlugin from "eslint-plugin-turbo"; import turboPlugin from "eslint-plugin-turbo";
import boundaries from "eslint-plugin-boundaries";
export default [ export default [
{ ignores: ["dist/**", "node_modules/**"] }, { ignores: ["dist/**", "node_modules/**", ".next/**", ".turbo/**"] },
js.configs.recommended, js.configs.recommended,
...tseslint.configs.recommended, ...tseslint.configs.recommended,
eslintConfigPrettier, eslintConfigPrettier,
@@ -14,4 +15,33 @@ export default [
"turbo/no-undeclared-env-vars": "warn", "turbo/no-undeclared-env-vars": "warn",
}, },
}, },
{
plugins: { boundaries },
settings: {
"boundaries/elements": [
{ type: "app", pattern: "apps/*" },
{ type: "core-composition", pattern: "packages/core-api" },
{ type: "core-composition", pattern: "packages/core-cms" },
{ type: "core", pattern: "packages/core-*" },
{ type: "tooling", pattern: "packages/eslint-config" },
{ type: "tooling", pattern: "packages/typescript-config" },
{ type: "feature", pattern: "packages/!(core-*|eslint-config|typescript-config)" },
],
},
rules: {
"boundaries/element-types": [
2,
{
default: "disallow",
rules: [
{ from: "app", allow: ["app", "core", "core-composition", "feature", "tooling"] },
{ from: "feature", allow: ["core", "tooling"] },
{ from: "core", allow: ["core", "tooling"] },
{ from: "core-composition", allow: ["core", "feature", "tooling"] },
{ from: "tooling", allow: ["tooling"] },
],
},
],
},
},
]; ];

View File

@@ -0,0 +1,3 @@
import baseConfig from "./base.js";
export default baseConfig;

View File

@@ -14,6 +14,7 @@
"@typescript-eslint/parser": "^8.25.0", "@typescript-eslint/parser": "^8.25.0",
"eslint": "^9.20.0", "eslint": "^9.20.0",
"eslint-config-prettier": "^10.1.0", "eslint-config-prettier": "^10.1.0",
"eslint-plugin-boundaries": "^4.2.2",
"eslint-plugin-turbo": "^2.4.0", "eslint-plugin-turbo": "^2.4.0",
"typescript-eslint": "^8.25.0" "typescript-eslint": "^8.25.0"
} }

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/eslint-config/base";
export default baseConfig;

85
pnpm-lock.yaml generated
View File

@@ -460,6 +460,9 @@ importers:
eslint-config-prettier: eslint-config-prettier:
specifier: ^10.1.0 specifier: ^10.1.0
version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) version: 10.1.8(eslint@9.39.4(jiti@2.6.1))
eslint-plugin-boundaries:
specifier: ^4.2.2
version: 4.2.2(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))
eslint-plugin-turbo: eslint-plugin-turbo:
specifier: ^2.4.0 specifier: ^2.4.0
version: 2.9.4(eslint@9.39.4(jiti@2.6.1))(turbo@2.9.4) version: 2.9.4(eslint@9.39.4(jiti@2.6.1))(turbo@2.9.4)
@@ -2819,6 +2822,14 @@ packages:
dateformat@4.6.3: dateformat@4.6.3:
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@@ -3053,6 +3064,36 @@ packages:
peerDependencies: peerDependencies:
eslint: '>=7.0.0' eslint: '>=7.0.0'
eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
eslint-module-utils@2.8.1:
resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint:
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
eslint-plugin-boundaries@4.2.2:
resolution: {integrity: sha512-cjwpZqkCXgfz953bc74uDetOtGVxwgMgNZ7hAKi6Oxck+x4oY6Z/9DzgPqAYhtQdSNHFVg+vhft/lSL+snPMQg==}
engines: {node: '>=14.0.0'}
peerDependencies:
eslint: '>=6.0.0'
eslint-plugin-turbo@2.9.4: eslint-plugin-turbo@2.9.4:
resolution: {integrity: sha512-8gIBw+QC7jLOjYLthoLYcDGf0pEefAukkMAl60exv3HkS3NO7AuXzzFjY3iDGDc4s5mbkC6f/692DCdb3XHwMg==} resolution: {integrity: sha512-8gIBw+QC7jLOjYLthoLYcDGf0pEefAukkMAl60exv3HkS3NO7AuXzzFjY3iDGDc4s5mbkC6f/692DCdb3XHwMg==}
peerDependencies: peerDependencies:
@@ -3721,6 +3762,10 @@ packages:
micromark@4.0.2: micromark@4.0.2:
resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
micromatch@4.0.7:
resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
engines: {node: '>=8.6'}
minimatch@10.2.5: minimatch@10.2.5:
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
engines: {node: 18 || 20 || >=22} engines: {node: 18 || 20 || >=22}
@@ -6976,6 +7021,10 @@ snapshots:
dateformat@4.6.3: {} dateformat@4.6.3: {}
debug@3.2.7:
dependencies:
ms: 2.1.3
debug@4.4.3: debug@4.4.3:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@@ -7174,6 +7223,37 @@ snapshots:
dependencies: dependencies:
eslint: 9.39.4(jiti@2.6.1) eslint: 9.39.4(jiti@2.6.1)
eslint-import-resolver-node@0.3.9:
dependencies:
debug: 3.2.7
is-core-module: 2.16.1
resolve: 1.22.11
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.8.1(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.58.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.4(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
eslint-plugin-boundaries@4.2.2(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)):
dependencies:
chalk: 4.1.2
eslint: 9.39.4(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.1(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1))
micromatch: 4.0.7
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
eslint-plugin-turbo@2.9.4(eslint@9.39.4(jiti@2.6.1))(turbo@2.9.4): eslint-plugin-turbo@2.9.4(eslint@9.39.4(jiti@2.6.1))(turbo@2.9.4):
dependencies: dependencies:
dotenv: 16.0.3 dotenv: 16.0.3
@@ -7930,6 +8010,11 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
micromatch@4.0.7:
dependencies:
braces: 3.0.3
picomatch: 2.3.2
minimatch@10.2.5: minimatch@10.2.5:
dependencies: dependencies:
brace-expansion: 5.0.5 brace-expansion: 5.0.5