diff --git a/CLAUDE.md b/CLAUDE.md index 33ea68e1a..d12a8f758 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -191,13 +191,21 @@ Before finishing behavior changes or bug fixes, follow `Regression Prevention An ### Linting ```bash -# Lint frontend -nx lint web +# Lint all projects (what CI enforces on every PR) +pnpm run lint -# Lint backend +# Lint a single project +nx lint web nx lint electron-backend ``` +CI runs lint for every project (`.github/workflows/ci.yml`). This enforces the +Nx module-boundary tags, the legacy bare-alias ban, and a `max-lines` ESLint +rule (hard maximum 400 lines per TypeScript file). Pre-existing oversized files +are baselined in `tools/eslint/max-lines-baseline.mjs`; regenerate the baseline +with `node tools/eslint/generate-max-lines-baseline.mjs` after splitting a file. +Never add new files to the baseline. + ### Documentation And Wiki Export ```bash diff --git a/docs/architecture/nx-workspace-boundaries.md b/docs/architecture/nx-workspace-boundaries.md index 4207660c8..44a43772c 100644 --- a/docs/architecture/nx-workspace-boundaries.md +++ b/docs/architecture/nx-workspace-boundaries.md @@ -82,3 +82,16 @@ playback, or EPG data belongs in `libs/portal/shared/data-access`, not `libs/portal/shared/util`. That keeps pure collection helpers importable by Xtream/Stalker data-access libraries while allowing shared UI to use provider-specific collection services without creating cycles. + +Note: `workspace-shell-util` (`libs/workspace/shell/util`) is tagged +`type:data-access` despite its path. It exports injectable services such as +`WorkspaceStartupPreferencesService` that depend on `@iptvnator/services`, and +it must stay eagerly importable from `apps/web/src/app/app.routes.ts` without +pulling the lazy-loaded workspace shell feature bundle into the initial chunk. + +## CI Enforcement + +The `Lint` job in `.github/workflows/ci.yml` runs +`pnpm nx run-many --target=lint --all` on every PR, so +`@nx/enforce-module-boundaries` violations, legacy bare-alias imports, and +`max-lines` violations fail CI. Run `pnpm run lint` locally before pushing. diff --git a/docs/architecture/validation-map.md b/docs/architecture/validation-map.md index 7df36a6de..089d52686 100644 --- a/docs/architecture/validation-map.md +++ b/docs/architecture/validation-map.md @@ -17,16 +17,36 @@ pnpm nx show projects --withTarget e2e | ---------------------------------- | ----------------------------------- | | Angular renderer entry points | `pnpm run typecheck:web` | | Electron main process entry points | `pnpm run typecheck:backend` | -| Curated CI unit suite | `pnpm run test:unit:ci` | +| Full unit suite (all projects) | `pnpm run test:unit:ci` | | EPG data access | `pnpm nx test epg-data-access` | | Workspace shell utilities | `pnpm nx test workspace-shell-util` | | Shared SQLite schema/connection | `pnpm nx test database` | | Packaging metadata | `pnpm nx test packaging` | +## Lint + +```bash +pnpm run lint # nx run-many --target=lint --all +pnpm nx lint # single project +``` + +The CI workflow (`.github/workflows/ci.yml`) runs lint for every project on +each PR. This enforces `@nx/enforce-module-boundaries` (scope/domain/type tag +constraints), the legacy bare-alias ban, and the `max-lines` file-size rule +(hard maximum 400 lines per TypeScript file). Files that predate the +`max-lines` rule are baselined in `tools/eslint/max-lines-baseline.mjs`; after +splitting a baselined file below the limit, regenerate the list with +`node tools/eslint/generate-max-lines-baseline.mjs`. Never add new files to +the baseline. + ## Coverage Tiers Use `tools/coverage/coverage-policy.json` as the source of truth for coverage -ownership. +ownership. Every project with a `test` target must be classified in a tier; +`pnpm run coverage:policy:check` (part of `coverage:ci`) fails CI when a new +project is missing from the policy or a listed project no longer exists. +CI runs Tier A with coverage (uploaded to Codecov) and Tier B/C tests without +coverage. | Tier | Rule | Validation | | --- | --- | --- |