@tungvivas/angular-vibe-kit 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,63 +1,12 @@
1
- Review the code changes in this PR. Check every item — flag violations clearly.
2
-
3
- Read `.claude/angular-practices/` for version-correct idioms, and
4
- `.claude/rules/project-rules.md` for project-specific rules.
5
-
6
- **Precedence (see `project-rules.md` Precedence):** a valid project convention wins over
7
- the BP profile; flag a BP deviation as a blocker only when it's an objective defect in NEW
8
- code. Do NOT flag legacy modules listed in the Coexistence Strategy they are kept as-is.
9
- Do NOT flag a valid project choice (naming, structure, state lib, response shape) just
10
- because it differs from the profile.
11
-
12
- ## Architecture
13
- - [ ] Smart / dumb separation: pages own data; presentational components only render + emit
14
- - [ ] HTTP calls ONLY in services — never in components
15
- - [ ] No business logic in templates
16
- - [ ] Feature routes are lazy-loaded
17
-
18
- ## Type Safety
19
- - [ ] No `any` — interfaces/types for every model and API response
20
- - [ ] Responses typed with the project's response shape recorded in `project-rules.md` (e.g. an `ApiResponse<T>` envelope, a raw DTO, or a GraphQL type — whatever the backend actually returns)
21
- - [ ] No `@ts-ignore` / `@ts-expect-error`
22
-
23
- ## Dependency Injection (follow `.claude/angular-practices/`)
24
- - [ ] DI matches the profile: `inject()` (v16+) or constructor injection (v12–15) — consistent across the project
25
- - [ ] Services `@Injectable({ providedIn: 'root' })`
26
-
27
- ## Reactive / RxJS / Signals (follow `.claude/angular-practices/`)
28
- - [ ] Subscriptions torn down: `takeUntilDestroyed` (v16+) or `takeUntil(destroy$)` + `ngOnDestroy` (v12–15)
29
- - [ ] `async` pipe preferred over manual subscribe
30
- - [ ] No `toPromise()` — use `firstValueFrom()` if needed
31
- - [ ] Services return `Observable<T>` — do NOT subscribe internally
32
- - [ ] Signals used per profile: stable for state (v16+); derived state via `computed()`. `resource`/`httpResource` are experimental (v19+) — only if the team opted in
33
-
34
- ## Error Handling
35
- - [ ] Loading / error / empty states handled in list/detail pages
36
- - [ ] HTTP errors surfaced to user (not swallowed)
37
- - [ ] Auth errors (e.g. 401) handled centrally by an interceptor — not per-feature
38
-
39
- ## Security
40
- - [ ] Auth handled per the project's model in `project-rules.md` (token in memory / httpOnly cookie / session / OAuth) — and consistent with it. If tokens are used, they are NOT in localStorage
41
- - [ ] No hardcoded backend URL — uses `environment`
42
- - [ ] Routes needing auth are guarded
43
- - [ ] No unsanitized HTML (`innerHTML` / `bypassSecurityTrust*`) without a clear, reviewed reason
44
-
45
- ## Performance
46
- - [ ] `ChangeDetectionStrategy.OnPush` on every component (or zoneless on v20+ if enabled)
47
- - [ ] List tracking present: `@for` with `track` (v17+) or `*ngFor` with `trackBy` (v12–16)
48
-
49
- ## Code Quality
50
- - [ ] Component file < ~300 lines; method < ~50 lines
51
- - [ ] No dead code, no `console.log`
52
- - [ ] Naming follows `.claude/rules/project-rules.md`
53
-
54
- ## Documentation
55
- - [ ] New feature: `CONTEXT.md` created inside feature folder
56
- - [ ] Logic changed: `CONTEXT.md` Refactor Log updated (append only)
57
- - [ ] Endpoint changed: `docs/API_CONTRACT.md` updated
58
- - [ ] `docs/PROJECT-STATUS.md` updated
59
-
60
- ## Summary
61
- 1. **Blockers** 🔴 — must fix before merge
62
- 2. **Suggestions** 🟡 — improve but not blocking
63
- 3. **Good parts** 🟢 — what was done well
1
+ Review the current code changes against this project's Angular standards.
2
+
3
+ 1. Get the diff: run `git diff` (unstaged) and `git diff --staged`, or `git diff <base>...HEAD` if a
4
+ base branch is named. Review only the changed code.
5
+ 2. Apply the full checklist in `.claude/references/review-checklist.md` — it defines the review
6
+ dimensions, the Precedence rule (a valid project convention wins; don't flag legacy), and the
7
+ 🔴/🟡/🟢 output format. That file is the single source of truth for what "correct" means here.
8
+ 3. Output the report **inline** in this conversation using the format from the checklist. If there are
9
+ no blockers, say so explicitly.
10
+
11
+ > For a large diff, or to review in the background while you keep coding, dispatch the
12
+ > `angular-reviewer` agent instead — it applies the same checklist in an isolated context.
@@ -45,6 +45,12 @@ Note what is local component state vs shared state.
45
45
  - **{Decision}**: {reason}
46
46
  - **{Decision}**: {reason}
47
47
 
48
+ ## Component Wrapping Decisions
49
+ - **Wrapped components used**: list the `<app-*>` components used by this feature (e.g. `<app-select>`, `<app-data-table>`)
50
+ - **Library components used directly**: list any direct library imports and the reason (e.g. `p-tree` used directly because no wrapper exists yet, and creating one is out of scope for this feature)
51
+ - **New wrappers introduced**: if this feature adds a new wrapper to `shared/components/`, list it here and link to the PR/ADR
52
+ - **Wrappers NOT used (with reason)**: if a wrapper exists for the need but you chose not to use it, document why (e.g. "wrapper doesn't support X yet — track in #123")
53
+
48
54
  ## Considered and Rejected
49
55
  - **{Option}**: rejected because {reason}
50
56
 
@@ -1,110 +1,12 @@
1
- Write tests for the specified feature module. Read the source code first, then generate tests.
1
+ Write tests for the specified feature module.
2
2
 
3
- Use the test runner the project already uses (Jest or Karma/Jasmine check
4
- `package.json` / `angular.json`). Read `.claude/angular-practices/` for the
5
- version's testing idioms.
3
+ Follow `.claude/references/test-spec.md` it is the single source of truth for how this project writes
4
+ tests: read-first, service unit tests (TestBed + `HttpTestingController`), component tests, E2E for
5
+ critical flows only, and the verify step (coverage ≥ 80%, no real backend). It detects the project's
6
+ runner (Jest or Karma/Jasmine) and version idioms from `.claude/angular-practices/`.
6
7
 
7
- ## Step 1: Read Before Writing
8
- - Read the feature's source: model, service, page components, presentational components
9
- - Read the module's `CONTEXT.md` (if it exists) to understand trade-offs and edge cases
10
- - Read `docs/API_CONTRACT.md` for expected request/response shapes
11
- - Identify all code paths: happy path, error cases, empty states, validation
8
+ Write the tests **inline** in this conversation, then run them and report the result (files created,
9
+ what each covers, pass/fail + coverage).
12
10
 
13
- ## Step 2: Unit Tests `{feature}.service.spec.ts`
14
-
15
- Use `HttpClientTestingModule` + `HttpTestingController` (works on every version, v12+).
16
- On v15+ you may instead use the functional `provideHttpClient()` + `provideHttpClientTesting()`.
17
- Follow whichever style the project already uses (see `.claude/angular-practices/`).
18
-
19
- ```typescript
20
- describe('{Feature}Service', () => {
21
- let service: {Feature}Service;
22
- let httpMock: HttpTestingController;
23
-
24
- beforeEach(() => {
25
- TestBed.configureTestingModule({
26
- imports: [HttpClientTestingModule],
27
- providers: [{Feature}Service],
28
- });
29
- service = TestBed.inject({Feature}Service);
30
- httpMock = TestBed.inject(HttpTestingController);
31
- });
32
-
33
- afterEach(() => httpMock.verify());
34
- });
35
- ```
36
-
37
- ### Required Coverage Per Method
38
- **getAll:**
39
- - ✅ Success — returns list; assert request URL + method `GET`
40
- - ✅ Empty — returns empty array, not null
41
- - ✅ Server error — propagates error (500)
42
-
43
- **getById:**
44
- - ✅ Found — returns correct response; assert URL contains the id
45
- - ✅ Not found — 404 error propagated
46
-
47
- **create:**
48
- - ✅ Success — assert `POST` + request body matches payload
49
- - ✅ Validation error — 400
50
- - ✅ Conflict — 409
51
-
52
- **update:**
53
- - ✅ Success — assert `PUT`/`PATCH` + body
54
- - ✅ Not found — 404
55
-
56
- **delete:**
57
- - ✅ Success — assert `DELETE` + URL
58
- - ✅ Not found — 404
59
-
60
- ### Unit Test Rules
61
- - Use `httpMock.expectOne(url)` to assert and flush each request
62
- - Test ONE behavior per test
63
- - Naming: `methodName_scenario_expectedResult`
64
- - Describe behavior in the test title, not the implementation
65
- - `httpMock.verify()` in `afterEach` — no unexpected requests
66
- - Never hit a real backend
67
-
68
- ## Step 3: Component Tests — `{feature}-list.component.spec.ts`
69
-
70
- Mock the service with `jasmine.createSpyObj` (Karma) or `jest.fn()` (Jest).
71
-
72
- ```typescript
73
- describe('{Feature}ListComponent', () => {
74
- let fixture: ComponentFixture<{Feature}ListComponent>;
75
- let serviceSpy: jasmine.SpyObj<{Feature}Service>;
76
-
77
- beforeEach(() => {
78
- serviceSpy = jasmine.createSpyObj('{Feature}Service', ['getAll', 'delete']);
79
- TestBed.configureTestingModule({
80
- imports: [{Feature}ListComponent],
81
- providers: [{ provide: {Feature}Service, useValue: serviceSpy }],
82
- });
83
- });
84
- });
85
- ```
86
-
87
- ### Required Coverage
88
- - ✅ Render — list shows correct data after load
89
- - ✅ Loading — spinner visible while the request is pending
90
- - ✅ Error — error message visible when the service errors
91
- - ✅ Empty — empty-state message when no data
92
- - ✅ Interaction — clicking delete calls `service.delete` with the right id
93
- - ✅ Signals (v16+) — assert signal values update as expected
94
-
95
- ### Component Test Rules
96
- - Mock the service — never the real HttpClient
97
- - Drive change detection with `fixture.detectChanges()`
98
- - Query the DOM via `fixture.nativeElement` / `DebugElement`
99
- - Each test is independent — no shared mutable state
100
-
101
- ## Step 4: E2E (only for critical flows)
102
- For login and the main CRUD flow, add a Playwright spec under the project's e2e folder.
103
- Skip E2E for trivial pages — manual testing covers those.
104
-
105
- ## Step 5: Verify
106
- - All tests pass: `ng test` / `jest`
107
- - No test depends on execution order
108
- - No unit test hits a real backend
109
- - Test names clearly describe WHAT is tested and the EXPECTED result
110
- - Coverage: every public service method has at least happy path + error case
11
+ > For a large feature, or to write tests in the background while you keep coding, dispatch the
12
+ > `angular-test-writer` agent instead — it follows the same spec in an isolated context.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tungvivas/angular-vibe-kit",
3
- "version": "0.1.0",
4
- "description": "Bootstrap a Vibe Coding workflow (CLAUDE.md, project docs, slash-commands) into any Angular project. Detects your Angular version and installs version-matched best-practice rules.",
3
+ "version": "0.3.0",
4
+ "description": "Bootstrap a Vibe Coding workflow (CLAUDE.md, project docs, slash-commands, skills, agents) into any Angular project. Detects your Angular version and installs version-matched best-practice rules.",
5
5
  "keywords": [
6
6
  "angular",
7
7
  "claude",
@@ -9,7 +9,10 @@
9
9
  "ai",
10
10
  "scaffold",
11
11
  "vibe-coding",
12
- "slash-commands"
12
+ "slash-commands",
13
+ "skills",
14
+ "agents",
15
+ "subagents"
13
16
  ],
14
17
  "license": "MIT",
15
18
  "type": "module",
@@ -17,9 +20,12 @@
17
20
  "angular-vibe-kit": "bin/cli.js"
18
21
  },
19
22
  "files": [
23
+ "agents/",
20
24
  "bin/",
21
25
  "commands/",
22
26
  "practices/",
27
+ "references/",
28
+ "skills/",
23
29
  "templates/",
24
30
  "README.md",
25
31
  "LICENSE"
@@ -0,0 +1,44 @@
1
+ # Feature Structure & Coding Rules (shared source of truth)
2
+
3
+ > Read by BOTH `/new-feature` (linear command) and `/dev-cycle` (gated orchestrator) when scaffolding
4
+ > and implementing a new feature module. Keep the folder shape, build order, and coding rules HERE
5
+ > only — the two commands differ in pacing (linear vs gated), not in what "correct" looks like.
6
+
7
+ ## Folder structure
8
+ > **Use the project's actual layout and folder names from `.claude/rules/project-rules.md`.**
9
+ > The tree below is only the DEFAULT shape — if the project calls things differently
10
+ > (e.g. `containers/` instead of `pages/`, `ui/` or `common/` instead of `shared/`,
11
+ > an Nx `libs/` layout, or NgModule-based folders), follow the project, not this tree.
12
+
13
+ ```
14
+ {features-dir}/{feature-name}/ # e.g. features/, modules/, or an Nx lib
15
+ ├── {feature}.routes.ts
16
+ ├── models/
17
+ │ └── {feature}.model.ts # Interfaces mirroring the backend response shape
18
+ ├── services/
19
+ │ └── {feature}.service.ts # All data-access calls
20
+ ├── pages/ # Smart (container) components — project may call these containers/
21
+ │ ├── {feature}-list/
22
+ │ │ ├── {feature}-list.component.ts
23
+ │ │ ├── {feature}-list.component.html
24
+ │ │ └── {feature}-list.component.scss
25
+ │ └── {feature}-detail/
26
+ └── components/ # Dumb (presentational) components
27
+ └── {feature}-form/
28
+ ```
29
+
30
+ ## Implementation order
31
+ 1. **Model** — interfaces for entity, request/response, mirroring the backend's actual DTOs / response shape (per `project-rules.md` — envelope, raw DTO, or GraphQL type)
32
+ 2. **Service** — data-access methods returning `Observable<T>` typed with the project's response shape (HttpClient, or the project's client if it uses Apollo/another)
33
+ 3. **Routes** — lazy-loaded, guard-protected where needed
34
+ 4. **Page components (smart)** — data, loading/error/empty states
35
+ 5. **Presentational components (dumb)** — inputs/outputs only, no data access
36
+
37
+ ## Coding rules (from `.claude/rules/project-rules.md` + `.claude/angular-practices/`)
38
+ - Data access ONLY in services — never in components
39
+ - `ChangeDetectionStrategy.OnPush` on every component
40
+ - Tear down subscriptions per profile: `takeUntilDestroyed` (v16+) or `takeUntil(destroy$)` + `ngOnDestroy` (v12–15)
41
+ - No `any` — interfaces/types for every model and response
42
+ - Use the project's forms approach from `project-rules.md` (Reactive Forms by default; Formly / template-driven if that's what the project uses)
43
+ - No hardcoded backend URL — use `environment`
44
+ - **Wrapper priority**: import from `@shared/components/<name>` (or the project's wrapper folder) if a wrapper exists; never import the library component directly. See `docs/DESIGN_SYSTEM.md` → Wrapped Components.
@@ -0,0 +1,112 @@
1
+ # Angular Plan Spec (shared source of truth)
2
+
3
+ > Read by `/plan` (writes the plan) and by `/dev-cycle` + `/new-feature` (consume the plan).
4
+ > Keep the plan format HERE only — the commands are thin wrappers around this file.
5
+ > Adapted from [obra/superpowers](https://github.com/obra/superpowers) `writing-plans` (MIT).
6
+
7
+ A plan is written for an engineer with **zero context for this codebase**: every task names exact
8
+ files, exact types, and exact signatures. If a step changes code, the step shows the code.
9
+
10
+ ## Where plans live
11
+
12
+ `docs/plans/YYYY-MM-DD-<feature-name>.md` — one plan per feature. Create `docs/plans/` if it
13
+ doesn't exist yet.
14
+
15
+ ## Plan document header (required)
16
+
17
+ ```markdown
18
+ # <Feature Name> — Implementation Plan
19
+
20
+ **Goal:** <one sentence: what this builds and for whom>
21
+
22
+ **Architecture:** <2-3 sentences: approach, where it sits in the app, key data flow>
23
+
24
+ **Approach chosen:** <the approach the user approved in /plan Phase C, one line, with the
25
+ main alternative that was rejected and why>
26
+
27
+ ## Global Constraints
28
+
29
+ Do NOT restate project rules here — point at the sources every task implicitly obeys:
30
+
31
+ - Precedence + naming + Coexistence: `.claude/rules/project-rules.md`
32
+ - Version idioms (DI, control flow, Signals/RxJS): `.claude/angular-practices/<version>.md`
33
+ - Folder shape, implementation order, coding rules: `.claude/references/feature-structure.md`
34
+ - Wrapper priority: `docs/DESIGN_SYSTEM.md` → Wrapped Components table
35
+ - Endpoints + payload shapes: `docs/API_CONTRACT.md`
36
+
37
+ <Then list ONLY feature-specific constraints the user stated, one line each, verbatim —
38
+ e.g. "must work offline", "max 1 request per keystroke", "reuse OrderService pagination".>
39
+ ```
40
+
41
+ ## File map (required, before any task)
42
+
43
+ Lock decomposition in before writing tasks. Use the **project's actual layout** from
44
+ `project-rules.md` (e.g. `containers/` not `pages/`, Nx `libs/`) — never the default tree blindly.
45
+
46
+ ```markdown
47
+ ## File Map
48
+
49
+ | Action | Path | Responsibility |
50
+ |--------|------|----------------|
51
+ | Create | src/app/features/<feature>/models/<feature>.model.ts | DTOs mirroring API_CONTRACT |
52
+ | Create | src/app/features/<feature>/services/<feature>.service.ts | Data access only |
53
+ | Modify | src/app/app.routes.ts | Register lazy route |
54
+ | Test | src/app/features/<feature>/services/<feature>.service.spec.ts | Per test-spec.md |
55
+ ```
56
+
57
+ One clear responsibility per file. Files that change together live together.
58
+
59
+ ## Task structure
60
+
61
+ Order tasks by the Implementation Order in `feature-structure.md`:
62
+ **Model → Service → Routes → Page components → Presentational components → Tests**
63
+ (tests follow `.claude/references/test-spec.md`; this kit does not use red/green TDD ordering).
64
+
65
+ Each task uses this shape:
66
+
67
+ ````markdown
68
+ ### Task N: <name>
69
+
70
+ **Files:**
71
+ - Create: `exact/path/file.ts`
72
+ - Modify: `exact/path/existing.ts` (what changes)
73
+ - Test: `exact/path/file.spec.ts`
74
+
75
+ **Interfaces:**
76
+ - Consumes: <what this task uses from earlier tasks — exact type names and signatures>
77
+ - Produces: <what later tasks rely on — exact function names, parameter and return types.
78
+ A task's implementer may see only their own task; this block is how they learn the
79
+ names and types neighboring tasks use.>
80
+
81
+ **Steps:**
82
+ - [ ] Step 1: <one action, 2-10 minutes, with the actual code block if it changes code>
83
+ - [ ] Step 2: <verify — exact command and expected output, e.g. `npx tsc --noEmit` → clean>
84
+ ````
85
+
86
+ Task sizing: the smallest unit that is independently verifiable (compiles / tests pass on its
87
+ own). Fold setup, config, and docs steps into the task whose deliverable needs them.
88
+
89
+ ## No placeholders (plan failures — never write these)
90
+
91
+ - "TBD", "TODO", "implement later", "fill in details"
92
+ - "Add appropriate error handling" / "add validation" / "handle edge cases" (show the handling)
93
+ - "Write tests for the above" without naming the cases (list them per test-spec.md coverage)
94
+ - "Similar to Task N" — repeat the code; tasks may be read out of order
95
+ - A step that describes what to do without showing how (code steps require code blocks)
96
+ - References to types, functions, or methods not defined in any task and not existing in the codebase
97
+
98
+ ## Self-review (run after writing, fix inline — no re-review needed)
99
+
100
+ 1. **Requirement coverage** — for each requirement the user confirmed in `/plan`, point to the
101
+ task that implements it. A requirement with no task = add the task.
102
+ 2. **Placeholder scan** — search the plan for every pattern in the list above.
103
+ 3. **Type consistency** — types, signatures, and property names used in later tasks match what
104
+ earlier tasks define, AND match the shapes in `docs/API_CONTRACT.md`.
105
+ 4. **Wrapper check** — every UI element in the plan uses the wrapper from the Wrapped
106
+ Components table when one exists (a raw library import where a wrapper exists is a plan bug).
107
+ 5. **Layout check** — every path in the File Map matches the project's real folder layout from
108
+ `project-rules.md`.
109
+
110
+ ## Output
111
+
112
+ Report the plan file path, the number of tasks, and the self-review result (what was fixed).
@@ -0,0 +1,88 @@
1
+ # Angular Review Checklist (shared source of truth)
2
+
3
+ > Read by BOTH `/review-pr` (command, runs inline) and the `angular-reviewer` agent (isolated context).
4
+ > Keep review logic HERE only — the command and the agent are thin wrappers around this file.
5
+
6
+ ## Load the project's standards first
7
+ - `.claude/angular-practices/*.md` — the version-matched idioms (DI, control flow, RxJS/Signals, tests).
8
+ - `.claude/rules/project-rules.md` — naming, folder layout, Precedence, Coexistence.
9
+ - `docs/DESIGN_SYSTEM.md` → Wrapped Components — the project's shared UI wrappers.
10
+
11
+ ## Precedence (do not over-flag)
12
+ A valid project convention WINS over the best-practice profile. Flag a profile deviation as a blocker
13
+ only when it's an **objective defect in NEW code**. Do NOT flag legacy modules listed in the Coexistence
14
+ Strategy — they are kept as-is. Do NOT flag a valid project choice (naming, structure, state library,
15
+ response shape) just because it differs from the profile. When unsure if something is a defect or a
16
+ valid choice, say so rather than blocking.
17
+
18
+ ## Review dimensions
19
+
20
+ ### 1. Architecture
21
+ - [ ] Smart / dumb separation: pages own data; presentational components only render + emit
22
+ - [ ] HTTP calls ONLY in services — never in components
23
+ - [ ] No business logic in templates
24
+ - [ ] Feature routes are lazy-loaded
25
+
26
+ ### 2. Type Safety
27
+ - [ ] No `any` — interfaces/types for every model and API response
28
+ - [ ] Responses typed with the project's response shape recorded in `project-rules.md` (envelope, raw DTO, GraphQL type — whatever the backend returns)
29
+ - [ ] No `@ts-ignore` / `@ts-expect-error`
30
+
31
+ ### 3. Dependency Injection (per `.claude/angular-practices/`)
32
+ - [ ] DI matches the profile: `inject()` (v16+) or constructor injection (v12–15) — consistent across the project
33
+ - [ ] Services `@Injectable({ providedIn: 'root' })` unless intentionally scoped
34
+
35
+ ### 4. Reactive / RxJS / Signals (per `.claude/angular-practices/`)
36
+ - [ ] Subscriptions torn down: `takeUntilDestroyed` (v16+) or `takeUntil(destroy$)` + `ngOnDestroy` (v12–15)
37
+ - [ ] `async` pipe preferred over manual subscribe
38
+ - [ ] No `toPromise()` — use `firstValueFrom()` if needed
39
+ - [ ] Services return `Observable<T>` — do NOT subscribe internally
40
+ - [ ] Signals used per profile: stable for state (v16+); derived state via `computed()`. `resource`/`httpResource` are experimental (v19+) — only if the team opted in
41
+
42
+ ### 5. Error Handling
43
+ - [ ] Loading / error / empty states handled in list & detail pages
44
+ - [ ] HTTP errors surfaced to the user (not swallowed)
45
+ - [ ] Auth errors (e.g. 401) handled centrally by an interceptor — not per-feature
46
+
47
+ ### 6. Security
48
+ - [ ] Auth handled per the project's model in `project-rules.md` (token in memory / httpOnly cookie / session / OAuth) and consistent with it. If tokens are used, they are NOT in localStorage
49
+ - [ ] No hardcoded backend URL — uses `environment`
50
+ - [ ] Routes needing auth are guarded
51
+ - [ ] No unsanitized HTML (`innerHTML` / `bypassSecurityTrust*`) without a clear, reviewed reason
52
+
53
+ ### 7. Performance
54
+ - [ ] `ChangeDetectionStrategy.OnPush` on every component (or zoneless on v20+ if enabled)
55
+ - [ ] List tracking present: `@for` with `track` (v17+) or `*ngFor` with `trackBy` (v12–16)
56
+
57
+ ### 8. Code Quality
58
+ - [ ] Component file < ~300 lines; method < ~50 lines
59
+ - [ ] No dead code, no `console.log`
60
+ - [ ] Naming follows `.claude/rules/project-rules.md`
61
+
62
+ ### 9. Component Wrapping (per `docs/DESIGN_SYSTEM.md` → Wrapped Components)
63
+ - [ ] No feature imports a raw UI-library component (`p-dropdown`, `mat-form-field`, `nz-input`, etc.) when a wrapper exists in `shared/components/`
64
+ - [ ] UI-primitive imports go through the project's wrapper (import path matches the wrapper's location)
65
+ - [ ] Wrapper exists but the PR uses the library directly → 🔴 BLOCKER
66
+ - [ ] No wrapper exists and the library is used directly → 🟡 SUGGESTION: "Consider a wrapper in `shared/components/`"
67
+ - [ ] New components do NOT silently re-implement logic an existing wrapper already provides
68
+ - [ ] A brand-new wrapper follows the Wrapper Reference Example from `project-rules.md`
69
+
70
+ ### 10. Documentation
71
+ - [ ] New feature: `CONTEXT.md` created inside the feature folder
72
+ - [ ] Logic changed: `CONTEXT.md` Refactor Log updated (append only)
73
+ - [ ] Endpoint changed: `docs/API_CONTRACT.md` updated
74
+ - [ ] `docs/PROJECT-STATUS.md` updated
75
+
76
+ ## Output format
77
+ ```
78
+ 🔴 Blockers — must fix before merge
79
+ - <file:line> — <issue> → <fix>
80
+ 🟡 Suggestions — improve but not blocking
81
+ - <file:line> — <issue>
82
+ 💭 Nits — optional polish (naming, minor style not handled by the linter)
83
+ - <file:line> — <note>
84
+ 🟢 Good — clean patterns / clever solutions worth calling out
85
+ - <note>
86
+ ```
87
+ If there are no blockers, say so explicitly. Cite `file:line`. Explain the "why" behind each finding
88
+ and suggest rather than demand.
@@ -0,0 +1,92 @@
1
+ # Angular Test Spec (shared source of truth)
2
+
3
+ > Read by BOTH `/write-tests` (command, runs inline) and the `angular-test-writer` agent (isolated).
4
+ > Keep test logic HERE only — the command and the agent are thin wrappers around this file.
5
+
6
+ ## Load the project's standards first
7
+ - `.claude/angular-practices/*.md` → the **Testing** section (version's `TestBed` idioms).
8
+ - `.claude/rules/project-rules.md` + an existing spec (the Reference Example) — mirror its style.
9
+ - Detect the runner from `package.json` / `angular.json` / `jest.config` / `karma.conf`
10
+ (Jest or Karma/Jasmine). Use what the project already uses — never introduce a new runner.
11
+
12
+ ## Step 1: Read before writing
13
+ - Read the feature's source: model, service, page components, presentational components, guards, pipes, resolvers.
14
+ - Read the feature's `CONTEXT.md` (if present) for trade-offs and edge cases.
15
+ - Read `docs/API_CONTRACT.md` for expected request/response shapes.
16
+ - Identify every code path: happy path, not-found, validation failure, loading/error/empty states, branches.
17
+
18
+ ## Step 2: Service unit tests — `{feature}.service.spec.ts`
19
+ Use `HttpClientTestingModule` + `HttpTestingController` (works v12+). On v15+ you may use the functional
20
+ `provideHttpClient()` + `provideHttpClientTesting()` — follow whichever style the project already uses.
21
+
22
+ ```typescript
23
+ describe('{Feature}Service', () => {
24
+ let service: {Feature}Service;
25
+ let httpMock: HttpTestingController;
26
+
27
+ beforeEach(() => {
28
+ TestBed.configureTestingModule({
29
+ imports: [HttpClientTestingModule],
30
+ providers: [{Feature}Service],
31
+ });
32
+ service = TestBed.inject({Feature}Service);
33
+ httpMock = TestBed.inject(HttpTestingController);
34
+ });
35
+
36
+ afterEach(() => httpMock.verify());
37
+ });
38
+ ```
39
+
40
+ ### Required coverage per method
41
+ - **getAll**: success (returns list; assert URL + `GET`) · empty (empty array, not null) · server error (500 propagates)
42
+ - **getById**: found (assert URL contains id) · not found (404 propagates)
43
+ - **create**: success (assert `POST` + body matches payload) · validation error (400) · conflict (409)
44
+ - **update**: success (assert `PUT`/`PATCH` + body) · not found (404)
45
+ - **delete**: success (assert `DELETE` + URL) · not found (404)
46
+
47
+ ### Service test rules
48
+ - Use `httpMock.expectOne(url)` to assert and flush each request.
49
+ - One behavior per test. Naming: `methodName_scenario_expectedResult`.
50
+ - `httpMock.verify()` in `afterEach` — no unexpected requests. Never hit a real backend.
51
+
52
+ ## Step 3: Component tests — `{feature}-list.component.spec.ts`
53
+ Mock the service with `jasmine.createSpyObj` (Karma) or `jest.fn()` (Jest).
54
+
55
+ ```typescript
56
+ describe('{Feature}ListComponent', () => {
57
+ let fixture: ComponentFixture<{Feature}ListComponent>;
58
+ let serviceSpy: jasmine.SpyObj<{Feature}Service>;
59
+
60
+ beforeEach(() => {
61
+ serviceSpy = jasmine.createSpyObj('{Feature}Service', ['getAll', 'delete']);
62
+ TestBed.configureTestingModule({
63
+ imports: [{Feature}ListComponent],
64
+ providers: [{ provide: {Feature}Service, useValue: serviceSpy }],
65
+ });
66
+ });
67
+ });
68
+ ```
69
+
70
+ ### Required coverage
71
+ - Render (list shows correct data after load) · Loading (spinner while pending) · Error (message on service error)
72
+ · Empty (empty-state message) · Interaction (clicking delete calls `service.delete` with the right id)
73
+ · Signals (v16+): assert signal values update as expected.
74
+
75
+ ### Component test rules
76
+ - Mock the service — never the real HttpClient.
77
+ - Drive change detection with `fixture.detectChanges()`; query DOM via `fixture.nativeElement` / `DebugElement`.
78
+ - Each test independent — no shared mutable state.
79
+
80
+ ## Step 4: E2E (only for critical flows)
81
+ For login and the main CRUD flow, add a spec under the project's e2e folder using its configured E2E
82
+ tool (e.g. Playwright). Skip E2E for trivial pages — manual testing covers those.
83
+
84
+ ## Step 5: Verify before reporting
85
+ - All new tests pass (`ng test --watch=false` / `npm test` / `jest`, or target the new spec).
86
+ - No test depends on execution order; no unit/component test hits a real backend.
87
+ - Test names describe behavior and the expected result.
88
+ - Coverage ≥ 80% for the feature (`ng test --code-coverage` / `jest --coverage` if configured);
89
+ every public service method has at least happy-path + error case.
90
+
91
+ ## Output
92
+ List the spec files created, what each covers, and the final test-run result (pass/fail + coverage).
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: angular-practices
3
+ description: Use when writing, reviewing, or refactoring any Angular / TypeScript code in this project — components, dependency injection, templates, services, HTTP, routing, RxJS/Signals, forms, and testing. Provides the version-matched Angular {{NG_PROFILE_LABEL}} idioms for this codebase.
4
+ ---
5
+
6
+ # Angular Practices (this project)
7
+
8
+ When you write or review Angular code in this project, follow the version-matched
9
+ best-practice profile that the installer selected for this codebase.
10
+
11
+ **→ Read `.claude/angular-practices/{{PRACTICE_FILE}}` and apply it.**
12
+
13
+ That file is the source of truth for HOW to write idiomatic Angular {{NG_PROFILE_LABEL}}:
14
+ component style (standalone vs NgModule), DI (`inject()` vs constructor), template syntax
15
+ (`@if/@for` vs `*ngIf/*ngFor`), thin components with a smart/dumb split, HTTP in services
16
+ (not components), typed reactive forms, RxJS teardown (`takeUntilDestroyed`) or Signals for
17
+ local state, `OnPush` change detection, and `TestBed` slice tests.
18
+
19
+ ## Precedence — which rule wins (read this first)
20
+
21
+ The profile is **not** absolute. Follow this order (see `.claude/rules/project-rules.md` → Precedence):
22
+
23
+ 1. **This project's conventions** (the codebase + `.claude/rules/project-rules.md`) — HIGHEST.
24
+ If the project does something consistently and it works, match it — even if it differs
25
+ from the profile (folder layout, naming, state-management library, API/response shape, auth).
26
+ 2. **This profile** — applies only where the project has NO convention, or where existing
27
+ code is objectively below standard. In that case the standard applies to **NEW code only**.
28
+ 3. **Legacy modules** (Coexistence Strategy in project-rules.md) — never refactored.
29
+
30
+ ## Before importing a raw UI-library component
31
+
32
+ Check whether a shared wrapper already exists for the need — see the
33
+ **component-wrapper-priority** skill and `docs/DESIGN_SYSTEM.md` → Wrapped Components table.
34
+ Never bypass an existing wrapper with a raw library import.