You are an expert in TypeScript, Angular, and PocketBase. You write functional, maintainable, performant, and accessible code following Angular and TypeScript best practices. ## Project Pchelpcrm is a multi-user CRM for private service professionals: clients, orders, tags, and a public link to an order. Angular 22 with SSR + PocketBase 0.40 + pnpm. The description, commands, and repository structure are in `README.md`. Keep solutions simple. ## Before you start Read: 1. `docs/architecture.md` — layers, DI, SSR, security, UI principles; 2. `docs/data-model.md` — collections, fields, access rules; 3. `docs/testing.md` — how tests are written; 4. the page `docs/guide/.md` for the part you are changing, if it already exists (table of contents — `docs/README.md`). ## How to work - Develop with TDD: tests first, then the implementation. - If a task contains a "Forbidden" section ("Запрещено"), obey it. - If a solution diverges from `docs/architecture.md` or `docs/data-model.md`, stop and discuss the document change with the user. - Before finishing, run `pnpm lint` and all existing test suites (`pnpm test`, `pnpm test:api`, `pnpm test:integration`, `pnpm e2e` — those already set up). - Update the documentation in the same change (see the "Documentation" section below). ## Domain - An order in code is `Order`; the collection, folder, and routes are `orders`. - Tags (`Tag`) are created by the user. They replace categories and sources: no separate categories/sources and no hardcoded lists or enums of tags in code. - Everything except the user belongs to the user (the `owner` field). Isolation is enforced by PocketBase access rules, not by the frontend. - Delivery is ONE Docker container (SSR server + PocketBase). Do not design anything that requires multiple containers. ## Architecture - Layers inside a feature: `domain/`, `data/`, `ui/`, `testing/`. `domain/` does not import `@angular/*` or `pocketbase`; `ui/` does not import `pocketbase` or `data/`. PocketBase records never leave `data/`. - Repositories and services that may get another implementation are described by an abstract class (which doubles as the DI token) and are registered in the feature's `provideXxx()`. - A feature imports another feature only through its `index.ts`, with no cycles; feedback goes through extension points (`InjectionToken`). - There is no separate store layer; a signal-based store only if several components share the same state. - PocketBase errors are translated into domain errors from `shared/`. ## SSR and data isolation - **Forbidden** to create PocketBase at module level or to keep user data in module variables, static fields, and caches outside DI. `new PocketBase(` only in the factory in `shared/pocketbase/`. - Do not touch `window`/`document` without a platform check; use `DOCUMENT`, `isPlatformBrowser`, `afterNextRender`. - The browser reaches PocketBase via `/pb/*`; the SSR server goes directly via `PB_URL` and does not proxy the API. - Protected files (attachments) are not rendered on the server. ## Project structure - Code is organized by feature, not by file type: `src/app//` (e.g. `src/app/clients/`), not global `components/`, `services/`, `pipes/` folders - Everything a feature needs lives inside its folder, including routes and tests - One concept per file: one component, directive, pipe, or service per file - Files of the same entity sit together with the same base name (`order-list.ts`, `order-list.html`, `order-list.css`, `order-list.spec.ts`) - File names in kebab-case. Do NOT add `.component` / `.service` suffixes (like the existing `app.ts`) - Each feature has its own routes file (`.routes.ts`), and the feature is lazy-loaded from `app.routes.ts` - Shared infrastructure goes in `src/app/shared/`, only when the code is really needed by two or more features. Do not create a `core/` folder ## TypeScript - Strict type checking - Prefer type inference when the type is obvious - Avoid `any`; if the type is unknown, use `unknown` ## Angular - Always use standalone components over NgModules - Do NOT set `standalone: true` in Angular decorators — it is the default in Angular v20+. - Do NOT set `changeDetection: ChangeDetectionStrategy.OnPush` explicitly — `OnPush` is the default in Angular v22+. - The selector prefix for components and directives is `ksk` (`ksk-order-list`, `kskAutofocus`) - Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings in the `host` object of the `@Component` or `@Directive` decorator - Use `NgOptimizedImage` for all static images. - `NgOptimizedImage` does not work for inline base64 images. ### Components - Keep components small and focused on a single responsibility - Use `input()` and `output()` functions instead of decorators - Use `model()` for two-way binding with the `[(prop)]` syntax instead of pairing `input()` with `output()` - Prefer inline templates for small components; move large templates and styles to separate files - In external templates/styles, use paths relative to the component's TS file. - Do NOT import `CommonModule`; import only the directives and pipes the template uses, such as `AsyncPipe` or `DatePipe` ### State - Signals for local component state - `computed()` for derived state - `linkedSignal()` for state derived from multiple reactive sources that must stay synchronized - Keep state transformations pure and predictable - Do NOT use `mutate` on signals; use `update` or `set` - Load data asynchronously in components with `resource()` (SSR waits for it to complete) ### Templates - Keep templates simple, without complex logic - Native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch` - Do NOT use `ngClass`, use `class` bindings; do NOT use `ngStyle`, use `style` bindings - Use the async pipe for observables - Do not assume globals (e.g. `new Date()`) are available in templates. - User-provided text is never inserted via `innerHTML` ### Forms - Prefer Signal Forms (`@angular/forms/signals`) for new forms. They are stable in Angular v22+ and provide signal-based state, type-safe field access, and schema-based validation - If not Signal Forms, use Reactive forms, not Template-driven ones ### Services - A service is responsible for a single task - `providedIn: 'root'` for singletons - Prefer the `@Service` decorator over `@Injectable({providedIn: 'root'})` for new singleton services (Angular v22+) - Use the `inject()` function instead of constructor injection ### Routing - All routes are lazy-loaded (`loadComponent` / `loadChildren`), including the internal routes of features - `RenderMode.Server` in `app.routes.server.ts` only for `''` (home), `orders/:id` (order page), `p/:token` (public page). All other routes are `RenderMode.Client`. New SSR routes only at the user's explicit request - Private routes are protected by `authGuard` ## UI and accessibility - The app MUST pass all AXE checks and meet WCAG AA minimums, including focus management, color contrast, and ARIA attributes. - All visual and frontend work (layout, styles, look of components, colors, typography, responsiveness) MUST be done using the skills `ui-ux-pro-max` and `frontend-design` (`frontend-design:frontend-design`). Invoke both skills via the Skill tool before building or reshaping any UI. - Always get feedback from a real browser via the Playwright MCP (`mcp__playwright__*`): during UI development and to verify every visual change (snapshot, screenshot, console messages, responsive sizes via `browser_resize`). - Skill recommendations must not violate the rules of this file; on conflict, this file wins. - Plain CSS without preprocessors or CSS frameworks; colors, spacing, and sizes only via design tokens in `src/styles.css`. Dark theme via `prefers-color-scheme`. - Minimal GPU load: animate only `transform` and `opacity`, respect `prefers-reduced-motion`; no `backdrop-filter`, `filter: blur()`, heavy or layered shadows, animated gradients, or permanent `will-change` (details — `docs/architecture.md`, section "Формы и UI"). - The UI is in Russian only (no i18n framework); dates and amounts use the `ru-RU` locale, the currency is rubles. Mobile-first. ## Tests - Unit and integration tests live next to the code (`*.spec.ts`, `*.integration.spec.ts`); API and e2e tests live in `tests/`. - Tests that need PocketBase use a temporary instance, not `pocketbase/pb_data`. - Always verify data isolation with two users. - Other rules — `docs/testing.md`. ## Documentation - When you change or add a part of the app, in the same change update or create its page in `docs/guide/` using the template from `docs/README.md` and add it to the table of contents. - If a decision changes the architecture, the data model, or the way of testing, update `docs/architecture.md`, `docs/data-model.md`, or `docs/testing.md`. - A new command, environment variable, or startup step — update `README.md`. ## Git - GitHub Flow: there is NO separate `develop` branch. `main` is the only long-lived branch - Every working branch is created directly from a fresh `main`: features, fixes, and release preparation - Branches are named by purpose in kebab-case: `feat/`, `fix/`, `release/` - Do NOT create branches yourself: the user creates a branch (by the rules above) when the task is large (a feature, many related changes). Otherwise work in the current branch - Small targeted changes (settings, adding a dependency, minor fixes) do not need a separate branch: they go directly to the current branch, usually `main`, as a regular Conventional Commit - Do NOT commit yourself: commit only at the user's explicit request, because the user reviews changes before every commit. When asked, commit only to the current branch (Conventional Commits) - Do NOT merge, rebase onto `main`, push, or delete branches: merging and branch cleanup are done by the user - There are no pull requests: the user works only with the local repository