@comet/agent-features 9.0.0-canary-20260527154746

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/LICENSE +24 -0
  2. package/package.json +19 -0
  3. package/rules/coding-guidelines/api-nestjs.instructions.md +107 -0
  4. package/rules/coding-guidelines/cdn.instructions.md +24 -0
  5. package/rules/coding-guidelines/general.instructions.md +30 -0
  6. package/rules/coding-guidelines/git.instructions.md +37 -0
  7. package/rules/coding-guidelines/kubernetes.instructions.md +59 -0
  8. package/rules/coding-guidelines/libraries.instructions.md +34 -0
  9. package/rules/coding-guidelines/naming.instructions.md +39 -0
  10. package/rules/coding-guidelines/postgresql.instructions.md +40 -0
  11. package/rules/coding-guidelines/react.instructions.md +102 -0
  12. package/rules/coding-guidelines/security.instructions.md +44 -0
  13. package/rules/coding-guidelines/styling.instructions.md +50 -0
  14. package/rules/coding-guidelines/typescript.instructions.md +50 -0
  15. package/skills/.gitkeep +0 -0
  16. package/skills/comet-block/SKILL.md +246 -0
  17. package/skills/comet-block/references/admin-patterns.md +192 -0
  18. package/skills/comet-block/references/api-patterns.md +183 -0
  19. package/skills/comet-block/references/block-loader.md +368 -0
  20. package/skills/comet-block/references/block-types.md +210 -0
  21. package/skills/comet-block/references/custom-block-field.md +266 -0
  22. package/skills/comet-block/references/fixtures.md +436 -0
  23. package/skills/comet-block/references/image.md +341 -0
  24. package/skills/comet-block/references/migration.md +597 -0
  25. package/skills/comet-block/references/registration.md +167 -0
  26. package/skills/comet-block/references/response-summary.md +102 -0
  27. package/skills/comet-block/references/rich-text.md +309 -0
  28. package/skills/comet-block/references/select.md +176 -0
  29. package/skills/comet-block/references/site-patterns.md +202 -0
  30. package/skills/comet-mail-react/SKILL.md +539 -0
  31. package/skills/comet-mail-react/references/components-and-theme.md +395 -0
  32. package/skills/comet-mail-react/references/layout-patterns.md +315 -0
  33. package/skills/comet-mail-react/references/styling-and-customization.md +306 -0
  34. package/skills/comet-minor-update/SKILL.md +191 -0
  35. package/skills/dev-pm/SKILL.md +100 -0
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2023, Vivid Planet Software GmbH
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@comet/agent-features",
3
+ "version": "9.0.0-canary-20260527154746",
4
+ "description": "Agent features (skills and rules) for Comet projects",
5
+ "repository": {
6
+ "directory": "packages/agent-features",
7
+ "type": "git",
8
+ "url": "https://github.com/vivid-planet/comet"
9
+ },
10
+ "license": "BSD-2-Clause",
11
+ "files": [
12
+ "skills/**",
13
+ "rules/**"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org"
18
+ }
19
+ }
@@ -0,0 +1,107 @@
1
+ ---
2
+ description: NestJS service/controller layering, MikroORM, GraphQL, ACL
3
+ applyTo: "**/api/**/*.ts"
4
+ paths:
5
+ - "**/api/**/*.ts"
6
+ globs:
7
+ - "**/api/**/*.ts"
8
+ alwaysApply: false
9
+ ---
10
+
11
+ # API (NestJS / MikroORM / GraphQL) Rules
12
+
13
+ ## Layers
14
+
15
+ - **Controller / Resolver** = HTTP or GraphQL layer only. Thin: translate input, delegate to services, translate output.
16
+ - **Service** = business logic. Must be decoupled from the transport layer:
17
+ - Do not accept GraphQL `InputType`s directly — accept plain objects / entities.
18
+ - Prefer passing the entire **entity** over passing just an ID (avoids re-fetching and ID-vs-object confusion).
19
+ - Services must be unit-testable and reusable from console jobs.
20
+ - Don't create a service just for pass-through methods. Introduce one only when business logic is reused or when the controller/resolver becomes messy.
21
+ - Utility files are fine if they are **pure, stateless functions**. They must not consume other services or repositories. Name them specifically — no generic `utils/` catch-all folders.
22
+
23
+ ## Access control (ACL)
24
+
25
+ - Put ACL logic in a dedicated service (e.g. `products.acl.service.ts`) or inline in the controller/resolver for per-action checks.
26
+ - **Never** perform ACL checks inside shared business services — console jobs run without a user and would either fail or accidentally double-check.
27
+ - ACL logic must have unit tests.
28
+
29
+ ## Dependency injection & config
30
+
31
+ - Use **constructor-based** injection. Property-based injection only when technically required.
32
+ - Do **not** read `process.env` inside services/controllers. It's untestable, unvalidated, and uncentralized. Exception: app entry points (`main.ts`, `bootstrap.ts`).
33
+
34
+ ## Logging
35
+
36
+ - By default log **warnings and errors only**. Put debug / info / trace behind a flag or env-configured toggle. Logs cost money in Kubernetes — see [kubernetes.instructions.md](kubernetes.instructions.md).
37
+ - Use the built-in [NestJS Logger](https://docs.nestjs.com/techniques/logger).
38
+
39
+ ## MikroORM
40
+
41
+ - Inject `EntityManager` directly. Do **not** inject repositories via `@InjectRepository` / `EntityRepository` — repositories are thin wrappers and add no value while complicating DI.
42
+
43
+ ```ts
44
+ // Good
45
+ constructor(private readonly entityManager: EntityManager) {}
46
+
47
+ async product(id: string) { return this.entityManager.findOneOrFail(Product, id); }
48
+ ```
49
+
50
+ - Prefer `entityManager.create(Entity, data)` over `new Entity()` — `create` forces a complete data object.
51
+ - Down migrations are not required. Use `throw new Error("Unsupported")` in the `down` method. Issues are fixed forward via new deployments, never rollbacks.
52
+
53
+ ## Entity column types
54
+
55
+ - IDs: `type: "uuid"` (see [postgresql.instructions.md](postgresql.instructions.md)).
56
+ - Strings: always `columnType: "text"` — never `varchar(n)`.
57
+ - JSON: prefer `jsonb` over `json`.
58
+ - Timestamps: `columnType: "timestamp with time zone"`.
59
+
60
+ ## DB defaults
61
+
62
+ Avoid DB-level defaults — they aren't available before insert and falsify the entity's TS types. Set the default in TS instead.
63
+
64
+ ```ts
65
+ // Bad
66
+ @Property({ default: false })
67
+ @Field()
68
+ visible: boolean;
69
+
70
+ // Good (GraphQL field — also provide a default in the InputType)
71
+ @Property()
72
+ @Field()
73
+ visible: boolean;
74
+
75
+ // Good (non-GraphQL property)
76
+ @Property()
77
+ visible: boolean = false;
78
+ ```
79
+
80
+ Exception: the upsert pattern may additionally use `defaultRaw`/`onUpdate` as a fallback, on top of the TS default.
81
+
82
+ ## GraphQL
83
+
84
+ ### GraphQL enums
85
+
86
+ - Keys **must equal** values; both use PascalCase — not lowercase, not SCREAMING_CASE. This is **different from TS-only enums** in [typescript.instructions.md](typescript.instructions.md).
87
+
88
+ ```ts
89
+ enum Category {
90
+ Main = "Main",
91
+ Secondary = "Secondary",
92
+ }
93
+ ```
94
+
95
+ Reason: Admin and Site consume the GraphQL schema (which exposes keys). If keys and values diverge, the API gets the wrong value at runtime.
96
+
97
+ ### Int vs Float
98
+
99
+ TypeScript has only one `number`. Be explicit in GraphQL — otherwise Float (less strict) is chosen:
100
+
101
+ ```ts
102
+ @Field(() => Int)
103
+ position: number;
104
+
105
+ @Field(() => Float)
106
+ price: number;
107
+ ```
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: Cache-Control header policy for GET routes (Site and API)
3
+ applyTo: "**/api/**/*.controller.ts,**/api/**/*.resolver.ts,**/site/**/route.ts,**/site/**/next.config.js,**/site/**/next.config.ts,**/site/**/next.config.mjs"
4
+ paths:
5
+ - "**/api/**/*.controller.ts"
6
+ - "**/api/**/*.resolver.ts"
7
+ - "**/site/**/route.ts"
8
+ - "**/site/**/next.config.{js,ts,mjs}"
9
+ globs:
10
+ - "**/api/**/*.controller.ts"
11
+ - "**/api/**/*.resolver.ts"
12
+ - "**/site/**/route.ts"
13
+ - "**/site/**/next.config.{js,ts,mjs}"
14
+ alwaysApply: false
15
+ ---
16
+
17
+ # CDN / Caching Rules
18
+
19
+ - Cache behavior is **controlled by the origin**. Never rely on CDN defaults.
20
+ - Every GET response (Site and API) must set an explicit `Cache-Control` header.
21
+ - Pick the TTL deliberately for the content:
22
+ - Static assets with cache-busting hashes → long TTL with `immutable`.
23
+ - API responses → short TTL, or `no-store` when the response is per-user / sensitive.
24
+ - In Comet, all built-in routes already set `Cache-Control` — if you add a custom route/handler, you are responsible for setting it too.
@@ -0,0 +1,30 @@
1
+ ---
2
+ description: Language-agnostic naming, control-flow, and comment rules
3
+ applyTo: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.mjs,**/*.cjs"
4
+ paths:
5
+ - "**/*.{ts,tsx,js,jsx,mjs,cjs}"
6
+ globs:
7
+ - "**/*.{ts,tsx,js,jsx,mjs,cjs}"
8
+ alwaysApply: false
9
+ ---
10
+
11
+ # General Rules (all languages)
12
+
13
+ ## Naming
14
+
15
+ - Use descriptive names. A reader should understand intent without reading the implementation or a comment.
16
+ - Prefer descriptive identifiers over explanatory comments — comments drift out of sync with the code.
17
+ - Boolean variables must read as booleans: prefix with `is` / `has` / `should` (exceptions: well-known flags like `loading`, `disabled`).
18
+ - Name booleans in the **affirmative**: `isComplete`, not `isNotComplete`. Negate at the use site with `!`.
19
+ - Do **not** use abbreviations. Exceptions: widely-known protocols/acronyms (HTML, CSS, TCP, API, SSO…) and names dictated by third parties.
20
+ - When an acronym appears in PascalCase / camelCase, treat it like a word: `GuiController`, `UiElement` — not `GUIController` / `UIElement`.
21
+
22
+ ## Control flow
23
+
24
+ - **Never use exceptions for control flow.** Exceptions signal _exceptional_ situations; using them for expected branches hides real failures. Check preconditions explicitly (`if (!(await exists(id))) return undefined;`) instead of wrapping a `findOrFail` in try/catch.
25
+
26
+ ## Comments
27
+
28
+ - Default to writing no comments. Only add a comment when the _why_ is non-obvious (hidden constraint, workaround, surprising invariant).
29
+ - Never write comments that restate _what_ the code does — the names should do that.
30
+ - Never reference the current task, ticket, or PR in comments — that context belongs in the PR description and rots in code.
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Git, commit, PR, and changeset conventions for this repo
3
+ applyTo: "**"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Git Rules
8
+
9
+ ## Pull requests
10
+
11
+ - One PR per change (feature, fix, or refactor). Never combine unrelated tasks (e.g. bugfix + new feature) in one PR.
12
+ - Do **not** include an unrelated bugfix in a feature PR, even as a separate commit. Open a follow-up PR instead.
13
+ - Changes to `api`, `admin`, and `site` in the same PR should **not** be split into separate commits.
14
+ - Keep PRs as small as possible. Avoid unnecessary new dependencies.
15
+ - If the `main` pipeline is red, do not merge anything that does not contribute to fixing it.
16
+
17
+ ## Commits
18
+
19
+ - Write commit messages in English, in the imperative, starting with a capital letter: `Add margin to footer` (not `Added margin` or `fix`).
20
+ - Explain **what** and **why**, not **how**: `Add margin to nav items to prevent them from overlapping the logo`.
21
+ - Never use vague messages like `fix`, `polish`, `wip`, `another try` in the final history — clean them up before merging.
22
+ - Commits should be **atomic**: each commit leaves the code in a runnable state.
23
+ - Prefer multiple small commits split by logical change (e.g. separate docs from feature work).
24
+ - Exception: codemod / CRUD-generator output belongs in its own commit so reviewers can skip it.
25
+ - Multi-line commit messages are preferred over MR-description-only explanations — the info stays in Git and shows up in IDE tools.
26
+
27
+ ## Branches & merging
28
+
29
+ - Trunk-based development — PRs target `main` (minor/patch) or `next` (breaking).
30
+ - Squash-merge is the default. If commit history is messy it **must** be squashed.
31
+ - Feature branches (name prefix `feature/…`) are protected — resolve conflicts by merging main into a new branch and opening a fresh MR; never squash-merge a feature branch.
32
+ - Cherry-picking into production is only allowed for commits already on `main`.
33
+
34
+ ## Review etiquette
35
+
36
+ - Reviewers resolve concerns (except obvious typos). A PR merges only when all concerns are resolved and all reviewers approved.
37
+ - `OPT:` / `Note:` / `Nit:` prefix optional suggestions.
@@ -0,0 +1,59 @@
1
+ ---
2
+ description: CronJob intervals, environments, replicas, resource requests/limits
3
+ applyTo: "**/*.yaml,**/*.yml,**/helm/**,**/k8s/**"
4
+ paths:
5
+ - "**/*.{yaml,yml}"
6
+ - "**/helm/**"
7
+ - "**/k8s/**"
8
+ globs:
9
+ - "**/*.{yaml,yml}"
10
+ - "**/helm/**"
11
+ - "**/k8s/**"
12
+ alwaysApply: false
13
+ ---
14
+
15
+ # Kubernetes Rules
16
+
17
+ ## CronJobs
18
+
19
+ - **Minimum interval: 10 minutes.** Shorter crons are not worth it — cold-start overhead dwarfs the resource savings.
20
+ - For anything more frequent, deploy a long-running process with reduced resources instead.
21
+
22
+ ## Logging
23
+
24
+ - Logging has real cost in k8s. Default to warnings/errors; make debug/info/trace toggleable via env var or flag. See also [api-nestjs.instructions.md](api-nestjs.instructions.md#logging).
25
+
26
+ ## Environments
27
+
28
+ | Env | Deploy | Lifetime | Notes |
29
+ | --------- | -------------------------------------- | ------------------------------------------- | --------------------------------------------------------------------------- |
30
+ | `dev` | Auto from `main`/`master` | Deleted after 12 h of no deploy (data kept) | Integration canary — if pipeline is red, **nothing** merges except the fix. |
31
+ | `test` | Manual push, no review required | Deleted after 7 d of no deploy (data kept) | Internal demos / WIP features. |
32
+ | `staging` | Only `main`/`master` may be reset here | Permanent | Customer acceptance; basis for prod. |
33
+ | `prod` | Manual deploy from `staging` | Permanent | Only cherry-pick commits already on `main`. |
34
+
35
+ ## Replicas
36
+
37
+ - **Non-prod**: 1 replica — optimize for cost; brief interruptions are acceptable.
38
+ - **Prod**: ≥2 replicas — must survive cluster-autoscaler and node upgrades.
39
+ - Consequence: every microservice must be **stateless** so multiple replicas can run concurrently.
40
+
41
+ ## Resources (requests / limits)
42
+
43
+ - Never over-commit memory: `memory.limit == memory.request`.
44
+ - Do **not** set a CPU limit below 2 on Node.js services. Node is single-threaded, but the second core lets GC and k8s overhead run off the main thread.
45
+ - `cpu.request` = CPU at average load. `memory.request` = RAM at average load + safety margin.
46
+
47
+ Example:
48
+
49
+ ```yaml
50
+ resources:
51
+ requests:
52
+ cpu: 50m
53
+ memory: 512Mi
54
+ limits:
55
+ cpu: 2
56
+ memory: 512Mi
57
+ ```
58
+
59
+ - CPU overrun → throttled. Memory overrun → OOM-killed (exit 137). Pods are scheduled based on requests, not limits.
@@ -0,0 +1,34 @@
1
+ ---
2
+ description: Criteria for adding or replacing npm packages
3
+ applyTo: "**/package.json"
4
+ paths:
5
+ - "**/package.json"
6
+ globs:
7
+ - "**/package.json"
8
+ alwaysApply: false
9
+ ---
10
+
11
+ # Libraries & Techniques Rules
12
+
13
+ ## Before adding a dependency
14
+
15
+ - Check if there is already a go-to solution in the repo (e.g. Swiper for sliders, MUI for admin UI, Emotion/styled-components for styling). Use it instead of introducing a parallel library.
16
+ - For "large" decisions (new paradigms like RxJS, new ORM, new state lib), do **not** decide inside a single project — coordinate with the architects first.
17
+ - Small, non-invasive utilities (e.g. `clsx`) can be added without coordination, but the checks below still apply.
18
+
19
+ ## Evaluation checklist for a new npm package
20
+
21
+ Before adding, verify:
22
+
23
+ - **Maintenance**: recent releases, regular commits on default branch, issues getting attention.
24
+ - **Longevity**: how long has it existed, multiple independent maintainers.
25
+ - **Compatibility**: works with our stack (React/Next/Nest/MikroORM/TS versions in use).
26
+ - **Bundle impact** (frontend): check [bundlephobia.com](https://bundlephobia.com/). Prefer tree-shakeable packages.
27
+ - **Vulnerabilities**: check [security.snyk.io](https://security.snyk.io/) for known CVEs.
28
+ - **License**: must be a recognized open-source license compatible with the product.
29
+
30
+ If a package fails any of these, either pick another or flag it explicitly in the PR description with justification.
31
+
32
+ ## Duplication risk
33
+
34
+ Do not introduce a second library that overlaps with an existing one (e.g. a different date-picker when one already exists). Consolidate instead.
@@ -0,0 +1,39 @@
1
+ ---
2
+ description: File, folder, DB, and branch naming conventions across api/admin/site
3
+ applyTo: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.sql"
4
+ paths:
5
+ - "**/*.{ts,tsx,js,jsx}"
6
+ - "**/*.sql"
7
+ globs:
8
+ - "**/*.{ts,tsx,js,jsx}"
9
+ - "**/*.sql"
10
+ alwaysApply: false
11
+ ---
12
+
13
+ # Naming Conventions
14
+
15
+ ## Files and folders
16
+
17
+ | Layer | Folder case | File case |
18
+ | --------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
19
+ | **API** (NestJS) | `kebab-case` (e.g. `page-tree/`) | `kebab-case` with dot segments (e.g. `page-tree.service.ts`, `page-tree.module.ts`) |
20
+ | **Admin** (React/MUI) | `camelCase` (e.g. `pageTree/`) | `PascalCase.tsx` for components (`DashboardPage.tsx`); `camelCase.ts` for hooks/utils (`useUser.ts`) |
21
+ | **Site** (Next.js) | `camelCase` (e.g. `contentScope/`) | `PascalCase.tsx` for components; `camelCase.ts` for hooks/utils; **exception**: Next.js route files stay lowercase (`page.tsx`, `layout.tsx`) |
22
+
23
+ ## Database / infra
24
+
25
+ - Database name: `db_<project>_<env>` (e.g. `db_myproject_dev`).
26
+ - DB user: `<project>_<env>` (e.g. `myproject_dev`).
27
+ - Entity names: singular, PascalCase (e.g. `Product`, not `Products` or `product`).
28
+ - Kubernetes namespaces / releases: `<project>-<env>` (e.g. `myproject-prod`).
29
+
30
+ ## Git
31
+
32
+ - Standard long-lived branches: `main`, `staging`, optionally `test`.
33
+ - Feature branches: must start with `feature/` to receive GitLab branch protection.
34
+
35
+ ## Consistency with other rules
36
+
37
+ - TypeScript-specific naming (enums, types) → [typescript.instructions.md](typescript.instructions.md).
38
+ - React component/prop/state naming → [react.instructions.md](react.instructions.md).
39
+ - Boolean, affirmative, no-abbreviation rules → [general.instructions.md](general.instructions.md).
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: UUID IDs, column types, forward-only migrations, DB defaults
3
+ applyTo: "**/*.entity.ts,**/entities/**/*.ts,**/migrations/**/*.ts,**/*.sql"
4
+ paths:
5
+ - "**/*.entity.ts"
6
+ - "**/entities/**/*.ts"
7
+ - "**/migrations/**/*.ts"
8
+ - "**/*.sql"
9
+ globs:
10
+ - "**/*.entity.ts"
11
+ - "**/entities/**/*.ts"
12
+ - "**/migrations/**/*.ts"
13
+ - "**/*.sql"
14
+ alwaysApply: false
15
+ ---
16
+
17
+ # PostgreSQL Rules
18
+
19
+ ## IDs
20
+
21
+ - Use **UUIDs** for primary keys, not auto-incrementing integers.
22
+ - Sequential IDs leak counts and invite enumeration attacks (`/users/1` → `/users/2`).
23
+ - UUIDs can be generated on the client before insert (used by page-tree documents).
24
+ - UUIDs let data migrate between environments without ID collisions.
25
+
26
+ ## Column types
27
+
28
+ See [api-nestjs.instructions.md](api-nestjs.instructions.md#entity-column-types) for the full list used with MikroORM:
29
+
30
+ - Strings → `columnType: "text"` (never `varchar(n)`).
31
+ - JSON → `jsonb`, not `json`.
32
+ - Timestamps → `columnType: "timestamp with time zone"`.
33
+
34
+ ## Migrations
35
+
36
+ - Forward-only. Do not implement `down` migrations — `throw new Error("Unsupported")` is the standard. Problems get fixed by the next deploy, not rolled back.
37
+
38
+ ## DB defaults
39
+
40
+ - Avoid DB-level defaults on columns exposed via the entity — they break the entity's TS types and aren't available before insert. Use TS-level defaults instead. Exception: upsert pattern, see [api-nestjs.instructions.md](api-nestjs.instructions.md#db-defaults).
@@ -0,0 +1,102 @@
1
+ ---
2
+ description: React component, prop, state, fragment, and anti-pattern rules
3
+ applyTo: "**/*.ts,**/*.tsx"
4
+ paths:
5
+ - "**/*.{ts,tsx}"
6
+ globs:
7
+ - "**/*.{ts,tsx}"
8
+ alwaysApply: false
9
+ ---
10
+
11
+ # React Rules
12
+
13
+ ## General
14
+
15
+ - Function components only — no class components.
16
+ - Always write JSX. `React.createElement` is only for app initialization.
17
+ - Children are typed via `PropsWithChildren`, not an explicit `children: ReactNode` field.
18
+ - Inject services / API clients via **Context**, not module-level singletons.
19
+ - Folder structure: group by **feature/module**, not by type. Move things until it feels right; avoid top-level `components/`, `hooks/`, `utils/` dumping grounds.
20
+ - One "logical component" per file. Multiple sub-components in the same file are fine for structure/styling when they support the main export.
21
+
22
+ ## Naming
23
+
24
+ - Components: **PascalCase**. Instances: **camelCase**. Import name must match the component name.
25
+ - File name must match the component name (`Footer.tsx` exports `Footer`). Exception: a file exporting multiple components.
26
+ - Prefer **meaningful file names** even inside a descriptive folder: `clients/ClientsTable.tsx`, not `clients/Table.tsx`.
27
+ - Private sibling files use the documented suffixes: `ClientsTable.sc.ts` (styled components), `ClientsTable.gql.ts` (GraphQL). **Never import `.sc.ts` / `.gql.ts` from another component.**
28
+
29
+ ## Props
30
+
31
+ - Props are **camelCase**.
32
+ - Do not reuse DOM-attribute names (`className`, `hidden`, …) as custom-semantic props — pick a non-conflicting name (e.g. `variant`).
33
+ - Boolean props are optional (`hidden?: boolean`) with no default — they're falsy by default.
34
+ - When setting a boolean prop to `true`, omit the value: `<Foo hidden />`, not `<Foo hidden={true} />`.
35
+
36
+ ## State
37
+
38
+ - `useState` pairs are `[value, setValue]` in camelCase: `const [userName, setUserName] = useState()`.
39
+
40
+ ## Performance pitfalls
41
+
42
+ - **Never** define components, styled components, or stable helper functions _inside_ another component — they're re-created on every render. Hoist them to module scope.
43
+
44
+ ```tsx
45
+ // Bad
46
+ const Foo = () => {
47
+ const Wrapper = styled.div`…`; // recreated every render
48
+ const sortJobs = (a, b) => …; // ditto
49
+ return <Wrapper>…</Wrapper>;
50
+ };
51
+
52
+ // Good
53
+ const Wrapper = styled.div`…`;
54
+ const sortJobs = (a, b) => …;
55
+ const Foo = () => <Wrapper>…</Wrapper>;
56
+ ```
57
+
58
+ - Never use the array `index` as a React `key`. Use a stable id from the item (`todo.id`).
59
+
60
+ ## Conditional rendering
61
+
62
+ - Do **not** use `cond && <X />` when `cond` is a number — React renders `0`. Compare explicitly (`arr.length > 0 && …`) or use a ternary (`arr.length ? <X /> : null`).
63
+
64
+ ## SVGs
65
+
66
+ - Use `<svg><use href="/icon.svg#id" /></svg>` over importing SVGs as components. See [styling.instructions.md](styling.instructions.md#svgs).
67
+
68
+ ## GraphQL — colocate fragments
69
+
70
+ A component that consumes GraphQL data must define its own fragment and be typed by that fragment. The parent query spreads the fragment. This way the child isn't coupled to the parent's query shape.
71
+
72
+ ```tsx
73
+ // DisplayName.tsx
74
+ export const displayNameFragment = gql`
75
+ fragment DisplayName on User {
76
+ firstName
77
+ lastName
78
+ }
79
+ `;
80
+
81
+ function DisplayName({ user }: { user: GQLDisplayNameFragment }) {
82
+ return (
83
+ <>
84
+ {user.firstName} {user.lastName}
85
+ </>
86
+ );
87
+ }
88
+
89
+ // UserDetail.tsx
90
+ const userDetailQuery = gql`
91
+ query UserDetail($id: ID!) {
92
+ user(id: $id) {
93
+ ...DisplayName
94
+ }
95
+ }
96
+ ${displayNameFragment}
97
+ `;
98
+ ```
99
+
100
+ ## General style
101
+
102
+ - Follow the official [React docs](https://react.dev/) for everything not covered here.
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: Security-by-design, privacy, authorization, defense-in-depth principles
3
+ applyTo: "**"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Secure Software Development Rules
8
+
9
+ Apply these when designing features, reviewing diffs, or writing validation/auth code. They are guidelines, not absolutes — reason about them explicitly rather than skipping them.
10
+
11
+ ## Security by design
12
+
13
+ - Validate input as precisely as possible. Prefer `IsUrl`, `IsEmail`, `IsUUID`, etc. over `IsString`. Narrow validators limit the blast radius of downstream bugs (e.g. XSS).
14
+ - Canonicalize before comparing: lowercase emails, normalize URL trailing slashes / default ports, etc. — prevents duplicate accounts and Allow/Deny list bypasses.
15
+ - Generate random values only via crypto-secure APIs (`node:crypto`). Never use `Math.random` for tokens, IDs, secrets, or nonces.
16
+
17
+ ## Privacy by design
18
+
19
+ - Only persist data that is actually needed. Plan deletion alongside creation (e.g. auto-delete contact requests after retention period).
20
+ - Default settings should be the privacy-friendly option.
21
+ - Avoid leaking account existence in flows like "forgot password": respond the same way whether the email is registered or not.
22
+
23
+ ## Authorization
24
+
25
+ - **Least privilege**: users and services start with zero rights; grant only what is necessary. Never build an "allow everything then deny" model.
26
+ - **Complete mediation**: check authorization on every access, not once per session.
27
+ - **Fail-secure**: deny by default. If a rule does not explicitly grant access, access is denied. Use DB transactions to avoid partial writes on failure.
28
+ - ACL logic belongs in a dedicated ACL service or inline in the controller/resolver — never in shared services (which also run from console jobs without an authenticated user). See [api-nestjs.instructions.md](api-nestjs.instructions.md).
29
+
30
+ ## Defense in depth
31
+
32
+ - Combine mechanisms (e.g. IP allow-list **and** auth **and** rate limiting). One layer is not enough.
33
+
34
+ ## Keep it simple
35
+
36
+ - Security relies on understandability and testability. Simpler designs are more secure designs. Resist clever schemes.
37
+
38
+ ## Don't roll your own crypto / auth
39
+
40
+ - Security-sensitive primitives (hashing, signing, auth flows, session handling) must use vetted libraries or Comet's built-in tools. No obscurity-based schemes.
41
+
42
+ ## Admin / public separation
43
+
44
+ - Administrative interfaces must be separated from public ones. Site-to-API calls without user auth go through the BFF, not directly to the API.
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: Theme usage, Emotion/styled-components, responsive, SVG handling
3
+ applyTo: "**/*.tsx,**/*.sc.ts,**/*.css,**/*.scss"
4
+ paths:
5
+ - "**/*.tsx"
6
+ - "**/*.sc.ts"
7
+ - "**/*.{css,scss}"
8
+ globs:
9
+ - "**/*.tsx"
10
+ - "**/*.sc.ts"
11
+ - "**/*.{css,scss}"
12
+ alwaysApply: false
13
+ ---
14
+
15
+ # Styling / CSS Rules
16
+
17
+ ## Theme
18
+
19
+ - Styling decisions go through the theme (colors, typography, buttons, spacing, breakpoints, easings). Do **not** hard-code values in components when the theme already defines them.
20
+ - Colors: use basic tokens (`primary`, `grey`, …) when the use is generic; define context-specific tokens (`colorUiLabel`, `colorUiLabelHover`) only when a name has real semantic meaning. Don't invent context tokens that are used once.
21
+ - Buttons / form elements: define granular tokens (`primaryBg`, `primaryBgHover`, `primaryBorder`, `primaryHeightDesktop`, …) so the theme is reusable across apps.
22
+ - Typography: define as CSS-in-JS helpers returning `css\`…\``blocks, including media-query overrides and an optional`disableMargin` parameter.
23
+ - Spacing: split into **dynamic** (responsive scale keyed by breakpoint) and **static** (single value) tokens.
24
+
25
+ ## Where styles live
26
+
27
+ - **No inline `style={{ … }}`.** Use Emotion / styled-components. Name the styled component after its semantic role (`DeleteButton`, not `StyledIconButton`).
28
+ - Keep list-level layout (flex/grid/wrap) on the list container, not on item blocks. When the item needs sizing, wrap it in an `Item` inside the list rather than styling the block itself.
29
+ - When a component gets complex, extract styles to a `*.sc.ts` sibling file (and GraphQL to `*.gql.ts`). Those files are **private** to the component — do not import them elsewhere.
30
+
31
+ ## CSS layout
32
+
33
+ - Use CSS Grid and Flexbox for alignment — but only when layout actually requires them. Do not blanket `display: flex` every `div`.
34
+
35
+ ## Browser support
36
+
37
+ - Verify features via [caniuse.com](https://caniuse.com) against **All Users / Europe**.
38
+ - **Site / frontend**: ≥93% usage → free to use. 90–93% → only if basic functionality still works without the feature; minor visual/behavioral degradation is acceptable. Below that → check with a stylist.
39
+ - **Admin**: anything supported by current Chrome, Firefox, Safari is fair game.
40
+
41
+ ## Responsive
42
+
43
+ - Mobile-first. Write the mobile layout first, then add breakpoint overrides upward.
44
+ - For readability, put a blank line before every nested selector / media query inside a styled block.
45
+
46
+ ## SVGs
47
+
48
+ - Prefer `<svg><use href="/icon.svg#id" /></svg>` — keeps SVGs out of the JS bundle and still allows `currentColor` theming.
49
+ - Do **not** import SVGs as React components (`import Icon from "./icon.svg"` → `<Icon />`) for production icons — they inflate the bundle.
50
+ - Do **not** use `<img src="icon.svg">` when the icon needs to be styled (e.g. color changes), since `<img>` cannot be manipulated.