diff --git a/TEST_STAND/LUCEE/SCHEMA.md b/TEST_STAND/LUCEE/SCHEMA.md
deleted file mode 100644
index 654dfbf..0000000
--- a/TEST_STAND/LUCEE/SCHEMA.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# LUCEE — схема взаимодействия с Postgres
-
-Ниже статическая SVG-версия схемы (надёжно рендерится в VSCode):
-
-
diff --git a/TEST_STAND/LUCEE/SCHEMA.svg b/TEST_STAND/LUCEE/SCHEMA.svg
deleted file mode 100644
index b77332f..0000000
--- a/TEST_STAND/LUCEE/SCHEMA.svg
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
\ No newline at end of file
diff --git a/TEST_STAND/LUCEE/locals.tf b/TEST_STAND/LUCEE/locals.tf
new file mode 100644
index 0000000..0c93bae
--- /dev/null
+++ b/TEST_STAND/LUCEE/locals.tf
@@ -0,0 +1,45 @@
+# =============================================================================
+# locals.tf — все настраиваемые значения модуля LUCEE
+# Никакого хардкода в ресурсах — всё здесь.
+# =============================================================================
+
+locals {
+ # ─── PostgreSQL ──────────────────────────────────────────────────────────
+ pg_resource_name = "pglucee001"
+ pg_cpu = 500
+ pg_memory = 512
+ pg_replicas = 1
+ pg_disk = 10
+ pg_version = "17"
+ pg_retain = 14
+ pg_schedule = "0 0 * * *"
+ pg_timeout = "11m"
+
+ # ─── PostgreSQL User ─────────────────────────────────────────────────────
+ pg_username = "user4crudpg"
+ pg_role = "ddl_user"
+ pg_db_name = "db4crudpg"
+
+ # ─── Lucee ───────────────────────────────────────────────────────────────
+ lucee_git_revision = "94e14"
+ lucee_resource_name = "luceeresource"
+ lucee_domain = "tflucee"
+ lucee_version = "5.4"
+ lucee_git_path = "https://gitea.services.ngcloud.ru/Nail/tfluceecrud.git"
+ lucee_cpu = 300
+ lucee_memory = 512
+ lucee_replicas = 1
+
+ # ─── Таблица CRUD ────────────────────────────────────────────────────────
+ crud_table_name = "crud_items"
+
+ # ─── JDBC / БД ───────────────────────────────────────────────────────────
+ jdbc_class = "org.postgresql.Driver"
+ jdbc_bundle_name = "org.postgresql.jdbc"
+ jdbc_bundle_version = "42.6.0"
+ jdbc_conn_limit = "5"
+ jdbc_live_timeout = "15"
+ jdbc_validate = "false"
+ pg_port = "5432"
+ pg_ssl_mode = "require"
+}
diff --git a/TEST_STAND/LUCEE/lucee.tf b/TEST_STAND/LUCEE/lucee.tf
index 7117d58..57daf86 100644
--- a/TEST_STAND/LUCEE/lucee.tf
+++ b/TEST_STAND/LUCEE/lucee.tf
@@ -1,51 +1,51 @@
locals {
pg_host = nubes_postgres.npg_lucee.state_out_flat["internalMaster"]
pg_user = nubes_postgres_user.crud_user_0.username
- pg_pass = jsondecode(nubes_postgres.npg_lucee.vault_secrets["users"]).user4crudpg.password
+ pg_pass = nonsensitive(jsondecode(nubes_postgres.npg_lucee.vault_secrets["users"]).user4crudpg.password)
pg_db = nubes_postgres_database.pg_db.db_name
}
resource "nubes_lucee" "applucee" {
- resource_name = "luceeresource"
+ resource_name = local.lucee_resource_name
startup_configuration = {
resource_realm = var.realm
}
cluster_configuration = {
- cpu = 300
- memory = 512
- replicas = 1
+ cpu = local.lucee_cpu
+ memory = local.lucee_memory
+ replicas = local.lucee_replicas
}
access_configuration = {
- domain = "tflucee"
+ domain = local.lucee_domain
}
app_configuration = {
- version = "5.4"
- git_path = "https://gitea.services.ngcloud.ru/Nail/tfluceecrud.git"
+ version = local.lucee_version
+ git_path = local.lucee_git_path
}
- git_revision = "94ebf06"
+ git_revision = local.lucee_git_revision
json_env = jsonencode({
- TABLE_NAME = "check_point"
- testds_class = "org.postgresql.Driver"
- testds_bundleName = "org.postgresql.jdbc"
- testds_bundleVersion = "42.6.0"
+ TABLE_NAME = local.crud_table_name
+ testds_class = local.jdbc_class
+ testds_bundleName = local.jdbc_bundle_name
+ testds_bundleVersion = local.jdbc_bundle_version
testds_connectionString = "jdbc:postgresql://${local.pg_host}:5432/${local.pg_db}"
testds_username = local.pg_user
testds_password = local.pg_pass
- testds_connectionLimit = "5"
- testds_liveTimeout = "15"
- testds_validate = "false"
+ testds_connectionLimit = local.jdbc_conn_limit
+ testds_liveTimeout = local.jdbc_live_timeout
+ testds_validate = local.jdbc_validate
PGHOST = local.pg_host
- PGPORT = "5432"
+ PGPORT = local.pg_port
PGUSER = local.pg_user
PGPASSWORD = local.pg_pass
- PGSSLMODE = "require"
+ PGSSLMODE = local.pg_ssl_mode
DATABASE_URL = format(
"postgresql://%s:%s@%s:5432/%s",
local.pg_user,
diff --git a/TEST_STAND/LUCEE/nubes_postgres_lucee.tf b/TEST_STAND/LUCEE/nubes_postgres_lucee.tf
index 3c0b46b..834e25b 100644
--- a/TEST_STAND/LUCEE/nubes_postgres_lucee.tf
+++ b/TEST_STAND/LUCEE/nubes_postgres_lucee.tf
@@ -1,15 +1,15 @@
resource "nubes_postgres" "npg_lucee" {
- resource_name = "pglucee001"
+ resource_name = local.pg_resource_name
startup_configuration = {
resource_realm = var.realm
}
cluster_configuration = {
- cpu = 500
- memory = 512
- replicas = 1
- disk = 10
+ cpu = local.pg_cpu
+ memory = local.pg_memory
+ replicas = local.pg_replicas
+ disk = local.pg_disk
}
access_configuration = {
@@ -20,7 +20,7 @@ resource "nubes_postgres" "npg_lucee" {
}
postgres_configuration = {
- version = "17"
+ version = local.pg_version
ssl_required = true
pooler_master = false
pooler_slave = false
@@ -33,9 +33,8 @@ resource "nubes_postgres" "npg_lucee" {
backup_configuration = {
s3_uid = var.s3_name
- # s3_uid = var.s3_user_uid
- retain = 14
- schedule = "0 0 * * *"
+ retain = local.pg_retain
+ schedule = local.pg_schedule
}
autoscale_configuration = {
@@ -45,6 +44,6 @@ resource "nubes_postgres" "npg_lucee" {
quota = 100
}
- operation_timeout = "11m"
+ operation_timeout = local.pg_timeout
adopt_existing_on_create = true
}
diff --git a/TEST_STAND/LUCEE/userUNDdb.tf b/TEST_STAND/LUCEE/userUNDdb.tf
index 103844b..2ee8cfd 100644
--- a/TEST_STAND/LUCEE/userUNDdb.tf
+++ b/TEST_STAND/LUCEE/userUNDdb.tf
@@ -1,17 +1,16 @@
# =============================================================================
-# PostgreSQL — пользователи (6 шт.)
+# PostgreSQL — пользователи и базы данных
# =============================================================================
resource "nubes_postgres_user" "crud_user_0" {
postgres_id = nubes_postgres.npg_lucee.id
- username = "user4crudpg"
- role = "ddl_user"
+ username = local.pg_username
+ role = local.pg_role
adopt_existing_on_create = true
}
resource "nubes_postgres_database" "pg_db" {
postgres_id = nubes_postgres.npg_lucee.id
- db_name = "db4crudpg"
+ db_name = local.pg_db_name
db_owner = nubes_postgres_user.crud_user_0.username
adopt_existing_on_create = true
}
-
diff --git a/TOOLS/config/dev/profile.env b/TOOLS/config/dev/profile.env
index 27db4e8..97617d0 100644
--- a/TOOLS/config/dev/profile.env
+++ b/TOOLS/config/dev/profile.env
@@ -4,7 +4,7 @@ TOKEN_FILE="secrets/dev.token"
# Release versions
# Version
-VERSION="3.1.11"
+VERSION="3.1.12"
# Registry/S3 settings
REGISTRY_HOST="registry.kube5s.ru"
diff --git a/TOOLS/config/prod/profile.env b/TOOLS/config/prod/profile.env
index d0f8eb3..5082d56 100644
--- a/TOOLS/config/prod/profile.env
+++ b/TOOLS/config/prod/profile.env
@@ -4,7 +4,7 @@ TOKEN_FILE="secrets/prod.token"
# Release versions
# Version
-VERSION="2.1.10"
+VERSION="2.1.11"
# Registry/S3 settings
REGISTRY_HOST="registry.kube5s.ru"
diff --git a/TOOLS/config/test/profile.env b/TOOLS/config/test/profile.env
index 259b5db..ac1b71e 100644
--- a/TOOLS/config/test/profile.env
+++ b/TOOLS/config/test/profile.env
@@ -3,7 +3,7 @@ NUBES_API_ENDPOINT="https://lk-api-gateway-test.ngcloud.ru/api/v1/svc"
TOKEN_FILE="secrets/test.token"
# Version
-VERSION="5.1.13"
+VERSION="5.1.14"
# Docs generation — ONLY from docs_gen// (never from docs/)
DOCS_GEN_DIR="provider/docs_gen/test"
diff --git a/TOOLS/resource-generator/internal/templates/instance.go b/TOOLS/resource-generator/internal/templates/instance.go
index b1e0c8f..ef22a03 100644
--- a/TOOLS/resource-generator/internal/templates/instance.go
+++ b/TOOLS/resource-generator/internal/templates/instance.go
@@ -548,7 +548,6 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd
{{- if .HasRedeploy }}
// --- Redeploy support (ARCHITECTURE.md) ---
if redeployRequested {
- {{- if .RedeployParams }}
redeployParams := map[int]string{}
{{- range .RedeployParams }}
{{- if (IsNested .) }}
@@ -559,10 +558,17 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd
redeployParams[{{.ID}}] = {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}}
{{- end }}
{{- end }}
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, redeployParams); err != nil {
+ // Merge modify-params into redeploy to avoid state drift
+ {{- range .ModifyParams }}
+ {{- if (IsNested .) }}
+ if plan.{{ToCamel .Code}} != nil {
+ redeployParams[{{.ID}}] = {{NestedJSONExpr . "plan"}}
+ }
{{- else }}
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, nil); err != nil {
+ redeployParams[{{.ID}}] = {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}}
{{- end }}
+ {{- end }}
+ if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout, redeployParams); err != nil {
resp.Diagnostics.AddError("Ошибка клиента", err.Error())
return
}
diff --git a/docs/TODO/GATEWAY_SERVICE.md b/docs/TODO/GATEWAY_SERVICE.md
new file mode 100644
index 0000000..ab7788d
--- /dev/null
+++ b/docs/TODO/GATEWAY_SERVICE.md
@@ -0,0 +1,574 @@
+# GATEWAY Service — Path-based DNS-less Router
+
+> **Репозиторий:** `gateway` (шаблонный, создан 2026-07-20)
+> **URL:** `https://gateway.nodejsk8s.services.ngcloud.ru/`
+> **Назначение:** Замена всех DNS-записей `*.kube5s.ru` единым path-based роутером
+> **Статус:** СПЛАНИРОВАНО, НЕ НАЧАТО
+
+---
+
+## 1. ЗАЧЕМ ЭТО НУЖНО
+
+### Проблема
+
+Сейчас каждый сервис живёт на своём поддомене `*.kube5s.ru`:
+
+| Поддомен | Сервис | Ingress | TLS-сертификат |
+|----------|--------|---------|-----------------|
+| `registry.kube5s.ru` | Terraform Registry | отдельный | отдельный |
+| `something1.kube5s.ru` | Сервис 1 | отдельный | отдельный |
+| `something2.kube5s.ru` | Сервис 2 | отдельный | отдельный |
+| ... | ... | ... | ... |
+
+**Проблемы:**
+- Домен `kube5s.ru` — **срочный**, скоро истекает
+- Продление — **дорого**
+- Каждый поддомен = DNS-запись + Ingress + сертификат — **администрировать заебало**
+
+### Решение
+
+**Один домен, один Ingress, один сертификат.** Все сервисы — под path-префиксами:
+
+```
+https://gateway.nodejsk8s.services.ngcloud.ru/record01/* → Сервис 1
+https://gateway.nodejsk8s.services.ngcloud.ru/record02/* → Сервис 2
+https://gateway.nodejsk8s.services.ngcloud.ru/record03/* → Сервис 3
+```
+
+Домен `gateway.nodejsk8s.services.ngcloud.ru` — **облачный managed service**, назначается облаком, не требует покупки/продления.
+
+### Выгода
+
+| Было (DNS-based) | Стало (Path-based) |
+|---|---|
+| N DNS-записей | 0 дополнительных DNS-записей |
+| N Ingress'ов | 1 Ingress |
+| N TLS-сертификатов | 1 TLS-сертификат |
+| Домен `kube5s.ru` нужен | Домен `kube5s.ru` не нужен |
+
+---
+
+## 2. АРХИТЕКТУРА
+
+```mermaid
+graph TD
+ subgraph "Внешний мир"
+ T[Terraform CLI]
+ C[Клиенты API]
+ end
+
+ subgraph "Kubernetes (облако Nubes)"
+ I["Ingress
gateway.nodejsk8s.services.ngcloud.ru
(cert-manager + LE)"]
+ G["GATEWAY Service
(NodeJS: Express + http-proxy-middleware)"]
+
+ I --> G
+
+ G -->|"/record01/*"| R1["registry-server
(Terraform Registry)"]
+ G -->|"/record02/*"| R2["Сервис 2
(будущий)"]
+ G -->|"/record03/*"| R3["Сервис 3
(будущий)"]
+ G -->|"/"| FALLBACK["Fallback / health-check"]
+ end
+
+ T -->|"source = gateway...nubes.ru/nubes/nubes"| I
+```
+
+### Как это работает (для Terraform Registry)
+
+1. Terraform читает `.tf`:
+ ```hcl
+ source = "gateway.nodejsk8s.services.ngcloud.ru/nubes-test/nubes"
+ ```
+
+2. Terraform идёт в:
+ ```
+ GET https://gateway.nodejsk8s.services.ngcloud.ru/.well-known/terraform.json
+ ```
+
+3. GATEWAY проксирует на registry-server, который отвечает:
+ ```json
+ { "providers.v1": "/record01/v1/providers/" }
+ ```
+
+4. Terraform дальше сам идёт по `/record01/v1/providers/nubes-test/nubes/versions`
+
+5. Registry-server генерит download-url с префиксом `/record01/v1/proxy?...`
+
+6. Profit. Terraform скачивает провайдер.
+
+---
+
+## 3. КОНФИГУРАЦИЯ GATEWAY
+
+### Формат конфига (`config.yaml` или env-переменные)
+
+```yaml
+# gateway/config.yaml
+routes:
+ - id: "registry"
+ prefix: "/record01"
+ description: "Terraform Provider Registry"
+ upstream: "http://registry-server.terra.svc.cluster.local:8080"
+ stripPrefix: false # НЕ отрезать /record01 — registry сам знает свой префикс
+ timeout: 30000 # 30s (registry может долго листить S3)
+
+ - id: "future-service-2"
+ prefix: "/record02"
+ description: "Будущий сервис — TODO"
+ upstream: "http://service2.namespace.svc.cluster.local:8080"
+ stripPrefix: true # Отрезать /record02 перед отправкой в upstream
+ timeout: 10000
+
+ - id: "future-service-3"
+ prefix: "/record03"
+ description: "Будущий сервис — TODO"
+ upstream: "http://service3.namespace.svc.cluster.local:3000"
+ stripPrefix: true
+ timeout: 10000
+```
+
+### Конфиг через env (альтернатива, проще для K8s)
+
+```bash
+# Формат: ROUTE_XX_ID, ROUTE_XX_PREFIX, ROUTE_XX_UPSTREAM, ROUTE_XX_STRIP, ROUTE_XX_TIMEOUT
+ROUTE_01_ID=registry
+ROUTE_01_PREFIX=/record01
+ROUTE_01_UPSTREAM=http://registry-server.terra.svc.cluster.local:8080
+ROUTE_01_STRIP=false
+ROUTE_01_TIMEOUT=30000
+
+ROUTE_02_ID=future-svc
+ROUTE_02_PREFIX=/record02
+ROUTE_02_UPSTREAM=http://service2.namespace.svc.cluster.local:8080
+ROUTE_02_STRIP=true
+ROUTE_02_TIMEOUT=10000
+```
+
+### Важно: `stripPrefix`
+
+| Режим | Когда использовать |
+|-------|--------------------|
+| `stripPrefix: false` | Upstream **знает** о своём префиксе и сам его обрабатывает (как registry-server с `PATH_PREFIX=/record01`) |
+| `stripPrefix: true` | Upstream **не знает** о префиксе — GATEWAY отрезает его перед проксированием. `/record01/api/users` → `/api/users` |
+
+---
+
+## 4. КОД GATEWAY (план)
+
+### Стек
+
+- **NodeJS** + **Express** — HTTP-фреймворк
+- **http-proxy-middleware** — реверс-прокси
+- **Dotenv / js-yaml** — конфигурация
+
+### Структура проекта
+
+```
+gateway/
+├── package.json
+├── server.js # Главный файл
+├── config/
+│ ├── routes.yaml # Конфиг маршрутов
+│ └── index.js # Загрузчик конфига
+├── lib/
+│ ├── proxy.js # Фабрика proxy-middleware'ов из конфига
+│ ├── health.js # Health/readiness probes
+│ └── logger.js # Логирование
+├── Dockerfile
+├── .dockerignore
+└── README.md
+```
+
+### `server.js` (псевдокод)
+
+```javascript
+const express = require('express');
+const { createProxyMiddleware } = require('http-proxy-middleware');
+const { loadRoutes } = require('./config');
+const { healthHandler, readyHandler } = require('./lib/health');
+
+const app = express();
+const routes = loadRoutes(); // из env или routes.yaml
+
+// Health probes (без прокси)
+app.get('/healthz', healthHandler);
+app.get('/readyz', readyHandler);
+
+// Root — информационная страница
+app.get('/', (req, res) => {
+ res.json({
+ service: 'gateway',
+ version: process.env.APP_VERSION || '1.0.0',
+ routes: routes.map(r => ({
+ prefix: r.prefix,
+ description: r.description
+ }))
+ });
+});
+
+// Динамическая регистрация прокси-маршрутов
+for (const route of routes) {
+ const proxy = createProxyMiddleware({
+ target: route.upstream,
+ changeOrigin: true,
+ pathRewrite: route.stripPrefix
+ ? { [`^${route.prefix}`]: '' }
+ : undefined,
+ timeout: route.timeout,
+ onError: (err, req, res) => {
+ console.error(`[${route.id}] Proxy error:`, err.message);
+ res.status(502).json({ error: 'Upstream unavailable', route: route.id });
+ }
+ });
+
+ app.use(route.prefix, proxy);
+ console.log(`Route: ${route.prefix} → ${route.upstream} (strip: ${route.stripPrefix})`);
+}
+
+// 404 для всего остального
+app.use((req, res) => {
+ res.status(404).json({ error: 'Not Found', path: req.path });
+});
+
+app.listen(process.env.PORT || 3000);
+```
+
+---
+
+## 5. КАК ДОБАВИТЬ НОВЫЙ СЕРВИС (RECORD)
+
+### Шаг 1: Создать сервис в K8s
+
+```yaml
+# Пример: новый сервис my-api
+apiVersion: v1
+kind: Service
+metadata:
+ name: my-api
+ namespace: default
+spec:
+ ports:
+ - port: 8080
+ selector:
+ app: my-api
+```
+
+### Шаг 2: Добавить route в конфиг gateway
+
+```yaml
+# Добавить в config/routes.yaml:
+ - id: "my-api"
+ prefix: "/record04"
+ description: "Мой новый API"
+ upstream: "http://my-api.default.svc.cluster.local:8080"
+ stripPrefix: true
+ timeout: 10000
+```
+
+### Шаг 3: Передеплоить gateway
+
+```bash
+kubectl rollout restart deployment/gateway -n terra
+```
+
+### Шаг 4: Готово
+
+Сервис доступен по адресу:
+```
+https://gateway.nodejsk8s.services.ngcloud.ru/record04/
+```
+
+**Никаких DNS, Ingress'ов, сертификатов.** Только конфиг gateway.
+
+---
+
+## 6. ЧТО НУЖНО ПОМЕНЯТЬ В REGISTRY-SERVER
+
+Файл: `~/tf_registry/server/main.go`
+
+### Добавить env-переменную
+
+```go
+var pathPrefix = os.Getenv("PATH_PREFIX") // "/record01" или "" (пустая строка = без префикса, обратная совместимость)
+```
+
+### Изменить `main()` — регистрация handlers
+
+```go
+// БЫЛО:
+http.HandleFunc("/.well-known/terraform.json", discoveryHandler)
+http.HandleFunc("/v1/providers/", router)
+http.HandleFunc("/v1/proxy", proxyHandler)
+http.HandleFunc("/docs/", docsHandler)
+
+// СТАЛО:
+http.HandleFunc(pathPrefix+"/.well-known/terraform.json", discoveryHandler)
+http.HandleFunc(pathPrefix+"/v1/providers/", router)
+http.HandleFunc(pathPrefix+"/v1/proxy", proxyHandler)
+http.HandleFunc(pathPrefix+"/docs/", docsHandler)
+```
+
+### Изменить `discoveryHandler()` — ответ с префиксом
+
+```go
+// БЫЛО:
+json.NewEncoder(w).Encode(Discovery{ProvidersV1: "/v1/providers/"})
+
+// СТАЛО:
+json.NewEncoder(w).Encode(Discovery{ProvidersV1: pathPrefix + "/v1/providers/"})
+```
+
+### Изменить `downloadVersion()` — ссылки с префиксом
+
+```go
+// БЫЛО:
+baseURL := "https://" + hostname
+downloadLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(fullKey))
+
+// СТАЛО:
+baseURL := "https://" + hostname + pathPrefix
+downloadLink := fmt.Sprintf("%s/v1/proxy?bucket=%s&key=%s", baseURL, bucketName, url.QueryEscape(fullKey))
+```
+
+### Изменить `listVersions()` — S3-префикс
+
+```go
+// БЫЛО:
+prefix := fmt.Sprintf("%s/%s/%s/", hostname, namespace, pType)
+
+// СТАЛО (hostname теперь = gateway.nodejsk8s.services.ngcloud.ru):
+// Если PATH_PREFIX непустой, можно использовать его как основу для S3-пути,
+// либо продолжать использовать hostname. Зависит от того, как лежат файлы в S3.
+// Пока оставляем hostname — он просто поменяется на новый домен.
+prefix := fmt.Sprintf("%s/%s/%s/", hostname, namespace, pType)
+```
+
+### Новые env-переменные для registry-server
+
+| Переменная | Было | Стало |
+|------------|------|-------|
+| `REGISTRY_HOSTNAME` | `terra.k8c.ru` / `registry.kube5s.ru` | `gateway.nodejsk8s.services.ngcloud.ru` |
+| `PATH_PREFIX` | — | `/record01` |
+
+---
+
+## 7. КАК ЭТО ВЫГЛЯДИТ ДЛЯ КЛИЕНТОВ (terraform init)
+
+### Было
+
+```hcl
+terraform {
+ required_providers {
+ nubes = {
+ source = "registry.kube5s.ru/nubes-test/nubes"
+ version = "5.1.13"
+ }
+ }
+}
+```
+
+### Стало
+
+```hcl
+terraform {
+ required_providers {
+ nubes = {
+ source = "gateway.nodejsk8s.services.ngcloud.ru/nubes-test/nubes"
+ version = "5.1.13"
+ }
+ }
+}
+```
+
+**Всё.** Terraform сам разберётся:
+1. Пойдёт на `.well-known/terraform.json`
+2. Получит путь `/record01/v1/providers/`
+3. Скачает провайдер через `/record01/v1/proxy?...`
+
+---
+
+## 8. ПЛАН ВНЕДРЕНИЯ
+
+### Фаза 1: Подготовка GATEWAY
+
+- [ ] Склонировать шаблонный репо
+- [ ] Написать `server.js` (прокси-роутер)
+- [ ] Написать `config/routes.yaml` с первым роутом (`/record01` → registry)
+- [ ] Dockerfile
+- [ ] Helm chart / K8s manifests (Deployment, Service)
+- [ ] Ingress: `gateway.nodejsk8s.services.ngcloud.ru` → gateway-service
+- [ ] TLS через cert-manager
+
+### Фаза 2: Подготовка Registry-Server
+
+- [ ] Добавить `PATH_PREFIX` в `server/main.go`
+- [ ] Изменить `REGISTRY_HOSTNAME` на `gateway.nodejsk8s.services.ngcloud.ru`
+- [ ] Собрать новый Docker-образ
+- [ ] Задеплоить registry-server с новыми env
+- [ ] Убедиться что registry отвечает на `/record01/.well-known/terraform.json`
+- [ ] Убедиться что download-url содержат `/record01/`
+
+### Фаза 3: Тестирование
+
+- [ ] `curl https://gateway.nodejsk8s.services.ngcloud.ru/record01/.well-known/terraform.json` → OK
+- [ ] `curl https://gateway.nodejsk8s.services.ngcloud.ru/record01/v1/providers/nubes-test/nubes/versions` → OK
+- [ ] `terraform init` с новым source → OK
+
+### Фаза 4: Миграция клиентов
+
+- [ ] Обновить `provider/main.go` — `address` по умолчанию на новый домен
+- [ ] Обновить profile.env (dev/test/prod) — `REGISTRY_HOSTNAME`
+- [ ] Обновить все `.tf` файлы в `PROD_STAND/`, `TEST_STAND/`, `DEV_STAND/`
+- [ ] Обновить CI/CD (`.github/workflows/`, build scripts)
+- [ ] Старый `registry.kube5s.ru` — 301 редирект или удалить
+
+### Фаза 5: Добавление остальных сервисов
+
+- [ ] Выявить все текущие `*.kube5s.ru` (через grep по всем репо)
+- [ ] Для каждого: добавить route в gateway
+- [ ] Перенести сервис за gateway
+- [ ] Удалить старые DNS/Ingress/сертификаты
+
+---
+
+## 9. ТЕКУЩИЕ ЗАПИСИ `kube5s.ru` (НАЙТИ ВСЕ)
+
+```bash
+# Выполнить чтобы найти все использования kube5s.ru:
+grep -r "kube5s\.ru" /home/naeel/ --include="*.{tf,yaml,yml,go,sh,env,js,json,md,cfg,ejs,html}" -l
+```
+
+**Известные на 2026-07-20:**
+
+| Запись | Сервис | Приоритет миграции |
+|--------|--------|--------------------|
+| `registry.kube5s.ru` | Terraform Registry Server | **#1 (критично)** |
+| ??? | ??? | Найти grep'ом |
+
+---
+
+## 10. КОНФИГУРАЦИЯ KUBERNETES
+
+### Deployment
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: gateway
+ namespace: terra
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: gateway
+ template:
+ metadata:
+ labels:
+ app: gateway
+ spec:
+ containers:
+ - name: gateway
+ image: registry.kube5s.ru/gateway:1.0.0
+ ports:
+ - containerPort: 3000
+ env:
+ - name: PORT
+ value: "3000"
+ - name: APP_VERSION
+ value: "1.0.0"
+ # ROUTES
+ - name: ROUTE_01_ID
+ value: "registry"
+ - name: ROUTE_01_PREFIX
+ value: "/record01"
+ - name: ROUTE_01_UPSTREAM
+ value: "http://registry-server.terra.svc.cluster.local:8080"
+ - name: ROUTE_01_STRIP
+ value: "false"
+ - name: ROUTE_01_TIMEOUT
+ value: "30000"
+ livenessProbe:
+ httpGet:
+ path: /healthz
+ port: 3000
+ initialDelaySeconds: 5
+ readinessProbe:
+ httpGet:
+ path: /readyz
+ port: 3000
+ initialDelaySeconds: 3
+```
+
+### Service
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: gateway
+ namespace: terra
+spec:
+ ports:
+ - port: 80
+ targetPort: 3000
+ selector:
+ app: gateway
+```
+
+### Ingress
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: gateway-ingress
+ namespace: terra
+ annotations:
+ cert-manager.io/cluster-issuer: "letsencrypt-prod"
+ nginx.ingress.kubernetes.io/proxy-body-size: "100m"
+spec:
+ ingressClassName: nginx
+ tls:
+ - hosts:
+ - gateway.nodejsk8s.services.ngcloud.ru
+ secretName: gateway-tls
+ rules:
+ - host: gateway.nodejsk8s.services.ngcloud.ru
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: gateway
+ port:
+ number: 80
+```
+
+---
+
+## 11. ССЫЛКИ
+
+| Ресурс | URL |
+|--------|-----|
+| GATEWAY (production) | `https://gateway.nodejsk8s.services.ngcloud.ru/` |
+| Репозиторий GATEWAY | `~/tf_provider/gateway/` (создать) или отдельный репо |
+| Registry Server | `~/tf_registry/server/main.go` |
+| Terraform Provider | `~/tf_provider/provider/main.go` |
+| S3 (registry files) | `s3.msk-1.ngcloud.ru`, bucket `terraform-registry` |
+
+---
+
+## 12. КОНТРОЛЬНЫЙ СПИСОК ПРИ ДОБАВЛЕНИИ НОВОГО RECORD
+
+1. [ ] Сервис задеплоен в K8s, есть Service
+2. [ ] Сервис работает (проверить через `kubectl port-forward` или напрямую)
+3. [ ] Определён `stripPrefix`: upstream знает о префиксе? (как registry) или нет?
+4. [ ] Добавлен route в конфиг gateway
+5. [ ] Gateway передеплоен
+6. [ ] Проверен curl через gateway: `curl https://gateway...ngcloud.ru/recordXX/...`
+7. [ ] Клиенты обновлены на новый URL
+
+---
+
+*Документ создан 2026-07-20. Планирование завершено, реализация — позже.*
diff --git a/tfluceecrud b/tfluceecrud
index 53e12ec..7b6ab4c 160000
--- a/tfluceecrud
+++ b/tfluceecrud
@@ -1 +1 @@
-Subproject commit 53e12ecddd2237c70d0ddde536a7edef6e748649
+Subproject commit 7b6ab4c8b735ca7858c083f4e72a14a263c83f8f