mirror of
https://github.com/kamask-dev/pchelpmaster.git
synced 2026-11-11 05:49:38 +00:00
9.8 KiB
9.8 KiB
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:
docs/architecture.md— layers, DI, SSR, security, UI principles;docs/data-model.md— collections, fields, access rules;docs/testing.md— how tests are written;- the page
docs/guide/<app part>.mdfor 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.mdordocs/data-model.md, stop and discuss the document change with the user. - Before finishing, run
pnpm lintand 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 areorders. - 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
ownerfield). 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/*orpocketbase;ui/does not importpocketbaseordata/. PocketBase records never leavedata/. - 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 inshared/pocketbase/. - Do not touch
window/documentwithout a platform check; useDOCUMENT,isPlatformBrowser,afterNextRender. - The browser reaches PocketBase via
/pb/*; the SSR server goes directly viaPB_URLand 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/<feature>/(e.g.src/app/clients/), not globalcomponents/,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/.servicesuffixes (like the existingapp.ts) - Each feature has its own routes file (
<feature>.routes.ts), and the feature is lazy-loaded fromapp.routes.ts - Shared infrastructure goes in
src/app/shared/, only when the code is really needed by two or more features. Do not create acore/folder
TypeScript
- Strict type checking
- Prefer type inference when the type is obvious
- Avoid
any; if the type is unknown, useunknown
Angular
- Always use standalone components over NgModules
- Do NOT set
standalone: truein Angular decorators — it is the default in Angular v20+. - Do NOT set
changeDetection: ChangeDetectionStrategy.OnPushexplicitly —OnPushis the default in Angular v22+. - The selector prefix for components and directives is
ksk(ksk-order-list,kskAutofocus) - Do NOT use the
@HostBindingand@HostListenerdecorators. Put host bindings in thehostobject of the@Componentor@Directivedecorator - Use
NgOptimizedImagefor all static images.NgOptimizedImagedoes not work for inline base64 images.
Components
- Keep components small and focused on a single responsibility
- Use
input()andoutput()functions instead of decorators - Use
model()for two-way binding with the[(prop)]syntax instead of pairinginput()withoutput() - 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 asAsyncPipeorDatePipe
State
- Signals for local component state
computed()for derived statelinkedSignal()for state derived from multiple reactive sources that must stay synchronized- Keep state transformations pure and predictable
- Do NOT use
mutateon signals; useupdateorset - 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, useclassbindings; do NOT usengStyle, usestylebindings - 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
@Servicedecorator 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.Serverinapp.routes.server.tsonly for''(home),orders/:id(order page),p/:token(public page). All other routes areRenderMode.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-maxandfrontend-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 viabrowser_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 viaprefers-color-scheme. - Minimal GPU load: animate only
transformandopacity, respectprefers-reduced-motion; nobackdrop-filter,filter: blur(), heavy or layered shadows, animated gradients, or permanentwill-change(details —docs/architecture.md, section "Формы и UI"). - The UI is in Russian only (no i18n framework); dates and amounts use the
ru-RUlocale, 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 intests/. - 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 fromdocs/README.mdand 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, ordocs/testing.md. - A new command, environment variable, or startup step — update
README.md.
Git
- GitHub Flow: there is NO separate
developbranch.mainis 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/<short-name>,fix/<short-name>,release/<version> - 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