From de71d31a2b89754eea544b6bad1bbc74ff240887 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Thu, 30 Apr 2026 23:16:57 +0200 Subject: [PATCH] chore(tooling): enable eslint-plugin-boundaries in apps/app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 'boundaries' to plugins, the layered-architecture matrix to rules, and the boundaries/elements + boundaries/ignore + boundaries/ include settings per the WS-3 1c audit (Phase A: dev-docs/WS-3-SESSION-1C-AUDIT.md). Phase B sign-off (Bert): - Q1=B — `lib → stores` is DISALLOWED in the matrix; lib/axios.ts is refactored in the next commit. - Q2 — src/views/** added to boundaries/ignore (dead Vuexy file; TECH-DELETE-DEAD-VIEWS backlog item lands with the docs commit). - Q3 — `navigation` allowed to import `types`, `utils` (forward headroom). - Q4 — sub-zone enforcement deferred to TECH-WS3-BOUNDARIES-SUBZONES (lands when WS-3 PR-B brings the §4.2 components/{organizer,portal, shared} + pages/{(auth),portal,…} structure). Forward-flag carried into the inline comment: when src/plugins/1.router/ migrates to a top-level src/router/ in a later WS-3 PR, add a { type: 'router', pattern: 'src/router/**' } element and a { from: 'router', allow: ['types','utils','lib','plugins','stores'] } rule. Doc-side flag also lands in the ARCH-CONSOLIDATION 1c entry. Boundaries plugin v6 emits a deprecation warning that the 'element-types' selector format is legacy (v5 syntax); the rule still works on v5-compatible config and migrating to v6 object- selector syntax is out of scope per the prompt's "only the two .eslintrc.cjs changes listed are permitted" constraint. Filing a TECH-BOUNDARIES-V6-SELECTOR-MIGRATION backlog item (in the docs commit) so the migration happens deliberately. Lint count after this commit: 4 errors, all in lib/axios.ts (lines 3, 4, 61, 72 — the 2 static + 2 dynamic store imports). The plugin treats both static AND dynamic `await import('@/stores/...')` as boundary edges; this is a deliberate intermediate state. The next commit (refactor) resolves all 4 to land at lint = 0. Tests + typecheck verified green (boundary errors are lint-only). Co-Authored-By: Claude --- apps/app/.eslintrc.cjs | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/apps/app/.eslintrc.cjs b/apps/app/.eslintrc.cjs index 3625abb3..4129ea26 100644 --- a/apps/app/.eslintrc.cjs +++ b/apps/app/.eslintrc.cjs @@ -32,6 +32,7 @@ module.exports = { '@typescript-eslint', 'regex', 'regexp', + 'boundaries', ], ignorePatterns: [ 'src/plugins/iconify/*.js', @@ -200,12 +201,68 @@ module.exports = { ], '\\.eslintrc\\.cjs', ], + + // Architectural import boundaries (WS-3 1c, audit: + // dev-docs/WS-3-SESSION-1C-AUDIT.md). The matrix is layered: + // types → utils → lib → composables → stores → components → layouts → pages. + // The `lib → stores` edge is intentionally disallowed; lib/axios.ts + // uses dynamic `await import('@/stores/...')` for its 4 store reads + // so the static-import surface stays clean. + // Sub-zone enforcement (components/{organizer,portal,shared}) is a + // backlog item (TECH-WS3-BOUNDARIES-SUBZONES); it lands after the + // §4.2 consolidation directory layout. + // FORWARD-FLAG: when src/plugins/1.router/ migrates to src/router/ + // in a later WS-3 PR, add `{ type: 'router', pattern: 'src/router/**' }` + // to boundaries/elements and `{ from: 'router', allow: ['types', + // 'utils', 'lib', 'plugins', 'stores'] }` to the rules. + 'boundaries/element-types': ['error', { + default: 'disallow', + rules: [ + { from: 'types', allow: ['types'] }, + { from: 'utils', allow: ['types', 'utils'] }, + { from: 'lib', allow: ['types', 'utils', 'lib'] }, + { from: 'plugins', allow: ['types', 'utils', 'lib', 'plugins', 'stores'] }, + { from: 'composables', allow: ['types', 'utils', 'lib', 'composables', 'stores'] }, + { from: 'stores', allow: ['types', 'utils', 'lib', 'composables', 'stores'] }, + { from: 'navigation', allow: ['types', 'utils', 'navigation'] }, + { from: 'components', allow: ['types', 'utils', 'lib', 'composables', 'stores', 'components'] }, + { from: 'layouts', allow: ['types', 'utils', 'lib', 'composables', 'stores', 'navigation', 'components', 'layouts'] }, + { from: 'pages', allow: ['types', 'utils', 'lib', 'composables', 'stores', 'navigation', 'components', 'layouts'] }, + ], + }], + 'boundaries/no-unknown': 'off', // External packages are fine. + 'boundaries/no-unknown-files': 'off', // The ignore list handles vendor/generated. }, settings: { 'import/resolver': { node: true, typescript: {}, }, + + // Element-type assignment: first-match-wins. Order matters. + 'boundaries/elements': [ + { type: 'types', pattern: 'src/types/**' }, + { type: 'utils', pattern: 'src/utils/**' }, + { type: 'lib', pattern: 'src/lib/**' }, + { type: 'plugins', pattern: 'src/plugins/**' }, + { type: 'composables', pattern: 'src/composables/**' }, + { type: 'stores', pattern: 'src/stores/**' }, + { type: 'navigation', pattern: 'src/navigation/**' }, + { type: 'components', pattern: 'src/components/**' }, + { type: 'layouts', pattern: 'src/layouts/**' }, + { type: 'pages', pattern: 'src/pages/**' }, + ], + 'boundaries/ignore': [ + 'src/@core/**', // vendored Vuexy + 'src/@layouts/**', // vendored Vuexy + 'src/views/**', // single dead Vuexy file (zero importers); see TECH-DELETE-DEAD-VIEWS + 'src/App.vue', // orchestration root + 'src/main.ts', // orchestration root + 'src/assets/**', // static media + 'src/styles/**', // SCSS + '**/*.d.ts', // generated declarations + ], + 'boundaries/include': ['src/**/*.{ts,vue,tsx}'], }, overrides: [ // Vue SFCs: the base lines-around-comment rule conflicts with