@comet/agent-features 9.0.0-beta.5
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.
- package/LICENSE +24 -0
- package/package.json +19 -0
- package/rules/coding-guidelines/api-nestjs.instructions.md +107 -0
- package/rules/coding-guidelines/cdn.instructions.md +24 -0
- package/rules/coding-guidelines/general.instructions.md +30 -0
- package/rules/coding-guidelines/git.instructions.md +37 -0
- package/rules/coding-guidelines/kubernetes.instructions.md +59 -0
- package/rules/coding-guidelines/libraries.instructions.md +34 -0
- package/rules/coding-guidelines/naming.instructions.md +39 -0
- package/rules/coding-guidelines/postgresql.instructions.md +40 -0
- package/rules/coding-guidelines/react.instructions.md +102 -0
- package/rules/coding-guidelines/security.instructions.md +44 -0
- package/rules/coding-guidelines/styling.instructions.md +50 -0
- package/rules/coding-guidelines/typescript.instructions.md +50 -0
- package/skills/.gitkeep +0 -0
- package/skills/comet-block/SKILL.md +246 -0
- package/skills/comet-block/references/admin-patterns.md +192 -0
- package/skills/comet-block/references/api-patterns.md +183 -0
- package/skills/comet-block/references/block-loader.md +368 -0
- package/skills/comet-block/references/block-types.md +210 -0
- package/skills/comet-block/references/custom-block-field.md +266 -0
- package/skills/comet-block/references/fixtures.md +436 -0
- package/skills/comet-block/references/image.md +341 -0
- package/skills/comet-block/references/migration.md +597 -0
- package/skills/comet-block/references/registration.md +167 -0
- package/skills/comet-block/references/response-summary.md +102 -0
- package/skills/comet-block/references/rich-text.md +309 -0
- package/skills/comet-block/references/select.md +176 -0
- package/skills/comet-block/references/site-patterns.md +202 -0
- package/skills/comet-mail-react/SKILL.md +541 -0
- package/skills/comet-mail-react/references/components-and-theme.md +441 -0
- package/skills/comet-mail-react/references/layout-patterns.md +315 -0
- package/skills/comet-mail-react/references/styling-and-customization.md +306 -0
- package/skills/comet-minor-update/SKILL.md +191 -0
- 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-beta.5",
|
|
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.
|