# S2 — ESLint for the frontend

Status: REFINED

Agreed after the grill-me review; shared understanding confirmed.

## User story

As a frontend maintainer, I want automated lint checks during development and in
CI, so that likely bugs and Angular/TypeScript problems are caught before changes
are accepted or application images are published.

I also want a fast local commit hook where feasible, without losing control of
which changes are included in my commit.

## Scope and boundary with S3

### In scope

- Install and configure compatible ESLint, TypeScript and Angular lint tooling.
- Apply the recommended JavaScript, TypeScript and Angular rules, including
  recommended type-aware checks for TypeScript.
- Lint maintained frontend application code, external and inline Angular HTML
  templates, unit tests, Playwright tests and applicable frontend configuration
  files.
- Fix all existing violations of the agreed rules and verify that the application
  still builds and its tests pass.
- Provide local check and autofix commands, mandatory pipeline enforcement,
  editor support and documentation.
- Introduce a staged-file commit hook only if it meets the agreed performance
  and change-preservation requirements.

### Out of scope

- Additional opinionated coding conventions or stricter rule sets beyond the
  agreed recommended baseline. These belong in S3.
- Backend or Java CI-helper linting.
- Linting dependencies, generated output or generated files such as
  `package-lock.json`.
- A new mandatory Prettier check in CI. Prettier remains the formatting tool;
  this spec adds its local commit-hook use only when the timing budget permits.

## Existing environment

The reviewed frontend uses Angular 22.2.3, Angular CLI/build 22.2.4, TypeScript
6.0.3 and Prettier 3.9.10. TypeScript strict mode and Angular strict-template
checking are already enabled. Prettier configuration already exists.

No ESLint configuration, lint command or active Git commit hook was present at
review. The frontend package is in `agiledancers-fe/`, below the Git root.
Implementation must account for that layout when installing repository hooks.

Choose versions compatible with the installed Angular CLI and TypeScript. Use
supported configuration for those versions rather than copying incompatible
examples or changing framework versions merely to introduce linting.

## Lint commands and rule behavior

- `npm run lint`, executed from `agiledancers-fe/`, checks the entire maintained
  frontend scope without changing files.
- A lint error or warning causes a nonzero exit status. A successful check means
  there are no outstanding ESLint errors or warnings.
- `npm run lint:fix` is an explicit local command that applies supported ESLint
  autofixes. Developers review its changes and resolve any remaining findings.
- CI uses the checking command only and must not repair, format, stage or commit
  source changes itself.
- Keep formatting under the existing Prettier configuration. Do not introduce
  conflicting ESLint formatting rules or redefine formatting conventions in S2.
- Narrow exceptions are permitted when a rule is demonstrably unsuitable. Each
  suppression has a concrete explanation and the smallest applicable scope.
  Do not broadly disable rules merely to avoid investigating existing findings.
- Start with a clean baseline: do not introduce a legacy-violation allowance,
  warning backlog or ignored maintained files to make the initial check pass.
- Fixes preserve application behavior; builds and tests must still pass.

## Pipeline integration

Every branch pipeline must run `npm run lint` immediately after frontend
`npm ci`, before frontend tests, frontend builds and container end-to-end tests.

A failed lint check fails the pipeline and prevents image publication. Its
concrete findings must be visible in the job log and retained in the existing
pipeline diagnostics. The local hook never replaces the full pipeline check.

Integrate this into the existing Java-based pipeline orchestration. Repository
hook installation is skipped during CI and Docker package installation.

## Editor support

Recommend the ESLint extension in the existing VS Code project recommendations.
Do not require automatic fixing or formatting on save. Document how developers
can see findings while editing and run the same check as CI.

## Local commit hook

### File selection and tools

- Only process maintained frontend files staged for the current commit.
- Skip frontend checks for commits without applicable staged frontend changes.
- ESLint only checks; it does not autofix in the hook. Errors and warnings block
  the commit if ESLint is part of the selected hook configuration.
- Prettier may format maintained frontend TypeScript, JavaScript, HTML, CSS and
  JSON configuration files and stage the formatting result automatically.
- Exclude dependencies, build output and generated files such as
  `package-lock.json`.
- If both tools are included, format with Prettier before checking the result
  with ESLint. Do not run modifying operations concurrently on overlapping files.

### Preserve the intended commit

- Support partially staged files: format the version intended for the commit
  while preserving unrelated unstaged changes.
- Automatically staging formatting must not include unrelated local edits or
  change which unrelated files are committed.
- On any hook failure, including an ESLint failure after successful formatting,
  abort the commit and restore the original staged and unstaged state.
- A conflict while reconciling formatting with unstaged edits also aborts the
  commit and restores the original state.
- Report a concrete cause when the hook fails. Do not leave partial formatter,
  staging or temporary-state changes behind.
- Use tooling that supports this behavior with its state-preservation protections
  enabled; the specific hook manager/staged-file runner is an implementation
  choice.

### Three-second performance budget

The budget covers the entire additional hook duration, including file selection,
backup/state handling, tool startup, formatting/checking, restaging and cleanup.
It is a combined budget, not three seconds per tool.

Measure the actual complete hook on the existing development mini-PC for:

1. A single applicable staged frontend file.
2. A mixed commit containing applicable frontend file types.
3. All maintained frontend files staged together.

Use a newly started process and no tool cache for each measured execution,
including cold tool starts. Every measured execution must finish within three
seconds. Record the machine/environment, exact staged scope, commands and timing
results in the implementation evidence. Do not claim the budget based only on
warm cached executions or timings of an individual tool.

Choose the hook configuration from those measurements:

1. Include Prettier and ESLint if the combined complete hook meets the budget.
2. Otherwise omit ESLint from the hook and measure the complete Prettier-only
   hook against the same budget and scenarios.
3. If Prettier-only also fails the budget, do not install an active commit hook.

Do not enforce the budget by killing a writing formatter mid-operation. It is an
acceptance criterion for selecting the hook configuration, not a hard runtime
interrupt that risks incomplete changes. The full type-aware ESLint check remains
mandatory in CI regardless of the selected local hook configuration.

### Installation and operation

If a hook configuration meets the budget, set it up automatically during local
`npm ci`. Skip installation in CI and Docker builds. Document the selected tools,
installation behavior and how a developer can disable the local hook.

If no hook configuration meets the budget, document that result and its timing
evidence. Local lint commands and mandatory pipeline enforcement still apply.

## Documentation

Add an explanation to the root `README.md` for both `npm run lint` and
`npm run lint:fix`, including:

- Run the commands from `agiledancers-fe/`.
- What each command checks or changes and the difference between checking and
  autofixing.
- That errors and warnings fail the checking command, and autofix may leave
  findings requiring manual changes.
- That the pipeline runs the check and blocks publication on failure.
- The selected hook behavior, its measured performance and any omitted checks.
- Automatic local installation, exclusion from CI/Docker installation, and local
  opt-out instructions if a hook is installed.
- Prettier formatting/restaging and preservation of partially staged files,
  including restoration on hook failure, when applicable.

The frontend README may link to the root explanation to keep instructions
consistent. Record the performance evidence with the implementation documentation.

## Acceptance criteria

- [ ] Compatible tooling checks maintained application TypeScript/JavaScript,
      Angular templates, unit tests, Playwright tests and applicable frontend
      configuration using the agreed recommended and type-aware rules.
- [ ] All existing violations are fixed; there is no legacy baseline allowance.
      Frontend builds, unit tests and container end-to-end tests still pass.
- [ ] `npm run lint` checks the full scope without modifications and fails on
      either errors or warnings.
- [ ] `npm run lint:fix` offers explicit local autofixes; CI does not modify source.
- [ ] Formatting remains under Prettier, without conflicting ESLint rules.
- [ ] Any necessary rule suppressions are narrow and concretely justified.
- [ ] Every branch pipeline runs lint immediately after frontend `npm ci` and
      before frontend tests/builds and container E2E; lint failure prevents
      publication and leaves actionable diagnostic output.
- [ ] VS Code recommends ESLint without mandatory fix/format-on-save settings.
- [ ] Complete-hook measurements cover the agreed single-file, mixed-file and
      all-maintained-files cases with fresh processes and no tool cache.
- [ ] The measured three-second budget determines combined tools, Prettier-only
      or no active hook; no writing formatter is forcibly interrupted to meet it.
- [ ] If installed, the hook processes only applicable staged frontend files,
      applies Prettier formatting before any ESLint check, and preserves unrelated
      files and unstaged edits, including partially staged files.
- [ ] A failed installed hook restores the original staged and unstaged state and
      blocks the commit with a concrete explanation.
- [ ] Hook installation is automatic for local `npm ci` when applicable, skipped
      in CI/Docker, and has documented local opt-out instructions.
- [ ] Root `README.md` explains `npm run lint`, `npm run lint:fix`, CI enforcement
      and the selected hook behavior; measurement evidence is included.

## Implementation handoff

This specification records agreed behavior. It does not install ESLint, change
application code, modify the pipeline, install a hook or update command usage in
the README yet. Those changes and the timing measurements are implementation work.
