@nitra/cursor 12.8.6 → 12.8.7
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/rules/adr/js/hooks.mdc +32 -0
- package/rules/adr/js/madr_format.mdc +96 -0
- package/rules/adr/js/settings_policy.mdc +34 -0
- package/rules/adr/main.mdc +13 -95
- package/rules/bun/js/bunfig.mdc +12 -0
- package/rules/bun/js/layout.mdc +60 -0
- package/rules/bun/js/lint.mdc +9 -0
- package/rules/bun/js/package_json.mdc +19 -0
- package/rules/bun/main.mdc +9 -61
- package/rules/capacitor/js/ios_spm.mdc +69 -0
- package/rules/capacitor/js/version.mdc +29 -0
- package/rules/capacitor/main.mdc +8 -22
- package/rules/changelog/js/agent-workflow.mdc +15 -0
- package/rules/changelog/js/changelog-format.mdc +33 -0
- package/rules/changelog/js/comparison-models.mdc +40 -0
- package/rules/changelog/main.mdc +4 -98
- package/rules/ci4/js/marksman_config.mdc +31 -0
- package/rules/ci4/js/vscode_extensions.mdc +33 -0
- package/rules/ci4/main.mdc +14 -14
- package/rules/docker/js/compile.mdc +44 -0
- package/rules/docker/js/hadolint.mdc +50 -0
- package/rules/docker/js/mirror.mdc +13 -0
- package/rules/docker/js/multistage.mdc +13 -0
- package/rules/docker/js/native-addon.mdc +43 -0
- package/rules/docker/js/nginx-tag.mdc +7 -0
- package/rules/docker/js/nginx-user.mdc +37 -0
- package/rules/docker/js/non-root.mdc +39 -0
- package/rules/docker/main.mdc +15 -196
- package/rules/ga/js/lint_toolchain.mdc +15 -0
- package/rules/ga/js/required_workflows.mdc +35 -0
- package/rules/ga/js/vscode.mdc +17 -0
- package/rules/ga/js/workflow_common.mdc +108 -0
- package/rules/ga/js/workflows.mdc +32 -0
- package/rules/ga/js/zizmor.mdc +7 -0
- package/rules/ga/main.mdc +17 -125
- package/rules/graphql/js/tooling.mdc +13 -0
- package/rules/graphql/js/vscode_extensions.mdc +13 -0
- package/rules/graphql/main.mdc +3 -22
- package/rules/hasura/js/internal_urls.mdc +27 -0
- package/rules/hasura/js/migrations.mdc +13 -0
- package/rules/hasura/js/svc_hl.mdc +17 -0
- package/rules/hasura/main.mdc +8 -30
- package/rules/image-avif/js/avif_generation.mdc +26 -0
- package/rules/image-avif/js/package_json_optout.mdc +21 -0
- package/rules/image-avif/main.mdc +7 -34
- package/rules/image-compress/js/package_json.mdc +7 -0
- package/rules/image-compress/js/package_setup.mdc +13 -0
- package/rules/image-compress/main.mdc +4 -12
- package/rules/js/docs/index.md +3 -3
- package/rules/js/js/dep-policy.mdc +17 -0
- package/rules/js/js/eslint-config.mdc +28 -0
- package/rules/js/js/extensions.mdc +8 -0
- package/rules/js/js/file-extensions.mdc +12 -0
- package/rules/js/js/for-in.mdc +26 -0
- package/rules/js/js/jscpd.mdc +42 -0
- package/rules/js/js/knip.mdc +15 -0
- package/rules/js/js/lint-js-workflow.mdc +58 -0
- package/rules/js/js/oxlintrc.mdc +20 -0
- package/rules/js/js/package-json.mdc +31 -0
- package/rules/js/js/tests.mdc +9 -0
- package/rules/js/js/utils-lib-structure.mdc +15 -0
- package/rules/js/main.mdc +21 -214
- package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
- package/rules/js-bun-db/js/connection.mdc +42 -0
- package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
- package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
- package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
- package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
- package/rules/js-bun-db/js/query-safety.mdc +117 -0
- package/rules/js-bun-db/js/sql-array.mdc +88 -0
- package/rules/js-bun-db/js/unsafe.mdc +65 -0
- package/rules/js-bun-db/main.mdc +15 -605
- package/rules/js-bun-redis/js/imports.mdc +47 -0
- package/rules/js-bun-redis/js/package_json.mdc +44 -0
- package/rules/js-bun-redis/main.mdc +3 -11
- package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
- package/rules/js-mssql/js/mssql-pool.mdc +56 -0
- package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
- package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
- package/rules/js-mssql/js/mssql-version.mdc +7 -0
- package/rules/js-mssql/main.mdc +10 -198
- package/rules/js-run/js/check-env.mdc +35 -0
- package/rules/js-run/js/conn-aliases.mdc +109 -0
- package/rules/js-run/js/jsconfig.mdc +20 -0
- package/rules/js-run/js/otel-configmap.mdc +6 -0
- package/rules/js-run/js/pino.mdc +6 -0
- package/rules/js-run/js/project-structure.mdc +11 -0
- package/rules/js-run/js/runtime.mdc +14 -0
- package/rules/js-run/js/scope.mdc +11 -0
- package/rules/js-run/js/settimeout.mdc +11 -0
- package/rules/js-run/js/temporal.mdc +5 -0
- package/rules/js-run/main.mdc +16 -218
- package/rules/k8s/js/configmap.mdc +41 -0
- package/rules/k8s/js/deployment_resources.mdc +49 -0
- package/rules/k8s/js/hasura_httproute.mdc +91 -0
- package/rules/k8s/js/hpa_apiversion.mdc +27 -0
- package/rules/k8s/js/ingress_gateway.mdc +16 -0
- package/rules/k8s/js/kustomize_structure.mdc +144 -0
- package/rules/k8s/js/lint_k8s.mdc +72 -0
- package/rules/k8s/js/multidoc_yaml.mdc +5 -0
- package/rules/k8s/js/network_policy.mdc +136 -0
- package/rules/k8s/js/schema_modeline.mdc +57 -0
- package/rules/k8s/js/service.mdc +44 -0
- package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
- package/rules/k8s/main.mdc +30 -843
- package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
- package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
- package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
- package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
- package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
- package/rules/nginx-default-tpl/main.mdc +6 -112
- package/rules/npm-module/js/docs/index.md +5 -5
- package/rules/npm-module/js/docs/rule_meta.md +6 -6
- package/rules/npm-module/js/docs/skill_meta.md +8 -8
- package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/js/package_structure.mdc +62 -0
- package/rules/npm-module/js/rule_meta.mdc +11 -0
- package/rules/npm-module/js/skill_meta.mdc +11 -0
- package/rules/npm-module/main.mdc +10 -55
- package/rules/php/js/lint_php_yml.mdc +12 -0
- package/rules/php/js/tooling.mdc +66 -0
- package/rules/php/main.mdc +7 -66
- package/rules/python/js/lint_python_yml.mdc +23 -0
- package/rules/python/js/pyproject_toml.mdc +32 -0
- package/rules/python/js/tooling.mdc +23 -0
- package/rules/python/main.mdc +9 -33
- package/rules/rego/js/rego-lint.mdc +31 -0
- package/rules/rego/js/vscode_extensions.mdc +11 -0
- package/rules/rego/js/vscode_settings.mdc +13 -0
- package/rules/rego/main.mdc +8 -24
- package/rules/rust/js/coverage.mdc +28 -0
- package/rules/rust/js/lint.mdc +22 -0
- package/rules/rust/js/tauri_composition.mdc +8 -0
- package/rules/rust/js/vscode_extensions.mdc +12 -0
- package/rules/rust/main.mdc +8 -38
- package/rules/security/js/rego_policies.mdc +15 -0
- package/rules/security/js/sample_secret.mdc +19 -0
- package/rules/security/js/trufflehog.mdc +21 -0
- package/rules/security/main.mdc +7 -35
- package/rules/style/js/admin-table.mdc +88 -0
- package/rules/style/js/colors.mdc +21 -0
- package/rules/style/js/gap.mdc +22 -0
- package/rules/style/js/quasar-fixes.mdc +32 -0
- package/rules/style/js/quasar.mdc +7 -0
- package/rules/style/js/tooling.mdc +85 -0
- package/rules/style/main.mdc +13 -253
- package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
- package/rules/tauri/js/tool_surface.mdc +21 -0
- package/rules/tauri/js/tooling.mdc +25 -0
- package/rules/tauri/main.mdc +8 -78
- package/rules/test/js/cargo_mutants_config.mdc +18 -0
- package/rules/test/js/docs/index.md +7 -7
- package/rules/test/js/location.mdc +52 -0
- package/rules/test/js/no-console-store-restore.mdc +11 -0
- package/rules/test/js/no-process-chdir.mdc +15 -0
- package/rules/test/js/no-relative-fs-path.mdc +22 -0
- package/rules/test/js/sandbox-aware-test.mdc +28 -0
- package/rules/test/js/stryker_config.mdc +26 -0
- package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
- package/rules/test/main.mdc +18 -184
- package/rules/text/js/ci-lint-text.mdc +15 -0
- package/rules/text/js/cspell.mdc +81 -0
- package/rules/text/js/dotenv-linter.mdc +16 -0
- package/rules/text/js/forbidden-prettier.mdc +13 -0
- package/rules/text/js/markdownlint.mdc +25 -0
- package/rules/text/js/oxfmt.mdc +35 -0
- package/rules/text/js/package-json.mdc +26 -0
- package/rules/text/js/shellcheck.mdc +18 -0
- package/rules/text/js/v8r.mdc +23 -0
- package/rules/text/js/vscode.mdc +86 -0
- package/rules/text/main.mdc +20 -237
- package/rules/vue/js/composition-api.mdc +82 -0
- package/rules/vue/js/nheader-layout.mdc +171 -0
- package/rules/vue/js/node-imports.mdc +25 -0
- package/rules/vue/js/quasar-ui.mdc +32 -0
- package/rules/vue/js/structure.mdc +101 -0
- package/rules/vue/js/testing.mdc +32 -0
- package/rules/vue/js/tfm-translations.mdc +26 -0
- package/rules/vue/js/vite-config.mdc +126 -0
- package/rules/vue/js/vite-env.mdc +55 -0
- package/rules/vue/js/vue-imports.mdc +25 -0
- package/rules/vue/main.mdc +16 -640
- package/scripts/docs/index.md +16 -16
- package/scripts/lib/docs/index.md +36 -36
- package/scripts/utils/docs/index.md +14 -14
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
## Внутрішні аліаси для підключень до БД і GraphQL
|
|
2
|
+
|
|
3
|
+
Якщо в проекті є підключення до баз даних, зовнішніх graphql на кшталт:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { SQL } from 'bun'
|
|
7
|
+
|
|
8
|
+
// або
|
|
9
|
+
|
|
10
|
+
import sql from 'mssql'
|
|
11
|
+
|
|
12
|
+
// або
|
|
13
|
+
|
|
14
|
+
import { GraphQLClient } from '@nitra/graphql-request'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
то ці підключення повинні бути винесені в окремий файл, наприклад `/src/conn/pg.mjs`, в package.json повинні бути додано аліас:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"imports": {
|
|
22
|
+
"#conn/*": "./src/conn/*"
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
так виглядатиме підключення до PostgreSQL в коді:
|
|
29
|
+
|
|
30
|
+
```javascript title="Приклад підключення до PostgreSQL в /src/conn/pg.mjs"
|
|
31
|
+
import { checkEnv, env } from '@nitra/check-env'
|
|
32
|
+
import { SQL } from 'bun'
|
|
33
|
+
|
|
34
|
+
checkEnv(['PG_CONN'])
|
|
35
|
+
|
|
36
|
+
export const db = new SQL({ url: env.PG_CONN })
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
а так до GraphQL:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
import { checkEnv, env } from '@nitra/check-env'
|
|
44
|
+
import { GraphQLClient } from '@nitra/graphql-request'
|
|
45
|
+
|
|
46
|
+
checkEnv(['QL', 'X_HASURA_ADMIN_SECRET'])
|
|
47
|
+
|
|
48
|
+
export { gql } from '@nitra/graphql-request'
|
|
49
|
+
|
|
50
|
+
export const graphQLClientSmart = new GraphQLClient(env.QL, {
|
|
51
|
+
headers: {
|
|
52
|
+
'X-Hasura-Admin-Secret': env.X_HASURA_ADMIN_SECRET
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
а в коді повинно бути використано:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import { pool } from '#conn/pg.mjs'
|
|
61
|
+
|
|
62
|
+
// або
|
|
63
|
+
|
|
64
|
+
import { gql, graphQLClient } from '@nitra/graphql-request'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Нейминг файлів у `src/conn/`
|
|
68
|
+
|
|
69
|
+
Назва файла в `src/conn/` має одразу повідомляти, **до чого** підключаємось і **в якому режимі**:
|
|
70
|
+
|
|
71
|
+
- **GraphQL** — префікс `ql-`, далі ідентифікатор endpoint:
|
|
72
|
+
- `src/conn/ql-contract.mjs`
|
|
73
|
+
- `src/conn/ql-smart.mjs`
|
|
74
|
+
- **PostgreSQL** — префікс `pg-`, далі тип підключення (репліка vs мастер): `read` або `write`:
|
|
75
|
+
- `src/conn/pg-read.mjs`
|
|
76
|
+
- `src/conn/pg-write.mjs`
|
|
77
|
+
- **PostgreSQL до кількох БД** — додатково ідентифікатор підключення після типу:
|
|
78
|
+
- `src/conn/pg-read-smart.mjs`
|
|
79
|
+
- `src/conn/pg-write-contract.mjs`
|
|
80
|
+
- **MySQL** — префікс `mysql-` за тією ж схемою (`mysql-read.mjs`, `mysql-write-<id>.mjs` тощо).
|
|
81
|
+
- **MSSQL** — префікс `mssql-` за тією ж схемою (`mssql-read.mjs`, `mssql-write-<id>.mjs` тощо). Хоча npm-пакет один (`mssql`), а драйвер MS SQL Server під капотом T-SQL — у файловій назві відрізняємо MS SQL Server від MySQL, бо це різні СУБД, різні діалекти, різні рантаймні залежності. Якщо проєкт історично використовує `mysql-…` для MSSQL-підключень — він валідний і далі (для backward-compat), але новий код пишемо з префіксом `mssql-`.
|
|
82
|
+
|
|
83
|
+
Підключення до БД **обов'язково** має бути ідентифіковано як `read` (репліка) або `write` (мастер). Якщо з імені змінної оточення (наприклад, `env.PG_CONN`) це не очевидно — визнач режим за операціями в коді: якщо немає операцій зміни даних (`INSERT`/`UPDATE`/`DELETE`/DDL) — це `pg-read.mjs`, інакше `pg-write.mjs`.
|
|
84
|
+
|
|
85
|
+
### Експорти у файлах `src/conn/`
|
|
86
|
+
|
|
87
|
+
У файлах підключень **заборонений** `export default`. Експорт має бути **іменований** і збігатися з назвою файла в camelCase.
|
|
88
|
+
|
|
89
|
+
Приклад — `src/conn/ql-smart.mjs`:
|
|
90
|
+
|
|
91
|
+
```javascript title="❌ Так не можна"
|
|
92
|
+
export default new GraphQLClient(env.SMART_QL, {
|
|
93
|
+
headers: {
|
|
94
|
+
'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```javascript title="✅ Канон: іменований експорт за іменем файла"
|
|
100
|
+
export const qlSmart = new GraphQLClient(env.SMART_QL, {
|
|
101
|
+
headers: {
|
|
102
|
+
'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Відповідно: `pg-read.mjs` → `export const pgRead = …`, `pg-write-contract.mjs` → `export const pgWriteContract = …`, `ql-contract.mjs` → `export const qlContract = …`.
|
|
108
|
+
|
|
109
|
+
Файли `index.*` у conn-каталозі пропускаються як можливий reexport-барель.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## `jsconfig.json` (редактор / перевірка типів)
|
|
2
|
+
|
|
3
|
+
Якщо в **backend** workspace-пакеті (без `vite` у `devDependencies`) є каталог **`src/`**, у **корені цього пакета** має бути **`jsconfig.json`**. Якщо файлу ще немає — створи його з таким вмістом (канон js-run):
|
|
4
|
+
|
|
5
|
+
```json title="jsconfig.json"
|
|
6
|
+
{
|
|
7
|
+
"compilerOptions": {
|
|
8
|
+
"lib": ["esnext"],
|
|
9
|
+
"module": "NodeNext",
|
|
10
|
+
"moduleResolution": "NodeNext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"checkJs": false
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Канон: [jsconfig.json.snippet.json](./policy/jsconfig/template/jsconfig.json.snippet.json)
|
|
19
|
+
|
|
20
|
+
Якщо пакет не слідує структурі з `src/` (наприклад, лише `scripts/` у корені) — ця вимога не застосовується; для типових сервісів із `src/` файл обов'язковий і має збігатися з каноном.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## OTEL ConfigMap (k8s)
|
|
2
|
+
|
|
3
|
+
В **/k8s/base/configmap.yaml** повинен бути заданий `OTEL_RESOURCE_ATTRIBUTES: 'service.name=<project_name>,service.namespace=<project_namespace>'`
|
|
4
|
+
а в директоріях з kustomize повинні бути перевизначені значення `OTEL_RESOURCE_ATTRIBUTES` і в них `service.namespace` повинен відповідати namespace, в якому знаходиться дана директорія.
|
|
5
|
+
|
|
6
|
+
Канон обовʼязкових substring у `data.OTEL_RESOURCE_ATTRIBUTES` (`service.name=`, `service.namespace=`): [configmap.yaml.contains.yml](./policy/configmap/template/configmap.yaml.contains.yml)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## Використання @nitra/pino для логування
|
|
2
|
+
|
|
3
|
+
Проект використовує @nitra/pino для логування.
|
|
4
|
+
Якщо в проекті присутній @nitra/bunyan, то він повинен бути замінений на @nitra/pino — як у `package.json`, так і в коді: усі `import` / `require` / динамічні `import()` з `@nitra/bunyan` (і застарілого `bunyan`) треба замінити на `@nitra/pino` і за потреби адаптувати виклики під його API.
|
|
5
|
+
|
|
6
|
+
Канон заборонених `dependencies` / `devDependencies` (`bunyan`, `@nitra/bunyan`): [package.json.deny.json](./policy/package_json/template/package.json.deny.json)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Структура проекту
|
|
2
|
+
|
|
3
|
+
Рекомендується використовувати таку структуру проекту:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
k8s/ # тут всі файли для деплойменту в Kubernetes, включаючи kustomize
|
|
7
|
+
src/ # тут всі файли необхідні для роботи проекту
|
|
8
|
+
Dockerfile
|
|
9
|
+
package.json
|
|
10
|
+
readme.md
|
|
11
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Runtime у `package.json#scripts`
|
|
2
|
+
|
|
3
|
+
У **backend**-пакетах (без `vite` у `devDependencies`) код запускають через **Bun**, не через бінарник **`node`** у значеннях `scripts`:
|
|
4
|
+
|
|
5
|
+
- `"start": "node src/index.js"` → `"start": "bun src/index.js"` (або `bun run …`, якщо так прийнято в репо);
|
|
6
|
+
- `node --watch app.js` → `bun --watch app.js`;
|
|
7
|
+
- `NODE_OPTIONS=… node app.js` → `NODE_OPTIONS=… bun app.js`.
|
|
8
|
+
- `env $(cat .env .env.local) bun src/index.js` → `bun --env-file=.env --env-file=.env.local src/index.js` (нативне завантаження env у Bun, без `env`/`cat`).
|
|
9
|
+
|
|
10
|
+
Заборонено викликати **`node`** у ланцюжках (`&&`, `;`, `|`). Заборонено обгортку **`env $(cat …) bun`** — файли з `cat` перелічуй у **`--env-file=`** (по одному прапорцю на файл, порядок як у `cat`). Допустимо: `bun`, `bunx`, `npx` (див. **bun.mdc**), інші CLI, якщо вони не підміняють рантайм на `node`.
|
|
11
|
+
|
|
12
|
+
Це **не** стосується поля `engines.node` (мінімальна версія Node для сумісності інструментів) і **не** стосується frontend-пакетів з `vite` у `devDependencies`.
|
|
13
|
+
|
|
14
|
+
Канон заборонених патернів у `scripts`: [package.json.deny.json](./policy/package_json/template/package.json.deny.json) (`scriptsForbidden`).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Область застосування
|
|
2
|
+
|
|
3
|
+
Правило стосується **виключно backend Node.js workspace-пакетів** (jobs, GraphQL/HTTP-сервери, CLI). **Не застосовується** до frontend-пакетів, які бандляться в браузер: маркер — наявність `vite` у `devDependencies` пакета (`site/`, мобільні Capacitor-пакети, будь-яка Vue/Quasar SPA).
|
|
4
|
+
|
|
5
|
+
У браузерному середовищі:
|
|
6
|
+
|
|
7
|
+
- немає `node:process` — імпорт `import { env } from 'node:process'` resolve'иться у `undefined`, і `env.X` падає з `TypeError: Cannot read properties of undefined`;
|
|
8
|
+
- `process.env.X` у джерелах пакета відсутнє в рантаймі — Vite або взагалі не підставляє його, або підставляє лише `process.env.NODE_ENV`;
|
|
9
|
+
- усі змінні оточення для frontend задаються через `VITE_*` і доступні як `import.meta.env.VITE_X` (типобезпечно через `vite-check-env`); режим — `import.meta.env.MODE` / `import.meta.env.PROD`.
|
|
10
|
+
|
|
11
|
+
Тому **у frontend-пакетах не торкайся `process.env.*`** і **не додавай** `import { env } from 'node:process'`. Якщо натрапив на `process.env.NODE_ENV` у frontend-коді — заміна, якщо взагалі потрібна, лише на `import.meta.env.MODE`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Паузи через setTimeout
|
|
2
|
+
|
|
3
|
+
Заборонено робити паузи через `await new Promise(resolve => setTimeout(resolve, ms))` — таку обгортку треба замінити на promise-варіант `setTimeout` з `node:timers/promises`:
|
|
4
|
+
|
|
5
|
+
```javascript title="Замість new Promise + setTimeout"
|
|
6
|
+
import { setTimeout } from 'node:timers/promises'
|
|
7
|
+
|
|
8
|
+
await setTimeout(500)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Імпорт `setTimeout` з `node:timers/promises` затіняє глобальний таймер у файлі — якщо в тому ж файлі потрібен callback-варіант, імпортуй його під іншим іменем (наприклад, `import { setTimeout as setTimeoutCb } from 'node:timers'`).
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
## Temporal API (заборона у Bun runtime)
|
|
2
|
+
|
|
3
|
+
У backend/Bun runtime-коді **не використовуй `Temporal`** (`Temporal.Now`, `Temporal.Instant`, імпорти з polyfill тощо). Поточний Bun runtime ще не має глобального `Temporal` (`typeof Temporal === "undefined"`), тому агентам треба лишатися на сумісному `Date` API або передавати timestamp у чисті функції через параметр.
|
|
4
|
+
|
|
5
|
+
Перевірка `npx @nitra/cursor fix js-run` сканує JS/TS AST і падає на identifier `Temporal` у backend workspace-коді.
|
package/rules/js-run/main.mdc
CHANGED
|
@@ -5,234 +5,32 @@ alwaysApply: false
|
|
|
5
5
|
version: '1.12'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Правило охоплює backend Node.js workspace-пакети (jobs, GraphQL/HTTP-сервери, CLI) — визначення меж застосування, вимоги до runtime, структуру проекту, конфігурацію, логування, підключення до БД/GraphQL і безпечне використання env-змінних.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[js-run-scope](./js/scope.mdc)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
[js-run-runtime](./js/runtime.mdc)
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
- `process.env.X` у джерелах пакета відсутнє в рантаймі — Vite або взагалі не підставляє його, або підставляє лише `process.env.NODE_ENV`;
|
|
16
|
-
- усі змінні оточення для frontend задаються через `VITE_*` і доступні як `import.meta.env.VITE_X` (типобезпечно через `vite-check-env`); режим — `import.meta.env.MODE` / `import.meta.env.PROD`.
|
|
14
|
+
[js-run-temporal](./js/temporal.mdc)
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
[js-run-project-structure](./js/project-structure.mdc)
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
[js-run-jsconfig](./js/jsconfig.mdc)
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
[js-run-pino](./js/pino.mdc)
|
|
23
21
|
|
|
24
|
-
-
|
|
25
|
-
- `node --watch app.js` → `bun --watch app.js`;
|
|
26
|
-
- `NODE_OPTIONS=… node app.js` → `NODE_OPTIONS=… bun app.js`.
|
|
27
|
-
- `env $(cat .env .env.local) bun src/index.js` → `bun --env-file=.env --env-file=.env.local src/index.js` (нативне завантаження env у Bun, без `env`/`cat`).
|
|
22
|
+
[js-run-otel-configmap](./js/otel-configmap.mdc)
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
[js-run-conn-aliases](./js/conn-aliases.mdc)
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
[js-run-check-env](./js/check-env.mdc)
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
[js-run-settimeout](./js/settimeout.mdc)
|
|
34
29
|
|
|
35
|
-
|
|
30
|
+
## Швидкий gate через conftest
|
|
36
31
|
|
|
37
|
-
|
|
32
|
+
Rego-пакети, які запускає `npx @nitra/cursor fix js-run` / `npx @nitra/cursor check`:
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Рекомендується використовувати таку структуру проекту:
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
k8s/ # тут всі файли для деплойменту в Kubernetes, включаючи kustomize
|
|
47
|
-
src/ # тут всі файли необхідні для роботи проекту
|
|
48
|
-
Dockerfile
|
|
49
|
-
package.json
|
|
50
|
-
readme.md
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## `jsconfig.json` (редактор / перевірка типів)
|
|
54
|
-
|
|
55
|
-
Якщо в **backend** workspace-пакеті (без `vite` у `devDependencies`) є каталог **`src/`**, у **корені цього пакета** має бути **`jsconfig.json`**. Якщо файлу ще немає — створи його з таким вмістом (канон js-run):
|
|
56
|
-
|
|
57
|
-
```json title="jsconfig.json"
|
|
58
|
-
{
|
|
59
|
-
"compilerOptions": {
|
|
60
|
-
"lib": ["esnext"],
|
|
61
|
-
"module": "NodeNext",
|
|
62
|
-
"moduleResolution": "NodeNext",
|
|
63
|
-
"target": "esnext",
|
|
64
|
-
"checkJs": false
|
|
65
|
-
},
|
|
66
|
-
"include": ["src/**/*"]
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
Канон: [jsconfig.json.snippet.json](./policy/jsconfig/template/jsconfig.json.snippet.json)
|
|
71
|
-
|
|
72
|
-
Якщо пакет не слідує структурі з `src/` (наприклад, лише `scripts/` у корені) — ця вимога не застосовується; для типових сервісів із `src/` файл обов’язковий і має збігатися з каноном.
|
|
73
|
-
|
|
74
|
-
## Використання @nitra/pino
|
|
75
|
-
|
|
76
|
-
Проект використовує @nitra/pino для логування.
|
|
77
|
-
Якщо в проекті присутній @nitra/bunyan, то він повинен бути замінений на @nitra/pino — як у `package.json`, так і в коді: усі `import` / `require` / динамічні `import()` з `@nitra/bunyan` (і застарілого `bunyan`) треба замінити на `@nitra/pino` і за потреби адаптувати виклики під його API. Канон заборонених `dependencies` / `devDependencies` (`bunyan`, `@nitra/bunyan`): [package.json.deny.json](./policy/package_json/template/package.json.deny.json)
|
|
78
|
-
|
|
79
|
-
В **/k8s/base/configmap.yaml повинен бути заданий OTEL_RESOURCE_ATTRIBUTES: 'service.name=<project_name>,service.namespace=<project_namespace>'
|
|
80
|
-
а в директоріях з kustomize повинні бути перевизначені значення OTEL_RESOURCE_ATTRIBUTES і в них service.namespace повинен відповідати namespace, в якому знаходиться дана директорія.
|
|
81
|
-
|
|
82
|
-
Канон обовʼязкових substring у `data.OTEL_RESOURCE_ATTRIBUTES` (`service.name=`, `service.namespace=`): [configmap.yaml.contains.yml](./policy/configmap/template/configmap.yaml.contains.yml)
|
|
83
|
-
|
|
84
|
-
## Внутрішні аліаси
|
|
85
|
-
|
|
86
|
-
Якщо в проекті є підключення до баз даних, зовнішніх graphql на кшталт:
|
|
87
|
-
|
|
88
|
-
```js
|
|
89
|
-
import { SQL } from 'bun'
|
|
90
|
-
|
|
91
|
-
// або
|
|
92
|
-
|
|
93
|
-
import sql from 'mssql'
|
|
94
|
-
|
|
95
|
-
// або
|
|
96
|
-
|
|
97
|
-
import { GraphQLClient } from '@nitra/graphql-request'
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
то ці підключення повинні бути винесені в окремий файл, наприклад `/src/conn/pg.mjs`, в package.json повинні бути додано аліас:
|
|
101
|
-
|
|
102
|
-
```json
|
|
103
|
-
{
|
|
104
|
-
"imports": {
|
|
105
|
-
"#conn/*": "./src/conn/*"
|
|
106
|
-
},
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
так виглядатиме підключення до PostgreSQL в коді:
|
|
112
|
-
|
|
113
|
-
```javascript title="Приклад підключення до PostgreSQL в /src/conn/pg.mjs"
|
|
114
|
-
import { checkEnv, env } from '@nitra/check-env'
|
|
115
|
-
import { SQL } from 'bun'
|
|
116
|
-
|
|
117
|
-
checkEnv(['PG_CONN'])
|
|
118
|
-
|
|
119
|
-
export const db = new SQL({ url: env.PG_CONN })
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
а так до GraphQL:
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
import { checkEnv, env } from '@nitra/check-env'
|
|
127
|
-
import { GraphQLClient } from '@nitra/graphql-request'
|
|
128
|
-
|
|
129
|
-
checkEnv(['QL', 'X_HASURA_ADMIN_SECRET'])
|
|
130
|
-
|
|
131
|
-
export { gql } from '@nitra/graphql-request'
|
|
132
|
-
|
|
133
|
-
export const graphQLClientSmart = new GraphQLClient(env.QL, {
|
|
134
|
-
headers: {
|
|
135
|
-
'X-Hasura-Admin-Secret': env.X_HASURA_ADMIN_SECRET
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
а в коді повинно бути використано:
|
|
141
|
-
|
|
142
|
-
```js
|
|
143
|
-
import { pool } from '#conn/pg.mjs'
|
|
144
|
-
|
|
145
|
-
// або
|
|
146
|
-
|
|
147
|
-
import { gql, graphQLClient } from '@nitra/graphql-request'
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Нейминг файлів у `src/conn/`
|
|
151
|
-
|
|
152
|
-
Назва файла в `src/conn/` має одразу повідомляти, **до чого** підключаємось і **в якому режимі**:
|
|
153
|
-
|
|
154
|
-
- **GraphQL** — префікс `ql-`, далі ідентифікатор endpoint:
|
|
155
|
-
- `src/conn/ql-contract.mjs`
|
|
156
|
-
- `src/conn/ql-smart.mjs`
|
|
157
|
-
- **PostgreSQL** — префікс `pg-`, далі тип підключення (репліка vs мастер): `read` або `write`:
|
|
158
|
-
- `src/conn/pg-read.mjs`
|
|
159
|
-
- `src/conn/pg-write.mjs`
|
|
160
|
-
- **PostgreSQL до кількох БД** — додатково ідентифікатор підключення після типу:
|
|
161
|
-
- `src/conn/pg-read-smart.mjs`
|
|
162
|
-
- `src/conn/pg-write-contract.mjs`
|
|
163
|
-
- **MySQL** — префікс `mysql-` за тією ж схемою (`mysql-read.mjs`, `mysql-write-<id>.mjs` тощо).
|
|
164
|
-
- **MSSQL** — префікс `mssql-` за тією ж схемою (`mssql-read.mjs`, `mssql-write-<id>.mjs` тощо). Хоча npm-пакет один (`mssql`), а драйвер MS SQL Server під капотом T-SQL — у файловій назві відрізняємо MS SQL Server від MySQL, бо це різні СУБД, різні діалекти, різні рантаймні залежності. Якщо проєкт історично використовує `mysql-…` для MSSQL-підключень — він валідний і далі (для backward-compat), але новий код пишемо з префіксом `mssql-`.
|
|
165
|
-
|
|
166
|
-
Підключення до БД **обов'язково** має бути ідентифіковано як `read` (репліка) або `write` (мастер). Якщо з імені змінної оточення (наприклад, `env.PG_CONN`) це не очевидно — визнач режим за операціями в коді: якщо немає операцій зміни даних (`INSERT`/`UPDATE`/`DELETE`/DDL) — це `pg-read.mjs`, інакше `pg-write.mjs`.
|
|
167
|
-
|
|
168
|
-
### Експорти у файлах `src/conn/`
|
|
169
|
-
|
|
170
|
-
У файлах підключень **заборонений** `export default`. Експорт має бути **іменований** і збігатися з назвою файла в camelCase.
|
|
171
|
-
|
|
172
|
-
Приклад — `src/conn/ql-smart.mjs`:
|
|
173
|
-
|
|
174
|
-
```javascript title="❌ Так не можна"
|
|
175
|
-
export default new GraphQLClient(env.SMART_QL, {
|
|
176
|
-
headers: {
|
|
177
|
-
'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
|
|
178
|
-
}
|
|
179
|
-
})
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
```javascript title="✅ Канон: іменований експорт за іменем файла"
|
|
183
|
-
export const qlSmart = new GraphQLClient(env.SMART_QL, {
|
|
184
|
-
headers: {
|
|
185
|
-
'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
|
|
186
|
-
}
|
|
187
|
-
})
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Відповідно: `pg-read.mjs` → `export const pgRead = …`, `pg-write-contract.mjs` → `export const pgWriteContract = …`, `ql-contract.mjs` → `export const qlContract = …`.
|
|
191
|
-
|
|
192
|
-
## CheckEnv
|
|
193
|
-
|
|
194
|
-
Усі змінні оточення, які використовуються в коді, повинні бути перевірені за допомогою `checkEnv` з пакету `@nitra/check-env`. Це гарантує, що всі необхідні змінні оточення встановлені перед запуском програми.
|
|
195
|
-
|
|
196
|
-
```javascript title="Приклад підключення до PostgreSQL в /src/conn/pg.mjs"
|
|
197
|
-
import { checkEnv, env } from '@nitra/check-env'
|
|
198
|
-
import { SQL } from 'bun'
|
|
199
|
-
|
|
200
|
-
checkEnv(['PG_CONN'])
|
|
201
|
-
|
|
202
|
-
export const db = new SQL({ url: env.PG_CONN })
|
|
203
|
-
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
## process.env
|
|
207
|
-
|
|
208
|
-
Прямий доступ до `process.env.X` у коді заборонений — його треба замінити на `env`:
|
|
209
|
-
|
|
210
|
-
> Стосується лише backend-пакетів (див. **Область застосування**). У frontend-пакетах (`vite` у `devDependencies`) — **не змінюй** `process.env.*` і **не додавай** імпорт `node:process`.
|
|
211
|
-
|
|
212
|
-
- **обов'язкова змінна** — `import { checkEnv, env } from '@nitra/check-env'` плюс `checkEnv(['X'])`
|
|
213
|
-
у тому ж файлі (приклад див. вище в розділі **CheckEnv**);
|
|
214
|
-
- **опційна змінна** — `import { env } from 'node:process'`:
|
|
215
|
-
|
|
216
|
-
```javascript title="Опційна змінна — env з node:process"
|
|
217
|
-
import { env } from 'node:process'
|
|
218
|
-
|
|
219
|
-
console.log(env.OPTIONAL_ENV_VAR)
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
Тимчасово приглушити перевірку для конкретного рядка можна коментарем
|
|
223
|
-
`// @nitra/cursor ignore-next-line checkEnv` безпосередньо перед використанням
|
|
224
|
-
(escape-hatch для legacy-коду, не для нових файлів).
|
|
225
|
-
|
|
226
|
-
## Паузи через setTimeout
|
|
227
|
-
|
|
228
|
-
Заборонено робити паузи через `await new Promise(resolve => setTimeout(resolve, ms))` — таку обгортку треба замінити на promise-варіант `setTimeout` з `node:timers/promises`:
|
|
229
|
-
|
|
230
|
-
```javascript title="Замість new Promise + setTimeout"
|
|
231
|
-
import { setTimeout } from 'node:timers/promises'
|
|
232
|
-
|
|
233
|
-
await setTimeout(500)
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
Імпорт `setTimeout` з `node:timers/promises` затіняє глобальний таймер у файлі — якщо в тому ж файлі потрібен callback-варіант, імпортуй його під іншим іменем (наприклад, `import { setTimeout as setTimeoutCb } from 'node:timers'`).
|
|
237
|
-
|
|
238
|
-
Файли `index.*` у conn-каталозі пропускаються як можливий reexport-барель.
|
|
34
|
+
- `js_run.package_json` — заборонені `dependencies`/`devDependencies` (`bunyan`, `@nitra/bunyan`) і заборонені патерни у `scripts` (`node`, `env $(cat …) bun`)
|
|
35
|
+
- `js_run.jsconfig` — відповідність `jsconfig.json` канону (`NodeNext`, `include: src/**/*`)
|
|
36
|
+
- `js_run.configmap` — наявність `service.name=` і `service.namespace=` у `OTEL_RESOURCE_ATTRIBUTES` в `k8s/base/configmap.yaml`
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
## ConfigMap: ім'я збігається з Deployment
|
|
2
|
+
|
|
3
|
+
Якщо в `k8s/base/` є **`configmap.yaml`** і **Deployment**, і цей Deployment посилається рівно на **один** ConfigMap — `metadata.name` ConfigMap має збігатися з `metadata.name` Deployment. Точні умови перевірки — **`rules/k8s/fix.mjs`**.
|
|
4
|
+
|
|
5
|
+
## ConfigMap для Hasura-Deployment
|
|
6
|
+
|
|
7
|
+
Якщо в `k8s/base/` поруч із **`configmap.yaml`** є **Deployment** з образом **`hasura/graphql-engine`**, у `data` ConfigMap **обов'язково** мають бути env-ключі:
|
|
8
|
+
|
|
9
|
+
- **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`**;
|
|
10
|
+
- **`HASURA_GRAPHQL_ENABLE_RELAY`** зі значенням **`"false"`**;
|
|
11
|
+
- **`HASURA_GRAPHQL_ENABLE_TELEMETRY`** зі значенням **`"false"`**;
|
|
12
|
+
- **`HASURA_GRAPHQL_ENABLED_LOG_TYPES`** зі значенням **`"startup,http-log"`** (точний рядок);
|
|
13
|
+
- **`HASURA_GRAPHQL_ENABLED_APIS`** зі значенням **`"metadata,graphql,pgdump"`** (точний рядок) — **значення для base/dev**;
|
|
14
|
+
- **`HASURA_GRAPHQL_DISABLE_EVENTING`** — ключ обов'язковий, значення довільне (за замовчуванням **`"true"`**).
|
|
15
|
+
|
|
16
|
+
Точні умови перевірки — rego-пакет **`k8s.hasura_configmap`** (cross-file прив'язка ConfigMap↔Deployment — у `rules/k8s/js/manifests.mjs`).
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
data:
|
|
20
|
+
HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS: 'true'
|
|
21
|
+
HASURA_GRAPHQL_ENABLE_RELAY: 'false'
|
|
22
|
+
HASURA_GRAPHQL_ENABLE_TELEMETRY: 'false'
|
|
23
|
+
HASURA_GRAPHQL_ENABLED_LOG_TYPES: 'startup,http-log'
|
|
24
|
+
HASURA_GRAPHQL_ENABLED_APIS: 'metadata,graphql,pgdump'
|
|
25
|
+
HASURA_GRAPHQL_DISABLE_EVENTING: 'true'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### `HASURA_GRAPHQL_ENABLED_APIS` поза base/dev
|
|
29
|
+
|
|
30
|
+
`pgdump` дозволено **лише** для **base**/**dev**. Кожен **не-base** overlay (`k8s/<env>/`, де `<env>` ≠ `base`/`dev`), що успадковує Hasura-base, **зобов'язаний** у своєму **`kustomization.yaml`** перевизначити `HASURA_GRAPHQL_ENABLED_APIS` до **`"metadata,graphql"`** (без `pgdump`) — патчем JSON6902 або Strategic Merge на ціль **ConfigMap**. Перевірка — cross-file у `rules/k8s/js/manifests.mjs` (`validateHasuraOverlayEnabledApisOverride`); `kind: Component` пропускається.
|
|
31
|
+
|
|
32
|
+
```yaml title="k8s/prod/kustomization.yaml"
|
|
33
|
+
patches:
|
|
34
|
+
- target:
|
|
35
|
+
kind: ConfigMap
|
|
36
|
+
name: db-h
|
|
37
|
+
patch: |
|
|
38
|
+
- op: replace
|
|
39
|
+
path: /data/HASURA_GRAPHQL_ENABLED_APIS
|
|
40
|
+
value: metadata,graphql
|
|
41
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
## Deployment: `resources.requests` (CPU і memory)
|
|
2
|
+
|
|
3
|
+
У кожному контейнері **`Deployment`** обов'язкові **`resources.requests.cpu`** і **`resources.requests.memory`** (непорожні скаляри Kubernetes Quantity).
|
|
4
|
+
|
|
5
|
+
### Шар **`…/k8s/…/base/…`** (dev / щільний packing)
|
|
6
|
+
|
|
7
|
+
У **всіх** `Deployment` у файлах під **`…/k8s/…/base/…`** значення **жорстко фіксовані** (для **cpu** допускається число **`0.02`** у YAML):
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
resources:
|
|
11
|
+
requests:
|
|
12
|
+
cpu: '0.02'
|
|
13
|
+
memory: '128Mi'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**HPA і PDB у base не тримаємо**: ні локальних `hpa.yaml` / `pdb.yaml` поруч із workload-manifest-файлами, ні через `resources` / `components` / `bases`. Канон — sibling каталог **`components/`** (Kustomize Component) поруч з `base/`, який підключають лише прод-overlays. **NetworkPolicy** — навпаки: **обов'язковий і у `base/`**, у вигляді `base/networkpolicy.yaml` підключений через `base/kustomization.yaml` `resources:`.
|
|
17
|
+
|
|
18
|
+
### Поза base (оверлеї, окремі каталоги)
|
|
19
|
+
|
|
20
|
+
Якщо ще не підібрано власні ліміти під сервіс, орієнтир для **`requests`**:
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
resources:
|
|
24
|
+
requests:
|
|
25
|
+
cpu: '0.5'
|
|
26
|
+
memory: '512Mi'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
У прод-оверлеях підіймай **`cpu` / `memory`** до реального споживання через **`patches`**. **`check k8s`** не вимагає саме **`0.5` / `512Mi`** поза base — лише непорожні **`requests.cpu`** і **`requests.memory`**.
|
|
30
|
+
|
|
31
|
+
```yaml title="k8s/prod/kustomization.yaml (фрагмент)"
|
|
32
|
+
patches:
|
|
33
|
+
- target:
|
|
34
|
+
kind: Deployment
|
|
35
|
+
name: backend-api
|
|
36
|
+
patch: |-
|
|
37
|
+
- op: replace
|
|
38
|
+
path: /spec/template/spec/containers/0/resources/requests/cpu
|
|
39
|
+
value: '500m'
|
|
40
|
+
- op: replace
|
|
41
|
+
path: /spec/template/spec/containers/0/resources/requests/memory
|
|
42
|
+
value: 1Gi
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Образ `hasura/graphql-engine`
|
|
46
|
+
|
|
47
|
+
Образ **`hasura/graphql-engine`**: дозволений лише канонічний тег зі списку **`allowed_hasura_images`** у rego-пакеті **`k8s.manifest`** (`policy/manifest/manifest.rego` — єдине джерело істини; допускається префікс **`docker.io/`**); решта — помилка **check k8s**.
|
|
48
|
+
|
|
49
|
+
Поле **`imagePullPolicy`** скрипт **не** перевіряє.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
## HTTPRoute для Deployment з `hasura/graphql-engine`
|
|
2
|
+
|
|
3
|
+
**Прив'язка:** **check k8s** вважає **HTTPRoute** Hasura-маршрутом, якщо в **тому самому каталозі** є **`Deployment`** з образом **`hasura/graphql-engine`**, а його **`metadata.name`** збігається з **`metadata.name`** цього **`HTTPRoute`**.
|
|
4
|
+
|
|
5
|
+
**Префікс параметризовано:** **`<prefix>`** — рядок перед **`/ql`** у першому Hasura-правилі (**`Exact <prefix>/ql`**). Може бути порожнім (**`<prefix>`** = **``**, шлях **`/ql`**) або непорожнім (наприклад **`<prefix>`** = **`/notify`**, шлях **`/notify/ql`**). Усі інші Hasura-правила цього **HTTPRoute** мають містити той самий **`<prefix>`**.
|
|
6
|
+
|
|
7
|
+
**Канон — 4 правила у цьому порядку** (додаткові правила поверх канону дозволені):
|
|
8
|
+
|
|
9
|
+
1. **`Exact <prefix>/ql`** → **`RequestRedirect`** **`ReplaceFullPath <prefix>/ql/console`** **`statusCode: 302`**.
|
|
10
|
+
2. **`Exact <prefix>/ql/`** → те саме (редирект на **`<prefix>/ql/console`** 302).
|
|
11
|
+
3. **`PathPrefix <prefix>/ql`** → **`URLRewrite`** **`ReplacePrefixMatch /`**, один **`backendRef`** на headless **Service** (**`-hl`**).
|
|
12
|
+
4. **WebSocket:** **`PathPrefix <prefix>/ql`** + header **`Upgrade: websocket`** → **`URLRewrite`** **`ReplacePrefixMatch /`** + **`RequestHeaderModifier`** **`remove: [Authorization]`** (авторизація для WebSocket іде всередині messages). Той самий **`backendRef`**.
|
|
13
|
+
|
|
14
|
+
**`parentRefs`**, **`hostnames`**, **`metadata.namespace`** / **`name`** підлаштуй під середовище. У **`backendRefs.name`** вказуй **headless** **Service** з суфіксом **`-hl`**; у прикладі **`db-h-hl`** заміни на фактичне ім'я.
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
# yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/gateway.networking.k8s.io/httproute_v1beta1.json
|
|
18
|
+
apiVersion: gateway.networking.k8s.io/v1
|
|
19
|
+
kind: HTTPRoute
|
|
20
|
+
metadata:
|
|
21
|
+
name: db-h
|
|
22
|
+
namespace: dev
|
|
23
|
+
spec:
|
|
24
|
+
parentRefs:
|
|
25
|
+
- group: gateway.networking.k8s.io
|
|
26
|
+
kind: Gateway
|
|
27
|
+
name: gw
|
|
28
|
+
namespace: dev
|
|
29
|
+
sectionName: https
|
|
30
|
+
hostnames:
|
|
31
|
+
- aiml.live
|
|
32
|
+
rules:
|
|
33
|
+
- matches:
|
|
34
|
+
- path:
|
|
35
|
+
type: Exact
|
|
36
|
+
value: /ql
|
|
37
|
+
filters:
|
|
38
|
+
- type: RequestRedirect
|
|
39
|
+
requestRedirect:
|
|
40
|
+
path:
|
|
41
|
+
type: ReplaceFullPath
|
|
42
|
+
replaceFullPath: /ql/console
|
|
43
|
+
statusCode: 302
|
|
44
|
+
- matches:
|
|
45
|
+
- path:
|
|
46
|
+
type: Exact
|
|
47
|
+
value: /ql/
|
|
48
|
+
filters:
|
|
49
|
+
- type: RequestRedirect
|
|
50
|
+
requestRedirect:
|
|
51
|
+
path:
|
|
52
|
+
type: ReplaceFullPath
|
|
53
|
+
replaceFullPath: /ql/console
|
|
54
|
+
statusCode: 302
|
|
55
|
+
- matches:
|
|
56
|
+
- path:
|
|
57
|
+
type: PathPrefix
|
|
58
|
+
value: /ql
|
|
59
|
+
filters:
|
|
60
|
+
- type: URLRewrite
|
|
61
|
+
urlRewrite:
|
|
62
|
+
path:
|
|
63
|
+
type: ReplacePrefixMatch
|
|
64
|
+
replacePrefixMatch: /
|
|
65
|
+
backendRefs:
|
|
66
|
+
- name: db-h-hl
|
|
67
|
+
port: 8080
|
|
68
|
+
# у websocket авторизація йде всередині messages
|
|
69
|
+
# Той самий URLRewrite, що й для HTTP: інакше бекенд бачить /ql/v1/graphql замість /v1/graphql
|
|
70
|
+
- matches:
|
|
71
|
+
- path:
|
|
72
|
+
type: PathPrefix
|
|
73
|
+
value: /ql
|
|
74
|
+
headers:
|
|
75
|
+
- type: Exact
|
|
76
|
+
name: Upgrade
|
|
77
|
+
value: websocket
|
|
78
|
+
filters:
|
|
79
|
+
- type: URLRewrite
|
|
80
|
+
urlRewrite:
|
|
81
|
+
path:
|
|
82
|
+
type: ReplacePrefixMatch
|
|
83
|
+
replacePrefixMatch: /
|
|
84
|
+
- type: RequestHeaderModifier
|
|
85
|
+
requestHeaderModifier:
|
|
86
|
+
remove:
|
|
87
|
+
- Authorization
|
|
88
|
+
backendRefs:
|
|
89
|
+
- name: db-h-hl
|
|
90
|
+
port: 8080
|
|
91
|
+
```
|