$npx -y skills add Jeffallan/claude-skills --skill angular-architectGenerates Angular 17+ standalone components, configures advanced routing with lazy loading and guards, implements NgRx state management, applies RxJS patterns, and optimizes bundle performance. Use when building Angular 17+ applications with standalone components or signals, sett
| 1 | # Angular Architect |
| 2 | |
| 3 | Senior Angular architect specializing in Angular 17+ with standalone components, signals, and enterprise-grade application development. |
| 4 | |
| 5 | ## Core Workflow |
| 6 | |
| 7 | 1. **Analyze requirements** - Identify components, state needs, routing architecture |
| 8 | 2. **Design architecture** - Plan standalone components, signal usage, state flow |
| 9 | 3. **Implement features** - Build components with OnPush strategy and reactive patterns |
| 10 | 4. **Manage state** - Setup NgRx store, effects, selectors as needed; verify store hydration and action flow with Redux DevTools before proceeding |
| 11 | 5. **Optimize** - Apply performance best practices and bundle optimization; run `ng build --configuration production` to verify bundle size and flag regressions |
| 12 | 6. **Test** - Write unit and integration tests with TestBed; verify >85% coverage threshold is met |
| 13 | |
| 14 | ## Reference Guide |
| 15 | |
| 16 | Load detailed guidance based on context: |
| 17 | |
| 18 | | Topic | Reference | Load When | |
| 19 | |-------|-----------|-----------| |
| 20 | | Components | `references/components.md` | Standalone components, signals, input/output | |
| 21 | | RxJS | `references/rxjs.md` | Observables, operators, subjects, error handling | |
| 22 | | NgRx | `references/ngrx.md` | Store, effects, selectors, entity adapter | |
| 23 | | Routing | `references/routing.md` | Router config, guards, lazy loading, resolvers | |
| 24 | | Testing | `references/testing.md` | TestBed, component tests, service tests | |
| 25 | |
| 26 | ## Key Patterns |
| 27 | |
| 28 | ### Standalone Component with OnPush and Signals |
| 29 | |
| 30 | ```typescript |
| 31 | import { ChangeDetectionStrategy, Component, computed, input, output, signal } from '@angular/core'; |
| 32 | import { CommonModule } from '@angular/common'; |
| 33 | |
| 34 | @Component({ |
| 35 | selector: 'app-user-card', |
| 36 | standalone: true, |
| 37 | imports: [CommonModule], |
| 38 | changeDetection: ChangeDetectionStrategy.OnPush, |
| 39 | template: ` |
| 40 | <div class="user-card"> |
| 41 | <h2>{{ fullName() }}</h2> |
| 42 | <button (click)="onSelect()">Select</button> |
| 43 | </div> |
| 44 | `, |
| 45 | }) |
| 46 | export class UserCardComponent { |
| 47 | firstName = input.required<string>(); |
| 48 | lastName = input.required<string>(); |
| 49 | selected = output<string>(); |
| 50 | |
| 51 | fullName = computed(() => `${this.firstName()} ${this.lastName()}`); |
| 52 | |
| 53 | onSelect(): void { |
| 54 | this.selected.emit(this.fullName()); |
| 55 | } |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | ### RxJS Subscription Management with `takeUntilDestroyed` |
| 60 | |
| 61 | ```typescript |
| 62 | import { Component, OnInit, inject } from '@angular/core'; |
| 63 | import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
| 64 | import { UserService } from './user.service'; |
| 65 | |
| 66 | @Component({ selector: 'app-users', standalone: true, template: `...` }) |
| 67 | export class UsersComponent implements OnInit { |
| 68 | private userService = inject(UserService); |
| 69 | // DestroyRef is captured at construction time for use in ngOnInit |
| 70 | private destroyRef = inject(DestroyRef); |
| 71 | |
| 72 | ngOnInit(): void { |
| 73 | this.userService.getUsers() |
| 74 | .pipe(takeUntilDestroyed(this.destroyRef)) |
| 75 | .subscribe({ |
| 76 | next: (users) => { /* handle */ }, |
| 77 | error: (err) => console.error('Failed to load users', err), |
| 78 | }); |
| 79 | } |
| 80 | } |
| 81 | ``` |
| 82 | |
| 83 | ### NgRx Action / Reducer / Selector |
| 84 | |
| 85 | ```typescript |
| 86 | // actions |
| 87 | export const loadUsers = createAction('[Users] Load Users'); |
| 88 | export const loadUsersSuccess = createAction('[Users] Load Users Success', props<{ users: User[] }>()); |
| 89 | export const loadUsersFailure = createAction('[Users] Load Users Failure', props<{ error: string }>()); |
| 90 | |
| 91 | // reducer |
| 92 | export interface UsersState { users: User[]; loading: boolean; error: string | null; } |
| 93 | const initialState: UsersState = { users: [], loading: false, error: null }; |
| 94 | |
| 95 | export const usersReducer = createReducer( |
| 96 | initialState, |
| 97 | on(loadUsers, (state) => ({ ...state, loading: true, error: null })), |
| 98 | on(loadUsersSuccess, (state, { users }) => ({ ...state, users, loading: false })), |
| 99 | on(loadUsersFailure, (state, { error }) => ({ ...state, error, loading: false })), |
| 100 | ); |
| 101 | |
| 102 | // selectors |
| 103 | export const selectUsersState = createFeatureSelector<UsersState>('users'); |
| 104 | export const selectAllUsers = createSelector(selectUsersState, (s) => s.users); |
| 105 | export const selectUsersLoading = createSelector(selectUsersState, (s) => s.loading); |
| 106 | ``` |
| 107 | |
| 108 | ## Constraints |
| 109 | |
| 110 | ### MUST DO |
| 111 | - Use standalone components (Angular 17+ default) |
| 112 | - Use signals for reactive state where appropriate |
| 113 | - Use OnPush change detection strategy |