mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 02:46:16 -08:00
Pipeline audit follow-up: reduce wasted runner time on PRs and tighten CI security, without reducing what actually gets validated. Runner-time waste: - Concurrency with PR-only cancel-in-progress on CI, E2E, and docker-build, so a new push cancels the previous commit's still-running checks. Non-PR runs use the unique run_id as the group, because GitHub keeps at most one pending run per group even with cancel-in-progress: false — a shared ref group could silently drop a queued master run. - paths-ignore for docs-only changes (Markdown, docs/, .plans/, .codex/, .claude/) on the Electron build matrix and the E2E suites; E2E also skips apps/website/**. The build workflow keeps apps/website/** because its Linux job builds the website to verify AppStream assets. Tag pushes are unaffected: GitHub does not evaluate paths filters for tags. - PRs lint affected projects only; master pushes keep the full run-many. Lint-global inputs (eslint.config.mjs, tools/eslint/**) now mark all 41 lint projects affected, including the run-commands targets database and packaging, so the max-lines baseline cannot be widened without lint. Hardening: - Explicit least-privilege permissions on CI, E2E, and build-and-make; the create-release job keeps its job-level contents: write. The repository default workflow token was switched to read-only. - New actionlint job (image pinned by digest, shellcheck at warning+), with the shared-anchor false positive suppressed in .github/actionlint.yaml. Fixed one real finding: unquoted $GITHUB_OUTPUT. - .github/dependabot.yml: weekly cadence, minor+patch grouped per ecosystem (npm, GitHub Actions, Docker), majors stay individual PRs. Docs updated: CLAUDE.md, docs/architecture/nx-workspace-boundaries.md, and docs/architecture/validation-map.md now describe affected-lint on PRs and the E2E path-filter exceptions.
101 lines
3.6 KiB
Markdown
101 lines
3.6 KiB
Markdown
# Nx Workspace Boundaries
|
|
|
|
This document records the current monorepo boundary conventions for IPTVnator.
|
|
|
|
## Fresh Worktree Bootstrap
|
|
|
|
Install dependencies before using Nx discovery or targets:
|
|
|
|
```bash
|
|
pnpm install --frozen-lockfile
|
|
pnpm nx show projects
|
|
```
|
|
|
|
`pnpm nx show projects` depends on the workspace-local Nx packages under
|
|
`node_modules`. In a fresh worktree without dependencies it will fail before it
|
|
can inspect project metadata.
|
|
|
|
## Project Tags
|
|
|
|
Every Nx project should carry three tag families in `project.json`:
|
|
|
|
1. `scope:*` - ownership area, for example `scope:portal`, `scope:workspace`,
|
|
`scope:shared`, `scope:electron`, `scope:e2e`, or `scope:dev-tools`.
|
|
2. `domain:*` - product/runtime domain, for example `domain:xtream`,
|
|
`domain:stalker`, `domain:m3u`, `domain:playback`, `domain:web`, or
|
|
`domain:shared-runtime`.
|
|
3. `type:*` - architectural role, for example `type:app`, `type:e2e`,
|
|
`type:dev-app`, `type:feature`, `type:ui`, `type:data-access`,
|
|
`type:util`, `type:tool`, or `type:website`.
|
|
|
|
`eslint.config.mjs` uses these tags with `@nx/enforce-module-boundaries`.
|
|
When adding a project, choose tags before adding imports so dependency direction
|
|
is clear from the start.
|
|
|
|
## Import Aliases
|
|
|
|
Use scoped `@iptvnator/*` aliases from `tsconfig.base.json`.
|
|
|
|
Examples:
|
|
|
|
```ts
|
|
import { SettingsStore } from '@iptvnator/services';
|
|
import { Playlist } from '@iptvnator/shared/interfaces';
|
|
import { DialogService } from '@iptvnator/ui/components';
|
|
```
|
|
|
|
Do not introduce legacy bare aliases such as:
|
|
|
|
- `components`
|
|
- `m3u-state`
|
|
- `m3u-utils`
|
|
- `services`
|
|
- `shared-interfaces`
|
|
- `shared-portals`
|
|
- `remote-control`
|
|
- `database`
|
|
- `database-schema`
|
|
- `database-path-utils`
|
|
- `workspace-dashboard-feature`
|
|
- `workspace-dashboard-data-access`
|
|
|
|
The lint config blocks these aliases so new code uses the same visible
|
|
namespace and ownership convention.
|
|
|
|
Buildable libraries that have a local `package.json` should use the same public
|
|
name as their scoped alias. Nx uses `package.json.name` when it rewrites
|
|
buildable dependency paths to `dist/` during `@nx/js:tsc` builds.
|
|
|
|
## Dependency Direction
|
|
|
|
- `type:feature` may use `type:feature`, `type:ui`, `type:data-access`, and
|
|
`type:util`.
|
|
- `type:ui` may use `type:ui`, `type:data-access`, and `type:util`.
|
|
- `type:data-access` may use `type:data-access` and `type:util`.
|
|
- `type:util` may use only `type:util`.
|
|
|
|
If a change needs a dependency in the opposite direction, move the shared
|
|
contract into a lower-level library instead of weakening boundaries.
|
|
|
|
Portal collection orchestration that reads/writes favorites, recent items, live
|
|
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 affected --target=lint` on PRs and
|
|
`pnpm nx run-many --target=lint --all` on master pushes, so
|
|
`@nx/enforce-module-boundaries` violations, legacy bare-alias imports, and
|
|
`max-lines` violations fail CI. Root config or lockfile changes mark every
|
|
project affected, so the boundary rules cannot be dodged on PRs. Run
|
|
`pnpm run lint` locally before pushing.
|