kramme-connect-workflow/skills/kramme:connect:modernize-angular/SKILL.md
Use this Skill when working in the Connect monorepo and needing to modernize legacy Angular components.
npx skillsauth add abildtoft/kramme-cc-workflow kramme:connect:modernize-angularInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When to use this skill:
FormComponent or BaseComponent@Select decorators for state managementFormNode instead of typed FormGroupChangeDetectionStrategy.OnPushContext: Connect's frontend is modernizing Angular components to use NgRx ComponentStore for state management, OnPush change detection, standalone components, and proper TypeScript typing. This provides better type safety, performance, and maintainability.
Read the guideline keyword glossary from references/guideline-keywords.md.
libs/connect/cms/qa/feature/src/lib/edit-topic/ - Edit topic component with form managementlibs/connect/cms/qa/feature/src/lib/settings-page/ - Settings page with conditional form logiclibs/connect/cms/qa/feature/src/lib/topics-page/ - Topics page with complex stateALWAYS read all component files before starting:
ALWAYS identify patterns to migrate:
extends FormComponent, extends BaseComponent)@Select decorators for stateFormNode usagesubscribe(), takeUntil())onInit() vs ngOnInit())ALWAYS identify business logic:
component-name.store.ts)initialState as a constantreadonly for immutability#privateFields for encapsulation(tuple): tuple is [void, DataType] => tuple[1] !== nullpipe() directly in effects: this.effect<Type>(pipe(...)) not this.effect<Type>((param$) => param$.pipe(...))EXAMPLE: See references/component-store.ts for a complete ComponentStore reference implementation.
ChangeDetectionStrategy.OnPushstandalone: trueproviders arrayinject() for dependency injectioninject() calls first in the class as readonly fields#privateField syntax for private memberspublic or private keywords in TypeScript@Select decoratorsDestroyRef and takeUntilDestroyed (ComponentStore handles cleanup)EXAMPLE: See references/component.ts for a complete component reference implementation.
@if, @for, @switch) instead of *ngIf, *ngFor, *ngSwitch*ngrxLet directive or ngrxPush pipe to handle Observables
ngrxPush pipe over async for one-off async bindings*ngrxLet or ngrxPush multiple times for the same Observable; instead assign it to a template variable using @letEXAMPLE: See references/template.html for native control flow and form binding examples.
afterClosed() and only proceed if confirmedEXAMPLE:
deleteItem(): void {
this.#dialog
.open(ConfirmDeleteModalComponent, {
data: { itemName: this.data$.value?.name },
})
.afterClosed()
.subscribe((confirmed) => {
if (confirmed) {
this.#componentStore.deleteItem();
}
});
}
successMessage in ApiAction definitions (not manual toasts in stores)CoSnackService only for local operations (cancel, info messages)EXAMPLE - Success Messages:
// ❌ WRONG - shows before API completes
readonly saveChanges = this.effect<void>(
pipe(
tap(() => {
this.#store.dispatch(updateAction.start(this.form.getRawValue()));
this.#snacks.success('Saved!'); // ← BAD
})
)
);
// ✅ CORRECT - shows only on actual success
export const updateAction = new ApiAction<State, Input, Output>(
'Entity',
'Update',
'Feature',
{
showErrors: true,
successMessage: 'Saved!', // ← GOOD
}
);
EXAMPLE:
<button
matSuffix
mat-icon-button
matTooltip="Copy to clipboard"
[cdkCopyToClipboard]="form.controls.id.value"
(cdkCopyToClipboardCopied)="onIdCopied($event)"
>
<fa-icon [icon]="copyIcon" />
</button>
corepack yarn nx lint <library-name>pipe() directlyany typesSee references/patterns.md for detailed examples of conditional field disabling and nonNullable form controls.
nonNullable: true to form controlsFormGroup and FormControl (not FormNode)pipe() directly: this.effect<Type>(pipe(...))this.effect<Type>((param$) => param$.pipe(...))DestroyRef and takeUntilDestroyed for ComponentStore subscriptionssuccessMessage in ApiAction definitionsCoSnackService only for local operationsany types
unknown when type is uncertain#privateField syntax for encapsulationpublic or private keywords in TypeScript class membersComponentStore.get()
See references/checklist.md for the full phase-by-phase migration checklist.
changeDetection: ChangeDetectionStrategy.OnPush in @Component decorator for new componentsinject() calls first in the class as readonly fields@Input and @Output properties second in the classclass bindings instead of ngClassstyle bindings instead of ngStyletw- prefix (enforced in libs/co/ui-tailwind-preset/tailwind.config.js)@apply directive@fortawesome/angular-fontawesome package<fa-icon> component, not <i> tags with CSS classes@fortawesome/pro-*-svg-icons (not free packages)yarn run format (from Connect/ng-app-monolith)yarn exec nx affected --targets=lint,test --skip-nx-cacheALWAYS refer to these files for complete examples:
libs/connect/cms/qa/feature/src/lib/edit-topic/cms-qa-edit-topic.store.tslibs/connect/cms/qa/feature/src/lib/settings-page/cms-qa-settings-page.store.tslibs/connect/cms/qa/feature/src/lib/topics-page/cms-qa-topics-page.store.tsAGENTS.md - Angular Development Patterns sectionSee the Instructions section.
tools
Requires Linear MCP. Implements one Linear issue end to end, selects applicable code-review, convention, and PR-refactor gates, runs them to bounded convergence, verifies, and optionally opens the PR and iterates on CI and review feedback until green. Use when the user wants a single Linear issue taken from implementation through a clean Pull Request. Not for implementation-only work, SIW-tracked issues, stacked PRs, existing PR updates, or post-merge rollout.
development
Reviews PR and local changes for convention drift and overcaution against documented rules and mined peer-file practice. Use for new patterns, dependencies, abstractions, or defensive complexity that departs from established practice; every finding cites evidence. Supports --inline. Not for general code quality (use kramme:pr:code-review) or spec review (use kramme:siw:spec-audit --team).
testing
Charts huge or foggy initiatives into a local `.context` decision map and resolves one typed frontier ticket per session until the work is ready for SIW or another execution workflow. Use when the route to a destination cannot fit in one agent session or parallel workspaces need coordinated planning state. Not for clear specs, ordinary issue decomposition, implementation, or Linear-native tracking.
development
Investigates a question against primary sources and saves one cited Markdown artifact. Use for reading legwork: official docs/API facts, source-code or spec checks, standards, and first-party service behavior before planning or implementation. Not for making product or architecture decisions, implementing code, broad web search, secondary blog summaries, or uncited answers.