diff --git a/apps/cms/eslint.config.js b/apps/cms/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/apps/cms/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/apps/cms/next-env.d.ts b/apps/cms/next-env.d.ts
index 830fb59..5277a32 100644
--- a/apps/cms/next-env.d.ts
+++ b/apps/cms/next-env.d.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/triple-slash-reference */
///
///
///
diff --git a/apps/storybook/eslint.config.js b/apps/storybook/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/apps/storybook/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/apps/web-next/eslint.config.js b/apps/web-next/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/apps/web-next/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/apps/web-next/next-env.d.ts b/apps/web-next/next-env.d.ts
index 830fb59..5277a32 100644
--- a/apps/web-next/next-env.d.ts
+++ b/apps/web-next/next-env.d.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/triple-slash-reference */
///
///
///
diff --git a/apps/web-tanstack/eslint.config.js b/apps/web-tanstack/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/apps/web-tanstack/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/auth/eslint.config.js b/packages/auth/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/auth/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/auth/src/di/bind-production.ts b/packages/auth/src/di/bind-production.ts
index 3c4904d..7ee8eb1 100644
--- a/packages/auth/src/di/bind-production.ts
+++ b/packages/auth/src/di/bind-production.ts
@@ -6,6 +6,7 @@ import type { SanitizedConfig as _SanitizedConfig } from "payload";
//
// Until then it's a no-op that intentionally accepts (and ignores) the
// 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 {
// Default mock bindings from `module.ts` already loaded by container.ts;
// nothing to swap.
diff --git a/packages/blog/eslint.config.js b/packages/blog/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/blog/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-api/eslint.config.js b/packages/core-api/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/core-api/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-api/src/root.ts b/packages/core-api/src/root.ts
index 444b570..1228d77 100644
--- a/packages/core-api/src/root.ts
+++ b/packages/core-api/src/root.ts
@@ -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 { authRouter } from "@repo/auth/api";
import { blogRouter } from "@repo/blog/api";
diff --git a/packages/core-cms/eslint.config.js b/packages/core-cms/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/core-cms/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-shared/eslint.config.js b/packages/core-shared/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/core-shared/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-trpc/eslint.config.js b/packages/core-trpc/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/core-trpc/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-ui/eslint.config.js b/packages/core-ui/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/core-ui/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/core-ui/src/atoms/input/input.tsx b/packages/core-ui/src/atoms/input/input.tsx
index 51b3dd0..b925986 100644
--- a/packages/core-ui/src/atoms/input/input.tsx
+++ b/packages/core-ui/src/atoms/input/input.tsx
@@ -1,7 +1,7 @@
import { forwardRef, type InputHTMLAttributes } from "react";
import { cn } from "../../lib/utils";
-export interface InputProps extends InputHTMLAttributes {}
+export type InputProps = InputHTMLAttributes;
export const Input = forwardRef(
({ className, type, ...props }, ref) => {
diff --git a/packages/core-ui/src/atoms/label/label.tsx b/packages/core-ui/src/atoms/label/label.tsx
index 13d0f4e..afc57b1 100644
--- a/packages/core-ui/src/atoms/label/label.tsx
+++ b/packages/core-ui/src/atoms/label/label.tsx
@@ -1,7 +1,7 @@
import { forwardRef, type LabelHTMLAttributes } from "react";
import { cn } from "../../lib/utils";
-export interface LabelProps extends LabelHTMLAttributes {}
+export type LabelProps = LabelHTMLAttributes;
export const Label = forwardRef(
({ className, ...props }, ref) => {
diff --git a/packages/eslint-config/base.js b/packages/eslint-config/base.js
index bc35bef..0971a70 100644
--- a/packages/eslint-config/base.js
+++ b/packages/eslint-config/base.js
@@ -2,9 +2,10 @@ import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";
import tseslint from "typescript-eslint";
import turboPlugin from "eslint-plugin-turbo";
+import boundaries from "eslint-plugin-boundaries";
export default [
- { ignores: ["dist/**", "node_modules/**"] },
+ { ignores: ["dist/**", "node_modules/**", ".next/**", ".turbo/**"] },
js.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier,
@@ -14,4 +15,33 @@ export default [
"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"] },
+ ],
+ },
+ ],
+ },
+ },
];
diff --git a/packages/eslint-config/eslint.config.js b/packages/eslint-config/eslint.config.js
new file mode 100644
index 0000000..5425eef
--- /dev/null
+++ b/packages/eslint-config/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "./base.js";
+
+export default baseConfig;
diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json
index b813bb7..b009120 100644
--- a/packages/eslint-config/package.json
+++ b/packages/eslint-config/package.json
@@ -14,6 +14,7 @@
"@typescript-eslint/parser": "^8.25.0",
"eslint": "^9.20.0",
"eslint-config-prettier": "^10.1.0",
+ "eslint-plugin-boundaries": "^4.2.2",
"eslint-plugin-turbo": "^2.4.0",
"typescript-eslint": "^8.25.0"
}
diff --git a/packages/marketing-pages/eslint.config.js b/packages/marketing-pages/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/marketing-pages/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/media/eslint.config.js b/packages/media/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/media/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/packages/navigation/eslint.config.js b/packages/navigation/eslint.config.js
new file mode 100644
index 0000000..35479e2
--- /dev/null
+++ b/packages/navigation/eslint.config.js
@@ -0,0 +1,3 @@
+import baseConfig from "@repo/eslint-config/base";
+
+export default baseConfig;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ac11ba7..e76a9a1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -460,6 +460,9 @@ importers:
eslint-config-prettier:
specifier: ^10.1.0
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:
specifier: ^2.4.0
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:
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:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
@@ -3053,6 +3064,36 @@ packages:
peerDependencies:
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:
resolution: {integrity: sha512-8gIBw+QC7jLOjYLthoLYcDGf0pEefAukkMAl60exv3HkS3NO7AuXzzFjY3iDGDc4s5mbkC6f/692DCdb3XHwMg==}
peerDependencies:
@@ -3721,6 +3762,10 @@ packages:
micromark@4.0.2:
resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
+ micromatch@4.0.7:
+ resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
+ engines: {node: '>=8.6'}
+
minimatch@10.2.5:
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
engines: {node: 18 || 20 || >=22}
@@ -6976,6 +7021,10 @@ snapshots:
dateformat@4.6.3: {}
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
debug@4.4.3:
dependencies:
ms: 2.1.3
@@ -7174,6 +7223,37 @@ snapshots:
dependencies:
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):
dependencies:
dotenv: 16.0.3
@@ -7930,6 +8010,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ micromatch@4.0.7:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.2
+
minimatch@10.2.5:
dependencies:
brace-expansion: 5.0.5