`.
+- `formControlName`: Binds a named control within a group to an input.
+- `formGroupName`: Binds a nested `FormGroup`.
+- `formArrayName`: Binds a nested `FormArray`.
+- `[formControl]`: Binds a standalone `FormControl`.
+
+```html
+
+```
+
+## Accessing Controls
+
+Use getters for easy access to controls, especially for `FormArray`.
+
+```ts
+get aliases() {
+ return this.profileForm.get('aliases') as FormArray;
+}
+
+addAlias() {
+ this.aliases.push(this.fb.control(''));
+}
+```
+
+## Updating Values
+
+- `patchValue()`: Updates only the specified properties. Fails silently on structural mismatches.
+- `setValue()`: Replaces the entire model. Strictly enforces the form structure.
+
+```ts
+updateProfile() {
+ this.profileForm.patchValue({
+ firstName: 'Nancy',
+ address: { street: '123 Drew Street' }
+ });
+}
+```
+
+## Unified Change Events
+
+Modern Angular (v18+) provides a single `events` observable on all controls to track value, status, pristine, touched, reset, and submit events.
+
+```ts
+import {ValueChangeEvent, StatusChangeEvent} from '@angular/forms';
+
+this.profileForm.events.subscribe((event) => {
+ if (event instanceof ValueChangeEvent) {
+ console.log('New value:', event.value);
+ }
+});
+```
+
+## Manual State Management
+
+- `markAsTouched()` / `markAllAsTouched()`: Useful for showing validation errors on submit.
+- `markAsDirty()` / `markAsPristine()`: Tracks if the value has been modified.
+- `updateValueAndValidity()`: Manually triggers recalculation of value and status.
+- Options `{ emitEvent: false }` or `{ onlySelf: true }` can be passed to most methods to control propagation.
diff --git a/.agents/skills/angular-developer/references/rendering-strategies.md b/.agents/skills/angular-developer/references/rendering-strategies.md
new file mode 100644
index 00000000..3b426002
--- /dev/null
+++ b/.agents/skills/angular-developer/references/rendering-strategies.md
@@ -0,0 +1,44 @@
+# Rendering Strategies
+
+Angular supports multiple rendering strategies to optimize for SEO, performance, and interactivity.
+
+## 1. Client-Side Rendering (CSR)
+
+**Default Strategy.** Content is rendered entirely in the browser.
+
+- **Use case**: Interactive dashboards, internal tools.
+- **Pros**: Simplest to configure, low server cost.
+- **Cons**: Poor SEO, slower initial content visibility (must wait for JS).
+
+## 2. Static Site Generation (SSG / Prerendering)
+
+Content is pre-rendered into static HTML files at **build time**.
+
+- **Use case**: Marketing pages, blogs, documentation.
+- **Pros**: Fastest initial load, excellent SEO, CDN-friendly.
+- **Cons**: Requires rebuild for content updates, not for user-specific data.
+
+## 3. Server-Side Rendering (SSR)
+
+Content is rendered on the server for the **initial request**. Subsequent navigations happen client-side (SPA style).
+
+- **Use case**: E-commerce product pages, news sites, personalized dynamic content.
+- **Pros**: Excellent SEO, fast initial content visibility.
+- **Cons**: Requires a server (Node.js), higher server cost/latency.
+
+## Hydration
+
+Hydration is the process of making server-rendered HTML interactive in the browser.
+
+- **Full Hydration**: The entire app becomes interactive at once.
+- **Incremental Hydration**: (Advanced) Parts become interactive as needed using `@defer` blocks.
+- **Event Replay**: Captures and replays user events that happened before hydration finished.
+
+## Decision Matrix
+
+| Requirement | Strategy |
+| :------------------------------ | :------------------- |
+| **SEO + Static Content** | SSG |
+| **SEO + Dynamic Content** | SSR |
+| **No SEO + High Interactivity** | CSR |
+| **Mixed** | Hybrid (Route-based) |
diff --git a/.agents/skills/angular-developer/references/resource.md b/.agents/skills/angular-developer/references/resource.md
new file mode 100644
index 00000000..e356ea51
--- /dev/null
+++ b/.agents/skills/angular-developer/references/resource.md
@@ -0,0 +1,77 @@
+# Async Reactivity with `resource`
+
+> [!IMPORTANT]
+> The `resource` API is currently experimental in Angular.
+
+A `Resource` incorporates asynchronous data fetching into Angular's signal-based reactivity. It executes an async loader function whenever its dependencies change, exposing the status and result as synchronous signals.
+
+## Basic Usage
+
+The `resource` function accepts an options object with two main properties:
+
+1. `params`: A reactive computation (like `computed`). When signals read here change, the resource re-fetches.
+2. `loader`: An async function that fetches data based on the parameters.
+
+```ts
+import { Component, resource, signal, computed } from '@angular/core';
+
+@Component({...})
+export class UserProfile {
+ userId = signal('123');
+
+ userResource = resource({
+ // Reactively tracking userId
+ params: () => ({ id: this.userId() }),
+
+ // Executes whenever params change
+ loader: async ({ params, abortSignal }) => {
+ const response = await fetch(`/api/users/${params.id}`, { signal: abortSignal });
+ if (!response.ok) throw new Error('Network error');
+ return response.json();
+ }
+ });
+
+ // Use the resource value in computed signals
+ userName = computed(() => {
+ if (this.userResource.hasValue()) {
+ return this.userResource.value()?.name;
+ } else {
+ return 'Loading...';
+ }
+ });
+}
+```
+
+## Aborting Requests
+
+If the `params` signal changes while a previous loader is still running, the `Resource` will attempt to abort the outstanding request using the provided `abortSignal`. **Always pass `abortSignal` to your `fetch` calls.**
+
+## Reloading Data
+
+You can imperatively force the resource to re-run the loader without the params changing by calling `.reload()`.
+
+```ts
+this.userResource.reload();
+```
+
+## Resource Status Signals
+
+The `Resource` object provides several signals to read its current state:
+
+- `value()`: The resolved data, or `undefined`.
+- `hasValue()`: Type-guard boolean. `true` if a value exists.
+- `isLoading()`: Boolean indicating if the loader is currently running.
+- `error()`: The error thrown by the loader, or `undefined`.
+- `status()`: A string constant representing the exact state (`'idle'`, `'loading'`, `'resolved'`, `'error'`, `'reloading'`, `'local'`).
+
+## Local Mutation
+
+You can optimistically update the resource's value directly. This changes the status to `'local'`.
+
+```ts
+this.userResource.value.set({name: 'Optimistic Update'});
+```
+
+## Reactive Data Fetching with `httpResource`
+
+If you are using Angular's `HttpClient`, prefer using `httpResource`. It is a specialized wrapper that leverages the Angular HTTP stack (including interceptors) while providing the same signal-based resource API.
diff --git a/.agents/skills/angular-developer/references/route-animations.md b/.agents/skills/angular-developer/references/route-animations.md
new file mode 100644
index 00000000..56cebbed
--- /dev/null
+++ b/.agents/skills/angular-developer/references/route-animations.md
@@ -0,0 +1,56 @@
+# Route Transition Animations
+
+Angular Router supports the browser's **View Transitions API** for smooth visual transitions between routes.
+
+## Enabling View Transitions
+
+Add `withViewTransitions()` to your router configuration.
+
+```ts
+provideRouter(routes, withViewTransitions());
+```
+
+This is a **progressive enhancement**. In browsers that don't support the API, the router will still work but without the transition animation.
+
+## How it Works
+
+1. Browser takes a screenshot of the old state.
+2. Router updates the DOM (activates new component).
+3. Browser takes a screenshot of the new state.
+4. Browser animates between the two states.
+
+## Customizing with CSS
+
+Transitions are customized in **global CSS files** (not component-scoped CSS).
+
+Use the `::view-transition-old()` and `::view-transition-new()` pseudo-elements.
+
+```css
+/* Example: Cross-fade + Slide */
+::view-transition-old(root) {
+ animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out;
+}
+::view-transition-new(root) {
+ animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in;
+}
+```
+
+## Advanced Control
+
+Use `onViewTransitionCreated` to skip transitions or customize behavior based on the navigation context.
+
+```ts
+withViewTransitions({
+ onViewTransitionCreated: ({transition, from, to}) => {
+ // Skip animation for specific routes
+ if (to.url === '/no-animation') {
+ transition.skipTransition();
+ }
+ },
+});
+```
+
+## Best Practices
+
+- **Global Styles**: Always define transition animations in `styles.css` to avoid view encapsulation issues.
+- **View Transition Names**: Assign unique `view-transition-name` to elements that should transition smoothly across routes (e.g., a header image).
diff --git a/.agents/skills/angular-developer/references/route-guards.md b/.agents/skills/angular-developer/references/route-guards.md
new file mode 100644
index 00000000..9169d543
--- /dev/null
+++ b/.agents/skills/angular-developer/references/route-guards.md
@@ -0,0 +1,52 @@
+# Route Guards
+
+Route guards control whether a user can navigate to or leave a route.
+
+## Types of Guards
+
+- **`CanActivate`**: Can the user access this route? (e.g., Auth check).
+- **`CanActivateChild`**: Can the user access children of this route?
+- **`CanDeactivate`**: Can the user leave this route? (e.g., Unsaved changes).
+- **`CanMatch`**: Should this route even be considered for matching? (e.g., Feature flags). If it returns `false`, the router continues checking other routes.
+
+## Creating a Guard
+
+Guards are typically functional since Angular 15.
+
+```ts
+export const authGuard: CanActivateFn = (route, state) => {
+ const authService = inject(AuthService);
+ const router = inject(Router);
+
+ if (authService.isLoggedIn()) {
+ return true;
+ }
+
+ // Redirect to login
+ return router.parseUrl('/login');
+};
+```
+
+## Applying Guards
+
+Add them to the route configuration as an array. They execute in order.
+
+```ts
+{
+ path: 'admin',
+ component: Admin,
+ canActivate: [authGuard],
+ canActivateChild: [adminChildGuard],
+ canDeactivate: [unsavedChangesGuard]
+}
+```
+
+## Return Values
+
+- `boolean`: `true` to allow, `false` to block.
+- `UrlTree` or `RedirectCommand`: Redirect to a different route.
+- `Observable` or `Promise`: Resolves to the above types.
+
+## Security Note
+
+**Client-side guards are NOT a substitute for server-side security.** Always verify permissions on the server.
diff --git a/.agents/skills/angular-developer/references/router-lifecycle.md b/.agents/skills/angular-developer/references/router-lifecycle.md
new file mode 100644
index 00000000..be9aeb6e
--- /dev/null
+++ b/.agents/skills/angular-developer/references/router-lifecycle.md
@@ -0,0 +1,45 @@
+# Router Lifecycle and Events
+
+Angular Router emits events through the `Router.events` observable, allowing you to track the navigation lifecycle from start to finish.
+
+## Common Router Events (Chronological)
+
+1. **`NavigationStart`**: Navigation begins.
+2. **`RoutesRecognized`**: Router matches the URL to a route.
+3. **`GuardsCheckStart` / `End`**: Evaluation of `canActivate`, `canMatch`, etc.
+4. **`ResolveStart` / `End`**: Data resolution phase (fetching data via resolvers).
+5. **`NavigationEnd`**: Navigation completed successfully.
+6. **`NavigationCancel`**: Navigation canceled (e.g., guard returned `false`).
+7. **`NavigationError`**: Navigation failed (e.g., error in resolver).
+
+## Subscribing to Events
+
+Inject the `Router` and filter the `events` observable.
+
+```ts
+import {Router, NavigationStart, NavigationEnd} from '@angular/router';
+
+export class MyService {
+ private router = inject(Router);
+
+ constructor() {
+ this.router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe((event) => {
+ console.log('Navigated to:', event.url);
+ });
+ }
+}
+```
+
+## Debugging
+
+Enable detailed console logging of all routing events during application bootstrap.
+
+```ts
+provideRouter(routes, withDebugTracing());
+```
+
+## Common Use Cases
+
+- **Loading Indicators**: Show a spinner when `NavigationStart` fires and hide it on `NavigationEnd`/`Cancel`/`Error`.
+- **Analytics**: Track page views by listening for `NavigationEnd`.
+- **Scroll Management**: Respond to `Scroll` events for custom scroll behavior.
diff --git a/.agents/skills/angular-developer/references/router-testing.md b/.agents/skills/angular-developer/references/router-testing.md
new file mode 100644
index 00000000..fc18d9ca
--- /dev/null
+++ b/.agents/skills/angular-developer/references/router-testing.md
@@ -0,0 +1,87 @@
+# Testing with the RouterTestingHarness
+
+When testing components that involve routing, it is crucial **not to mock the Router or related services**. Instead, use the `RouterTestingHarness`, which provides a robust and reliable way to test routing logic in an environment that closely mirrors a real application.
+
+Using the harness ensures you are testing the actual router configuration, guards, and resolvers, leading to more meaningful tests.
+
+## Setting Up for Router Testing
+
+The `RouterTestingHarness` is the primary tool for testing routing scenarios. You also need to provide your test routes using the `provideRouter` function in your `TestBed` configuration.
+
+### Example Setup
+
+```ts
+import {TestBed} from '@angular/core/testing';
+import {provideRouter} from '@angular/router';
+import {RouterTestingHarness} from '@angular/router/testing';
+import {Dashboard} from './dashboard.component';
+import {HeroDetail} from './hero-detail.component';
+
+describe('Dashboard Component Routing', () => {
+ let harness: RouterTestingHarness;
+
+ beforeEach(async () => {
+ // 1. Configure TestBed with test routes
+ await TestBed.configureTestingModule({
+ providers: [
+ // Use provideRouter with your test-specific routes
+ provideRouter([
+ {path: '', component: Dashboard},
+ {path: 'heroes/:id', component: HeroDetail},
+ ]),
+ ],
+ }).compileComponents();
+
+ // 2. Create the RouterTestingHarness
+ harness = await RouterTestingHarness.create();
+ });
+});
+```
+
+### Key Concepts
+
+1. **`provideRouter([...])`**: Provide a test-specific routing configuration. This should include the routes necessary for the component-under-test to function correctly.
+2. **`RouterTestingHarness.create()`**: Asynchronously creates and initializes the harness and performs an initial navigation to the root URL (`/`).
+
+## Writing Router Tests
+
+Once the harness is created, you can use it to drive navigation and make assertions on the state of the router and the activated components.
+
+### Example: Testing Navigation
+
+```ts
+it('should navigate to a hero detail when a hero is selected', async () => {
+ // 1. Navigate to the initial component and get its instance
+ const dashboard = await harness.navigateByUrl('/', Dashboard);
+
+ // Suppose the dashboard has a method to select a hero
+ const heroToSelect = {id: 42, name: 'Test Hero'};
+ dashboard.selectHero(heroToSelect);
+
+ // Wait for stability after the action that triggers navigation
+ await harness.fixture.whenStable();
+
+ // 2. Assert on the URL
+ expect(harness.router.url).toEqual('/heroes/42');
+
+ // 3. Get the activated component after navigation
+ const heroDetail = await harness.getHarness(HeroDetail);
+
+ // 4. Assert on the state of the new component
+ expect(await heroDetail.componentInstance.hero.name).toBe('Test Hero');
+});
+
+it('should get the activated component directly', async () => {
+ // Navigate and get the component instance in one step
+ const dashboardInstance = await harness.navigateByUrl('/', Dashboard);
+
+ expect(dashboardInstance).toBeInstanceOf(Dashboard);
+});
+```
+
+### Best Practices
+
+- **Navigate with the Harness:** Always use `harness.navigateByUrl()` to simulate navigation. This method returns a promise that resolves with the instance of the activated component.
+- **Access the Router State:** Use `harness.router` to access the live router instance and assert on its state (e.g., `harness.router.url`).
+- **Get Activated Components:** Use `harness.getHarness(ComponentType)` to get an instance of a component harness for the currently activated routed component, or `harness.routeDebugElement` to get the `DebugElement`.
+- **Wait for Stability:** After performing an action that causes navigation, always `await harness.fixture.whenStable()` to ensure the routing is complete before making assertions.
diff --git a/.agents/skills/angular-developer/references/show-routes-with-outlets.md b/.agents/skills/angular-developer/references/show-routes-with-outlets.md
new file mode 100644
index 00000000..af43f014
--- /dev/null
+++ b/.agents/skills/angular-developer/references/show-routes-with-outlets.md
@@ -0,0 +1,68 @@
+# Show Routes with Outlets
+
+The `RouterOutlet` directive is a placeholder where Angular renders the component for the current URL.
+
+## Basic Usage
+
+Include `
` in your template. Angular inserts the routed component as a sibling immediately following the outlet.
+
+```html
+
+
+
+```
+
+## Nested Outlets
+
+Child routes require their own `
` within the parent component's template.
+
+```ts
+// Parent component template
+
Settings
+
+```
+
+## Named Outlets (Secondary Routes)
+
+Pages can have multiple outlets. Assign a `name` to an outlet to target it specifically. The default name is `'primary'`.
+
+```html
+
+
+
+
+```
+
+Define the `outlet` in the route config:
+
+```ts
+{
+ path: 'chat',
+ component: Chat,
+ outlet: 'sidebar'
+}
+```
+
+## Outlet Lifecycle Events
+
+`RouterOutlet` emits events when components are changed:
+
+- `activate`: New component instantiated.
+- `deactivate`: Component destroyed.
+- `attach` / `detach`: Used with `RouteReuseStrategy`.
+
+```html
+
+```
+
+## Passing Data via `routerOutletData`
+
+You can pass contextual data to the routed component using the `routerOutletData` input. The component accesses this via the `ROUTER_OUTLET_DATA` injection token as a signal.
+
+```ts
+// In Parent
+
+
+// In Routed Component
+outletData = inject(ROUTER_OUTLET_DATA) as Signal<{ theme: string }>;
+```
diff --git a/.agents/skills/angular-developer/references/signal-forms.md b/.agents/skills/angular-developer/references/signal-forms.md
new file mode 100644
index 00000000..992fab10
--- /dev/null
+++ b/.agents/skills/angular-developer/references/signal-forms.md
@@ -0,0 +1,897 @@
+# Signal Forms
+
+Signal Forms are the recommended approach for handling forms in modern Angular applications (v21+). They provide a reactive, type-safe, and model-driven way to manage form state using Angular Signals.
+
+**CRITICAL**: You MUST use Angular's new Signal Forms API for all form-related functionality. Do NOT use null as a value or type of any fields.
+
+## Imports
+
+You can import the following from `@angular/forms/signals`:
+
+```ts
+import {
+ form,
+ FormField,
+ submit,
+ // Rules for field state
+ disabled,
+ hidden,
+ readonly,
+ debounce,
+ // Schema helpers
+ applyWhen,
+ applyEach,
+ schema,
+ // Custom validation
+ validate,
+ validateHttp,
+ validateStandardSchema,
+ // Metadata
+ metadata,
+} from '@angular/forms/signals';
+```
+
+## Creating a Form
+
+Use the `form()` function with a Signal model. The structure of the form is derived directly from the model.
+
+```ts
+import {Component, signal} from '@angular/core';
+import {form, FormField} from '@angular/forms/signals';
+
+@Component({
+ // ...
+ imports: [FormField],
+})
+export class Example {
+ // 1. Define your model with initial values (avoid undefined)
+ userModel = signal({
+ name: '', // CRITICAL: NEVER use null or undefined as initial values
+ email: '',
+ age: 0, // Use 0 for numbers, NOT null
+ address: {
+ street: '',
+ city: '',
+ },
+ hobbies: [] as string[], // Use [] for arrays, NOT null
+ });
+
+ // WRONG - DO NOT DO THIS:
+ // badModel = signal({
+ // name: null, // ERROR: use '' instead
+ // age: null, // ERROR: use 0 instead
+ // items: null // ERROR: use [] instead
+ // });
+
+ // 2. Create the form
+ userForm = form(this.userModel);
+}
+```
+
+## Validation
+
+Import validators from `@angular/forms/signals`.
+
+```ts
+import {required, email, min, max, minLength, maxLength, pattern} from '@angular/forms/signals';
+```
+
+Use them in the schema function passed to `form()`:
+
+```ts
+userForm = form(this.userModel, (schemaPath) => {
+ // Required
+ required(schemaPath.name, {message: 'Name is required'});
+
+ // Conditional required.
+ required(schemaPath.name, {
+ when({valueOf}) {
+ return valueOf(schemaPath.age) > 10;
+ },
+ });
+ // when is only available for required
+ // Do NOT do this: pattern(p.name, /xxx/, {when /* ERROR */)
+
+ // Email
+ email(schemaPath.email, {message: 'Invalid email'});
+
+ // Min/Max for numbers
+ min(schemaPath.age, 18);
+ max(schemaPath.age, 100);
+
+ // MinLength/MaxLength for strings/arrays
+ minLength(schemaPath.password, 8);
+ maxLength(schemaPath.description, 500);
+
+ // Pattern (Regex)
+ pattern(schemaPath.zipCode, /^\d{5}$/);
+});
+```
+
+## FieldState vs FormField: The Parental Requirement
+
+It's important to understand the difference between **FormField** (the structure) and **FieldState** (the actual data/signals).
+
+**RULE**: You must **CALL** a field as a function to access its state signals (valid, touched, dirty, hidden, etc.).
+
+```ts
+// f is a FormField (structural)
+const f = form(signal({cat: {name: 'pirojok-the-cat', age: 5}}));
+
+f.cat.name; // FormField: You can't get flags from here!
+f.cat.name.touched(); // ERROR: touched() does not exist on FormField
+
+f.cat.name(); // FieldState: Calling it gives you access to signals
+f.cat.name().touched(); // VALID: Accessing the signal
+f.cat().name.touched(); // ERROR: f.cat() is state, it doesn't have children!
+```
+
+Similarly in a template:
+
+```html
+
+@if (bookingForm.hotelDetails.hidden()) { ... }
+
+
+@if (bookingForm.hotelDetails().hidden()) { ... }
+```
+
+## Disabled / Readonly / Hidden
+
+Control field status using rules in the schema.
+
+```ts
+import {disabled, readonly, hidden} from '@angular/forms/signals';
+
+userForm = form(this.userModel, (schemaPath) => {
+ // Conditionally disabled
+ disabled(schemaPath.password, ({valueOf}) => !valueOf(schemaPath.createAccount));
+
+ // Conditionally hidden (does NOT remove from model, just marks as hidden)
+ hidden(schemaPath.shippingAddress, ({valueOf}) => valueOf(schemaPath.sameAsBilling));
+
+ // Readonly
+ readonly(schemaPath.username);
+});
+```
+
+## Binding
+
+Import `FormField` and use the `[formField]` directive.
+
+```ts
+import {FormField} from '@angular/forms/signals';
+```
+
+All props on state, such as `disabled`, `hidden`, `readonly` and `name` are bound automatically.
+Do _NOT_ bind the `name` field.
+
+**CRITICAL: FORBIDDEN ATTRIBUTES**
+When using `[formField]`, you MUST NOT set the following attributes in the template (either static or bound):
+
+- `min`, `max` (Use validators in the schema instead)
+- `value`, `[value]`, `[attr.value]` (Already handled by `[formField]`)
+- `[attr.min]`, `[attr.max]`
+- `[disabled]`, `[readonly]` (Already handled by `[formField]`)
+
+Do NOT do this: `
` or `
`.
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Reactive Forms
+
+**Do NOT import** `FormControl`, `FormGroup`, `FormArray`, or `FormBuilder` from `@angular/forms`. Signal Forms replace these concepts entirely.
+Signal forms does NOT have a builder.
+
+## Accessing State
+
+Each field in the form is a function that returns its state.
+
+```ts
+// Access the field by calling it
+const emailState = this.userForm.email();
+
+// Value (WritableSignal)
+const value = this.userForm().value();
+
+// Validation State (Signals)
+const isValid = this.userForm().valid();
+const isInvalid = this.userForm().invalid();
+const errors = this.userForm().errors(); // Array of errors
+const isPending = this.userForm().pending(); // Async validation pending
+
+// Interaction State (Signals)
+const isTouched = this.userForm().touched();
+const isDirty = this.userForm().dirty();
+
+// Availability State (Signals)
+const isDisabled = this.userForm().disabled();
+const isHidden = this.userForm().hidden();
+const isReadonly = this.userForm().readonly();
+```
+
+IMPORTANT!: Make sure to call the field to get it state.
+
+```ts
+form().invalid()
+form.field().dirty()
+form.field.subfield().touched()
+form.a.b.c.d().value()
+form.address.ssn().pending()
+form().reset()
+
+// The only exception is length:
+form.children.length
+form.length // NOTE: no parenthesis!
+form.client.addresses.length // No "()"
+
+@for (income of form.addresses; track $index) {/**/}
+```
+
+## Submitting
+
+Use the `submit()` function. It automatically marks all fields as touched before running the action.
+
+**CRITICAL**: The callback to `submit()` MUST be `async` and MUST return a Promise.
+
+```ts
+import { submit } from '@angular/forms/signals';
+
+// CORRECT - async callback
+onSubmit() {
+ submit(this.userForm, async () => {
+ // This only runs if the form is valid
+ await this.apiService.save(this.userModel());
+ console.log('Saved!');
+ });
+}
+
+// WRONG - missing async keyword
+onSubmit() {
+ submit(this.userForm, () => { // ERROR: must be async
+ console.log('Saved!');
+ });
+}
+```
+
+## Handling Errors
+
+`field().errors()` returns the errors array of ValidationError:
+
+```ts
+interface ValidationError {
+ readonly kind: string;
+ readonly message?: string;
+}
+```
+
+Do _NOT_ return null from validators.
+When there are no errors, return undefined
+
+### Context
+
+Functions passed to rules like `validate()`, `disabled()`, `applyWhen` take a context object. It is **CRITICAL** to understand its structure:
+
+```ts
+validate(
+ schemaPath.username,
+ ({
+ value, // Signal
: Writable current value of the field
+ fieldTree, // FieldTree: Sub-fields (if it's a group/array)
+ state, // FieldState: Access flags like state.valid(), state.dirty()
+ valueOf, // (path) => T: Read values of OTHER fields (tracking dependencies), e.g. valueOf(schemaPath.password)
+ stateOf, // (path) => FieldState: Access state (valid/dirty) of OTHER fields, e.g. stateOf(schemaPath.password).valid()
+ pathKeys, // Signal: Path from root to this field
+ }) => {
+ // WRONG: if (touched()) ... (touched is not in context)
+ // RIGHT: if (state.touched()) ...
+
+ if (value() === 'admin') {
+ return {kind: 'reserved', message: 'Username admin is reserved'};
+ }
+ },
+);
+```
+
+### IMPORTANT: Paths are NOT Signals
+
+Inside the `form()` callback, `schemaPath` and its children (e.g., `schemaPath.user.name`) are **NOT** signals and are **NOT** callable.
+
+```ts
+// WRONG - This will throw an error:
+applyWhen(p.ssn, () => p.ssn().touched(), (ssnField) => { ... });
+
+// RIGHT - Use stateOf() to get the state of a path:
+applyWhen(p.ssn, ({ stateOf }) => stateOf(p.ssn).touched(), (ssnField) => { ... });
+
+// RIGHT - Use valueOf() to get the value of a path:
+applyWhen(p.ssn, ({ valueOf }) => valueOf(p.ssn) !== '', (ssnField) => { ... });
+```
+
+### Multiple Items
+
+- Use `applyEach` for applying rules per item.
+- **CRITICAL**: `applyEach` callback takes ONLY ONE argument (the item path), NOT two:
+
+```ts
+// CORRECT - single argument
+applyEach(s.items, (item) => {
+ required(item.name);
+});
+
+// WRONG - do NOT pass index
+applyEach(s.items, (item, index) => {
+ // ERROR: callback takes 1 argument
+ required(item.name);
+});
+```
+
+- In the template use `@for` to iterate over the items.
+- To remove an item from an array, just remove appropriate item from the array in the data.
+- **`select` binding**: You CAN bind to `