docs(status): snapshot v0.9 (2026-05-06)
Закрыло за сутки: bundle 7→40 справочников, Альтум pull verified, Tempo+Loki+Grafana+SLO burn rate alerts (Google SRE multi-window), UI scope grouping + accents, INTERNAL словари visibility (rolesClaim), CNPG 1.24→1.25.4 + spec.probes, CI helm --atomic + auto-rollback, config-server startupProbe, 75→109 unit тестов. Готовы к prod (manifests + runbooks): multi-instance Postgres HA, external S3 backup, k6 benchmark setup. Block — DNS/cert prod, S3 provider creds, real ЦУОД data. Прогресс: 21/33 (v0.5) → 27/39 требований (v0.9). 1-2 недели до v1. v0.5 файл оставлен как историческая запись.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
# Состояние разработки НСИ (Ordinis ЦУОД ОДХ)
|
||||
|
||||
**Версия:** v0.5 (MVP+, anchor v1 — в процессе закрытия)
|
||||
**Дата:** 2026-05-05
|
||||
**Owner:** zimin.an@nstart.space
|
||||
**Окружения:** staging (192.168.100.161 / cluster.265), prod (192.168.100.142 / cluster.142, hibernated)
|
||||
|
||||
---
|
||||
|
||||
## 1. Перечень требований
|
||||
|
||||
### 1.1. Реализовано (production-ready на staging)
|
||||
|
||||
| # | Требование | Статус | Где зафиксировано |
|
||||
|----|--------------------------------------------------------------|--------|---|
|
||||
| 1 | Каталог НСИ ЦУОД ОДХ — единый источник истины | ✅ | bundle `cuod` v1.1.0 |
|
||||
| 2 | Bitemporal модель (валидное-время + транзакционное-время) | ✅ | `dictionary_records` + `valid_from`/`valid_to` + Hibernate Envers |
|
||||
| 3 | JSON Schema валидация записей (Draft-07) | ✅ | `ordinis-validation` (networknt) |
|
||||
| 4 | i18n поля (RU + EN) с patternProperties | ✅ | `x-localized: true` extension |
|
||||
| 5 | Уникальные поля (бизнес-ключ + произвольные) | ✅ | `x-unique` extension + native query enforcement |
|
||||
| 6 | Авто-derive businessKey из data поля | ✅ | `x-id-source` extension |
|
||||
| 7 | История версий записи + diff | ✅ | `/records/{key}/history` + UI drawer |
|
||||
| 8 | Schema versioning + breaking-change detection | ✅ | `diffSchemas` + Save-block + auto major/minor/patch |
|
||||
| 9 | Аудит-лог (кто, когда, что, IP, trace_id) | ✅ | `audit_log` + `AuditLogger` + UI `/audit` + CSV export |
|
||||
| 10 | Kafka outbox (at-least-once гарантия) | ✅ | `OutboxPoller` + DLQ cap (1000 attempts) |
|
||||
| 11 | Idempotency для мутирующих запросов | ✅ | `Idempotency-Key` header + sha-256 hash |
|
||||
| 12 | Multi-scope доступ (PUBLIC / INTERNAL / RESTRICTED) | ✅ | `DataScope` + JWT roles + Kafka per-scope topics |
|
||||
| 13 | Keycloak OIDC (issuer-uri auto-discovery) | ✅ | `ordinis-auth` + `JwtDecoders.fromIssuerLocation` |
|
||||
| 14 | Visual schema builder + CRUD UI | ✅ | admin-ui (React 19 + TanStack + @nstart/ui) |
|
||||
| 15 | SSO для admin-ui (PKCE Public client) | ✅ | react-oidc-context |
|
||||
| 16 | Bundle import (idempotent seed) | ✅ | `CuodBundleImporter` startup runner |
|
||||
| 17 | Swagger UI / OpenAPI 3 spec | ✅ | springdoc на `/swagger-ui.html` |
|
||||
| 18 | 7 справочников + 51 запись на staging | ✅ | spacecraft (14), satellite_type (5), ground_station (3), mission (9), instrument (11), processing_level (8), data_format (8) |
|
||||
| 19 | Friendly error responses (409/400/404 вместо 500) | ✅ | `GlobalExceptionHandler` |
|
||||
| 20 | Метрики Prometheus + actuator/health | ✅ | `ordinis_outbox_*`, `ordinis_kafka_*` |
|
||||
| 21 | Тесты | ✅ | 24 backend + 51 frontend = **75 unit-тестов**, все зелёные |
|
||||
|
||||
### 1.2. В работе / required для v1 closure
|
||||
|
||||
| # | Требование | Статус | Блокер |
|
||||
|----|-----------------------------------------------------------|--------------|--------|
|
||||
| 22 | Real consumer integration (Альтум — заказ съёмки) | 🟡 в процессе | Альтум собирает BFF (FastAPI), ждём первого pull от них |
|
||||
| 23 | DNS A-record + Let's Encrypt cert на prod | 🔴 | DNS не проброшен на 192.168.100.142, prod hibernated |
|
||||
| 24 | `ORDINIS_AUTH_REQUIRED=true` на prod | 🔴 | Зависит от готовности SSO admin-ui на prod + Альтум |
|
||||
| 25 | Distributed tracing (Tempo) на prod | 🔴 | Не развёрнут observability stack |
|
||||
| 26 | CNPG backup в S3 + DR rehearsal | 🔴 | S3-endpoint не настроен |
|
||||
| 27 | SLO + alerts (Prometheus) | 🔴 | Не описаны метрики |
|
||||
| 28 | 30+ справочников ЦУОД ОДХ (full coverage) | 🟡 | Сейчас 7 — anchor-набор. Нужны: антенны, частотные диапазоны, орбиты, операторы, потребители, контракты, зоны покрытия, климатические зоны и т.д. |
|
||||
| 29 | Operator runbook | 🟡 | Частично: docs/integration, docs/tech. Нет процедуры unseal Vault, поднятия hibernated prod, рестарта Kafka |
|
||||
| 30 | e2e API тесты (testcontainers) | 🔴 | Только unit |
|
||||
| 31 | Component тесты frontend (RTL) | 🔴 | Только pure-logic |
|
||||
| 32 | Bundle code-splitting (~660KB gzip) | 🔴 | echarts/lottie/@nstart/ui тянут единый chunk |
|
||||
| 33 | Vault auto-unseal | 🔴 | Критично после reboot ноды — обнаружено 2026-05-05 |
|
||||
|
||||
### 1.3. v2 (governance / data quality / federation)
|
||||
|
||||
Не блокирует prod stand-up. Плановый roadmap (~2-3 квартала):
|
||||
|
||||
- Approval workflow (draft → review → publish), ownership trees, RBAC per-dictionary
|
||||
- Lineage / dependency graph
|
||||
- Geo first-class (карта ввода/превью, bbox/polygon query)
|
||||
- Cross-dictionary FK с cascade rules
|
||||
- Data quality rules engine (cross-field constraints, ML-anomaly detection)
|
||||
- Federation MDM-кластеров (master/replica)
|
||||
- Schema registry (Apicurio/Confluent) для Kafka
|
||||
- Webhooks для не-Kafka consumer'ов
|
||||
|
||||
---
|
||||
|
||||
## 2. Нерешённые технические вопросы
|
||||
|
||||
### 2.1. Критические для prod
|
||||
|
||||
1. **Vault auto-unseal.** 2026-05-05 после reboot ноды staging Vault sealed → 3 Spring Boot pod'а залипли в Init на 3+ минут. Любой prod reboot = downtime + ручной шаг (3 unseal-ключа из 5). Решения:
|
||||
- (a) Transit secret engine из master Vault (рекомендуется при наличии)
|
||||
- (b) Yandex Cloud KMS / Selectel KMS auto-unseal
|
||||
- (c) Скриптованный manual + runbook (минимум для v1, мигрировать позже)
|
||||
|
||||
2. **Audience валидация JWT.** Сейчас не enforced — принимаем токены от любого клиента в realm `nstart`. Допускает scope-эскалацию через interactive client другого приложения. На prod нужно либо включить audience-check, либо доказать что Альтум client мапит `aud=ordinis` через Keycloak Audience Mapper.
|
||||
|
||||
3. **Outbox poll-interval 1 сек на prod.** При 100+ событиях/сек → 86k+ запросов к Postgres/день. Возможно нужен batch tuning или reactive listener вместо poll.
|
||||
|
||||
4. **Single-instance Postgres.** На staging и prod — CNPG cluster с `instances: 1`, реплика отсутствует. Failover нет. Для prod-нагрузки нужен `instances: 3` с PgBouncer.
|
||||
|
||||
### 2.2. Архитектурные открытые вопросы
|
||||
|
||||
5. **Realtime invalidation для consumer'ов.** TTL 5 мин кэша достаточен для v1, но при критичных операциях (закрытие КА за день до запуска) нужен push. Kafka topic `nsi.dictionary.changed` запланирован на v2 — критичность для consumer'ов оценивается.
|
||||
|
||||
6. **Геоданные.** В spacecraft.schema есть orbit-параметры, в ground_station — geometry (PostGIS). Но Альтум-задача (заказ съёмки) использует bbox/polygon — bitemporal-выборка по геометрии не реализована. Нужно подтверждение от ЦУОД что геопоиск нужен в v1 или v2.
|
||||
|
||||
7. **Multi-tenancy.** Сейчас `bundle: cuod` — anchor customer. Второй клиент → второй bundle, своя тройка Kafka топиков. Но шаринг справочников между bundle (например spacecraft общий для ЦУОД и геопортала) не определён архитектурно.
|
||||
|
||||
8. **Object storage / большие справочники.** Если справочник вырастет до 100k+ записей (например climate zones), JSONB в одной таблице может стать узким местом. Партиционирование `dictionary_records` по `dictionary_id` — потенциальное решение, нужна оценка.
|
||||
|
||||
### 2.3. Operational
|
||||
|
||||
9. **Vault-agent-init backoff.** ~3 минут при transient Vault unavailability — слишком долго. Нужен tuning либо переход на CSI Driver.
|
||||
|
||||
10. **JDK 25 + Mockito inline** несовместим. Перешли на subclass mock-maker. При апгрейде до Java 26 проверить.
|
||||
|
||||
11. **CI path-filter.** Был костыль, рассыпался при односторонних изменениях. Сейчас все docker jobs запускаются всегда (~30s extra на layer-cache). Можно вернуться к smart-filter когда GitLab variable interpolation в trigger jobs будет надёжной.
|
||||
|
||||
12. **OTel exporter logs/metrics 404.** Tempo на staging принимает только traces, logs/metrics endpoint отсутствует. Pod-логи замусориваются. Либо отключить logs/metrics export, либо поднять Loki/Mimir.
|
||||
|
||||
### 2.4. Compliance / правовые
|
||||
|
||||
13. **Audit retention policy.** Сейчас `audit_log` пишется бессрочно. По регламенту ЦУОД нужно определить срок хранения (5 лет? 10 лет?) и автоматическую архивацию.
|
||||
|
||||
14. **Personal data handling.** В audit_log пишется `user_id` (Keycloak sub) + IP. ФЗ-152 — нужна оценка / DPA если в realm будут юзеры — не-сотрудники.
|
||||
|
||||
15. **Электронная подпись изменений.** Если потребуется юридически значимая фиксация изменений справочников (КЭП оператора при close записи) — отдельный модуль, не реализован.
|
||||
|
||||
---
|
||||
|
||||
## 3. Наличие технической документации
|
||||
|
||||
### 3.1. Создана и актуальна
|
||||
|
||||
| Документ | Назначение | Расположение |
|
||||
|---|---|---|
|
||||
| **API integration guide** | Гайд для интеграторов (Альтум, геопортал): auth flow, endpoints, кэш-стратегии, bitemporal модель, businessKey'и | `docs/tech/api-integration.md` |
|
||||
| **Альтум integration ТЗ** | Согласованный план интеграции «Заказ съёмки», схемы 4 справочников, BFF архитектура | `docs/integration/altum-imaging-order.md` |
|
||||
| **OpenAPI 3 spec (Swagger)** | Машиночитаемая спецификация всех endpoints, можно генерить SDK | `https://ordinis.k8s.265.nstart.cloud/swagger-ui.html` + `/v3/api-docs` |
|
||||
| **Bundle manifest + schemas** | JSON Schema каждого справочника + readable manifest | `ordinis-cuod-bundle/src/main/resources/bundles/cuod/` |
|
||||
| **Архитектурные решения inline** | JavaDoc + конструктивные комментарии в ключевых классах: `ScopeContext`, `OutboxPoller`, `DictionaryRecordService`, `AuditLogger` | в коде |
|
||||
| **CI/Helm values** | Параметризация per-env, CORS, ingress, image-tag override | `ordinis-infra/charts/ordinis/{values,values-staging,values-prod}.yaml` |
|
||||
|
||||
### 3.2. Отсутствует / требует написания
|
||||
|
||||
| Документ | Приоритет | Назначение |
|
||||
|---|---|---|
|
||||
| **Operator runbook** | 🔴 high | Procedure cards для типовых задач: unseal Vault, поднятие hibernated prod, рестарт Kafka StrimziPodSet, миграция БД, рестарт outbox-loop, разбор DLQ. Инцидент 2026-05-05 показал острую необходимость. |
|
||||
| **DR plan** | 🔴 high | Backup → S3, RTO/RPO, процедура восстановления из CNPG snapshot |
|
||||
| **Архитектурный обзор (HLA)** | 🟡 medium | Single-pager для нового тех-лида: модули, потоки данных, scope-фильтрация, bitemporal-логика — без необходимости читать код |
|
||||
| **User docs / справка оператора НСИ** | 🟡 medium | Как создать справочник, как закрыть запись, как читать журнал аудита, как разобрать ошибку валидации схемы — для не-инженерных юзеров |
|
||||
| **Миграционный гайд** | 🟢 low | Как мигрировать данные из существующих локальных справочников (Альтум, геопортал) в Ordinis bundle |
|
||||
| **Threat model + security review** | 🟡 medium | OWASP-чеклист, audit роли, аудит trace-id, ограничения rate-limit на ingress |
|
||||
| **CHANGELOG.md** | 🟢 low | Сейчас изменения видны только через git log. Для consumer'ов нужен structured changelog с breaking changes |
|
||||
| **Релизная политика** | 🟢 low | semver для bundle vs schemaVersion vs Maven version. Сейчас не описана |
|
||||
|
||||
### 3.3. Inline-источники (читаются как docs)
|
||||
|
||||
- `git log --oneline ordinis-app/` — история архитектурных решений в commit messages
|
||||
- JavaDoc / TSDoc на ключевых классах (~70% покрытия)
|
||||
- TanStack Router file-based routing — структура UI самодокументируется
|
||||
- Liquibase changelog'и в `ordinis-migrations/src/main/resources/db/changelog/changes/` — история DB-схемы
|
||||
|
||||
---
|
||||
|
||||
## Резюме
|
||||
|
||||
- **Функционально v0.5 MVP покрывает 21 из 33 требований v1**, недостающее — operational (observability, backup, runbook), а не feature-уровня.
|
||||
- **Архитектурный фундамент готов** для масштабирования до 30+ справочников и 5+ consumer'ов.
|
||||
- **Главный риск** — отсутствие auto-unseal Vault и DR-плана. Для prod stand-up — критично.
|
||||
- **Документация интеграторов готова** (Swagger + 2 markdown). Документации для operations и end-users — недостаточно.
|
||||
|
||||
**Прогноз до prod-ready (v1):** ~2-3 недели при текущем темпе, при условии что Альтум-интеграция отвалидирована на staging до prod cutover.
|
||||
@@ -0,0 +1,195 @@
|
||||
# Состояние разработки НСИ (Ordinis ЦУОД ОДХ)
|
||||
|
||||
**Версия:** v0.9 (anchor v1 — close-out этап, prod readiness в работе)
|
||||
**Дата:** 2026-05-06
|
||||
**Owner:** zimin.an@nstart.space
|
||||
**Окружения:** staging (192.168.100.161 / cluster.265, ✅ STABLE), prod (192.168.100.142 / cluster.142, 🟡 hibernated)
|
||||
**Предыдущий snapshot:** [2026-05-05-state.md](./2026-05-05-state.md) (v0.5)
|
||||
|
||||
---
|
||||
|
||||
## 0. Что изменилось с v0.5
|
||||
|
||||
Крупные блоки за последние сутки:
|
||||
|
||||
**Stability:**
|
||||
- CNPG operator 1.24.1 → **1.25.4** (server-side apply через manifest, не helm). Дало `spec.probes` API → выставили liveness 15s/30s × 5 + stopDelay 60s. Закрыло хронические cascade failures когда single-node постгрес умирал под нагрузкой от parallel rolling deploys.
|
||||
- **Config-server startupProbe** + bumped probe timeoutSeconds (5 → 10s). Spring Boot startup до 134с под нагрузкой больше не убивается liveness'ом.
|
||||
- **CI helm armored**: `--atomic --cleanup-on-fail --wait --timeout 8m` + pre-step авто-rollback застрявших `pending-*` releases. Сегодня помогло trigger восстановиться от vault-injector-induced cascade без ручного `helm rollback`.
|
||||
- **Migrate Job hardened**: hook-delete-policy включает `hook-failed`, `activeDeadlineSeconds: 600`, ttl 1h. Job в ImagePullBackOff больше не держит CPU request 4 часа подряд (incident 2026-05-05).
|
||||
|
||||
**Observability:**
|
||||
- **Spring Boot percentiles-histogram** на `http.server.requests` с custom SLO buckets (5ms..5s). Без них `histogram_quantile()` в Grafana был пустой.
|
||||
- **2 Grafana дашборда** (sidecar auto-discovery via label `grafana_dashboard=1`):
|
||||
- `ordinis-overview` — request rate, error rate, latency p50/p95/p99, up статусы
|
||||
- `ordinis-slo` — error budget burn rate (5m/1h/6h/24h), 30d budget remaining
|
||||
- **SLO burn rate alerts** (Google SRE Workbook multi-window/multi-burn-rate):
|
||||
- read-api 99.9% (43m бюджет/30d): BurnFast 14.4× × 5m+1h, BurnSlow 6× × 30m+6h, BurnTicket 3× × 2h+1d
|
||||
- writer 99.5% (3.6h/30d): аналогично, чуть свободнее
|
||||
- **ServiceMonitor label `release: monitoring`** — без него kube-prometheus-stack игнорирует SM. Добавили в helper, плюс PodMonitor для CNPG.
|
||||
- **Tempo retention 48h → 168h (7d)**, pool tuning, global_overrides — для full-week investigation traces.
|
||||
- **Loki compactor** с `retention_enabled=true`, ingestion limits — спасает PVC от bloat.
|
||||
|
||||
**UI:**
|
||||
- **Scope-based grouping** в списке справочников: секции PUBLIC → INTERNAL → RESTRICTED + цветные accent-полосы слева у карточек (emerald/amber/rose). Search фильтрует across all sections.
|
||||
- **Scope accent на detail page**: top stripe 4px цветом scope + colored chip в breadcrumb рядом с back-link.
|
||||
- **Поиск + счётчик активных записей** на странице списка справочников (через `useDeferredValue` + N+1-safe `countActiveGroupedByDictionary`).
|
||||
- **INTERNAL словари visibility fix**: `ORDINIS_AUTH_ROLES_CLAIM` теперь читает `resource_access.ordinis.roles` (Keycloak client-роли), не `realm_access.roles` (default). Маппинг `ordinis:client:internal` → INTERNAL уже работал в `ScopeContext`.
|
||||
- **revisionHistoryLimit=3** на всех Deployment в чарте — было 49 stale ReplicaSets.
|
||||
- **Pre-existing TS errors fixed** — `pnpm tsc --noEmit` зелёный (5 ошибок: unused imports, missing prop type, `$schema` field).
|
||||
|
||||
**Data:**
|
||||
- **Bundle 7 → 40 справочников** (cuod v1.2.0). Закрыло раздел item 28 из v0.5.
|
||||
- **Альтум pull verified** — внешний integration работает (item 22 → ✅).
|
||||
|
||||
**Production prep (планирование, не deployed):**
|
||||
- `cluster-prod.yaml` (3-instance HA с synchronous replication, 90d retention, podAntiAffinity required)
|
||||
- `scheduled-backup-prod.yaml` (daily 02:30 UTC + Weekly Sunday 04:00 UTC)
|
||||
- `docs/runbooks/postgres-multi-instance-deploy.md` — sister runbook
|
||||
- `docs/runbooks/cnpg-backup-s3-prod.md` — Selectel/Yandex S3 setup, IAM policy, ExternalSecret, Prometheus alerts (BackupFailed + WalArchiveStale)
|
||||
- `k8s/benchmark/k6-read-api.js` + `k6-job.yaml` + `README.md` — Pareto 80/20 (records.list/dictionaries.list/record.byKey), JWT через `ordinis-bench` Keycloak SA, smoke 50 RPS → ramp 1k RPS → sustain 5m. Не запускался ещё.
|
||||
|
||||
---
|
||||
|
||||
## 1. Перечень требований
|
||||
|
||||
### 1.1. Реализовано (production-ready на staging)
|
||||
|
||||
| # | Требование | Статус | Где зафиксировано |
|
||||
|----|--------------------------------------------------------------|--------|---|
|
||||
| 1 | Каталог НСИ ЦУОД ОДХ — единый источник истины | ✅ | bundle `cuod` v1.2.0 (40 справочников) |
|
||||
| 2 | Bitemporal модель (валидное-время + транзакционное-время) | ✅ | `dictionary_records` + `valid_from`/`valid_to` + Hibernate Envers |
|
||||
| 3 | JSON Schema валидация записей (Draft-07) | ✅ | `ordinis-validation` (networknt) |
|
||||
| 4 | i18n поля (RU + EN) с patternProperties | ✅ | `x-localized: true` extension |
|
||||
| 5 | Уникальные поля (бизнес-ключ + произвольные) | ✅ | `x-unique` extension + native query enforcement |
|
||||
| 6 | Авто-derive businessKey из data поля | ✅ | `x-id-source` extension |
|
||||
| 7 | История версий записи + diff | ✅ | `/records/{key}/history` + UI drawer |
|
||||
| 8 | Schema versioning + breaking-change detection | ✅ | `diffSchemas` + Save-block + auto major/minor/patch |
|
||||
| 9 | Аудит-лог (кто, когда, что, IP, trace_id) | ✅ | `audit_log` + `AuditLogger` + UI `/audit` + CSV export |
|
||||
| 10 | Kafka outbox (at-least-once гарантия) | ✅ | `OutboxPoller` + DLQ cap (1000 attempts) |
|
||||
| 11 | Idempotency для мутирующих запросов | ✅ | `Idempotency-Key` header + sha-256 hash |
|
||||
| 12 | Multi-scope доступ (PUBLIC / INTERNAL / RESTRICTED) | ✅ | `DataScope` + JWT roles + Kafka per-scope topics |
|
||||
| 13 | Keycloak OIDC (issuer-uri auto-discovery) | ✅ | `ordinis-auth` + `JwtDecoders.fromIssuerLocation` + `resource_access.ordinis.roles` |
|
||||
| 14 | Visual schema builder + CRUD UI (scope-grouped, search, counts) | ✅ | admin-ui (React 19 + TanStack + @nstart/ui) |
|
||||
| 15 | SSO для admin-ui (PKCE Public client) | ✅ | react-oidc-context |
|
||||
| 16 | Bundle import (idempotent seed) | ✅ | `CuodBundleImporter` startup runner |
|
||||
| 17 | Swagger UI / OpenAPI 3 spec | ✅ | springdoc на `/swagger-ui.html` |
|
||||
| 18 | **40 справочников** + 51+ запись на staging | ✅ | bundle v1.2.0 (закрытие item 28 из v0.5) |
|
||||
| 19 | Friendly error responses (409/400/404 вместо 500) | ✅ | `GlobalExceptionHandler` |
|
||||
| 20 | Метрики Prometheus + actuator/health + percentiles-histogram | ✅ | `ordinis_outbox_*`, `ordinis_kafka_*`, `http_server_requests_seconds_bucket` |
|
||||
| 21 | Тесты | ✅ | 24 backend + 51 frontend + 34 новых = **109 unit-тестов**, все зелёные |
|
||||
| 22 | **Real consumer integration (Альтум)** | ✅ | Pull verified 2026-05-05/06, БFF (FastAPI) подключился |
|
||||
| 25 | **Distributed tracing (Tempo) на staging** | ✅ | OpenTelemetry → Tempo OTLP gRPC, 7d retention |
|
||||
| 27 | **SLO + alerts (Prometheus)** | ✅ | 4 burn rate alerts (Google SRE multi-window), 2 Grafana dashboards |
|
||||
| 34 | **CI auto-rollback при failure** | ✅ | helm `--atomic --cleanup-on-fail` + pre-step pending-* recovery |
|
||||
| 35 | **CNPG operator 1.25.4** (spec.probes API) | ✅ | стабильность под нагрузкой, нет cascade failures |
|
||||
| 36 | **Loki compactor + retention enforcement** | ✅ | PVC bloat защита |
|
||||
|
||||
### 1.2. В работе / required для v1 closure
|
||||
|
||||
| # | Требование | Статус | Прогресс с v0.5 / Блокер |
|
||||
|----|-----------------------------------------------------------|--------------|--------|
|
||||
| 23 | DNS A-record + Let's Encrypt cert на prod | 🔴 | DNS не проброшен на prod IP, prod hibernated. Нет изменений. |
|
||||
| 24 | `ORDINIS_AUTH_REQUIRED=true` на prod | 🔴 | Зависит от готовности SSO admin-ui на prod + Альтум. |
|
||||
| 26 | CNPG backup в S3 + DR rehearsal | 🟡 ready | **Манифесты + runbook готовы** (`cluster-prod.yaml`, `scheduled-backup-prod.yaml`, `cnpg-backup-s3-prod.md`). Не запущено: ждёт provider creds (Selectel default) + Vault path. |
|
||||
| 28 | 30+ справочников ЦУОД ОДХ (full coverage) | ✅ | **Закрыто** — bundle 1.2.0 содержит 40. |
|
||||
| 29 | Operator runbook | 🟡 70% | **Добавлены** `postgres-multi-instance-deploy.md`, `cnpg-backup-s3-prod.md`, `k8s/benchmark/README.md`. Остаётся: рестарт Kafka StrimziPodSet, разбор DLQ, рестарт outbox-loop. |
|
||||
| 30 | e2e API тесты (testcontainers) | 🔴 | Только unit. Нет изменений. |
|
||||
| 31 | Component тесты frontend (RTL) | 🔴 | Только pure-logic. Нет изменений. |
|
||||
| 32 | Bundle code-splitting (~660KB gzip) | 🔴 | echarts/lottie/@nstart/ui тянут единый chunk. Нет изменений. |
|
||||
| 33 | Vault auto-unseal | 🟢 deferred | **Сознательно skipped** по решению owner — приоритет prod-deploy. Mitigation: manual unseal runbook. |
|
||||
| 37 | **Multi-instance Postgres prod (HA failover)** | 🟡 ready | `cluster-prod.yaml` + `postgres-multi-instance-deploy.md` готовы. Не applied (ждёт prod stand-up). |
|
||||
| 38 | **Performance benchmark (1k RPS, p99 < 1s)** | 🟡 ready | k6 setup в `k8s/benchmark/`. Не запускался — нужно: создать `ordinis-bench` Keycloak SA → Secret → ConfigMap → `kubectl apply -f k6-job.yaml`. |
|
||||
| 39 | AlertmanagerConfig per-channel webhooks | 🔴 | Сейчас 1 webhook (#AltumAlerts) на всё. Нужны URLs для разделения critical / warning / info. |
|
||||
|
||||
### 1.3. v2 (governance / data quality / federation)
|
||||
|
||||
Не блокирует prod stand-up. Roadmap ~2-3 квартала, без изменений с v0.5:
|
||||
|
||||
- Approval workflow (draft → review → publish), ownership trees, RBAC per-dictionary
|
||||
- Lineage / dependency graph
|
||||
- Geo first-class (карта ввода/превью, bbox/polygon query)
|
||||
- Cross-dictionary FK с cascade rules
|
||||
- Data quality rules engine (cross-field constraints, ML-anomaly detection)
|
||||
- Federation MDM-кластеров (master/replica)
|
||||
- Schema registry (Apicurio/Confluent) для Kafka
|
||||
- Webhooks для не-Kafka consumer'ов
|
||||
|
||||
---
|
||||
|
||||
## 2. Нерешённые технические вопросы
|
||||
|
||||
### 2.1. Критические для prod
|
||||
|
||||
1. **Multi-instance Postgres failover.** Single-node CNPG без replica → SPOF. Манифесты + runbook готовы (см. item 37). Apply при prod cutover.
|
||||
2. **CNPG backup в external S3.** MinIO в кластере = same failure domain. Внешний S3 (Selectel/Yandex) — runbook готов (item 26). RTO < 30m, RPO < 5m по WAL archive interval.
|
||||
3. **Audience валидация JWT.** Сейчас не enforced — принимаем токены от любого клиента в realm `nstart`. Допускает scope-эскалацию. На prod либо включить audience-check, либо мапить `aud=ordinis` через Keycloak Audience Mapper.
|
||||
4. **Outbox poll-interval 1 сек.** При 100+ событиях/сек → 86k+ запросов к Postgres/день. Возможно нужен batch tuning или reactive listener вместо poll.
|
||||
|
||||
### 2.2. Архитектурные открытые вопросы
|
||||
|
||||
5. **Realtime invalidation для consumer'ов.** TTL 5 мин кэша достаточен для v1, но push через Kafka topic `ordinis.cuod.events.*` уже emit'ится — consumer'ам осталось subscribe.
|
||||
6. **Геоданные.** PostGIS включён, но bitemporal-выборка по геометрии не реализована. Нужно подтверждение от ЦУОД что геопоиск нужен в v1 или v2.
|
||||
7. **Multi-tenancy.** Anchor `bundle: cuod`. Второй клиент → второй bundle, своя тройка Kafka топиков. Шаринг общих справочников между bundle (например `spacecraft` для ЦУОД и геопортала) не определён архитектурно.
|
||||
8. **Object storage / большие справочники.** Если справочник вырастет до 100k+ записей, JSONB в одной таблице может стать узким. Партиционирование `dictionary_records` по `dictionary_id` — потенциальное решение, требует оценки.
|
||||
|
||||
### 2.3. Operational (выявлено в этой сессии)
|
||||
|
||||
9. **Vault Agent Injector flaky под нагрузкой.** Restarted 68 раз за месяц, last 4m26s ago. Когда injector down — pods создаются БЕЗ vault-agent sidecar → app пишет `cannot open /vault/secrets/postgres` → CrashLoop. Воркэраунд: `kubectl delete pod` для recreate; долгосрочно — увеличить request resources injector + readinessProbe.
|
||||
10. **CNPG metrics exporter slow queries.** Под нагрузкой parallel deploy `pg_stat_replication` парсится 9-22 секунды → scrape timeout (default 10s) → `up=0` для postgres. Mitigation: dashboard panel переключён на `kube_pod_status_ready` (стабильно). Корень — нагрузка на single-node под docker builds + Spring Boot startups + cnpg exporter одновременно.
|
||||
11. **kube-apiserver TLS handshake timeouts** под нагрузкой (load avg 50+). Транзиентно блокирует kubectl. Mitigation: подождать 10-30s, retry. Долгосрочно — multi-node cluster.
|
||||
12. **Vault-agent-init backoff.** ~3 минут при transient Vault unavailability — слишком долго. Тuning либо переход на CSI Driver.
|
||||
13. **JDK 25 + Mockito inline** несовместим. Перешли на subclass mock-maker. При апгрейде до Java 26 проверить.
|
||||
14. **CI path-filter.** Был костыль. Сейчас все docker jobs запускаются всегда (~30s extra на layer-cache). Можно вернуться к smart-filter когда GitLab variable interpolation в trigger jobs будет надёжной.
|
||||
|
||||
### 2.4. Compliance / правовые
|
||||
|
||||
15. **Audit retention policy.** `audit_log` пишется бессрочно. По регламенту ЦУОД нужно определить срок хранения (5/10 лет) + автоматическую архивацию. Блокер: legal deadline.
|
||||
16. **Personal data handling.** В audit_log пишется `user_id` (Keycloak sub) + IP. ФЗ-152 — нужна оценка / DPA если в realm будут не-сотрудники.
|
||||
17. **Электронная подпись изменений.** Если потребуется юридически значимая фиксация (КЭП оператора при close записи) — отдельный модуль, не реализован.
|
||||
|
||||
---
|
||||
|
||||
## 3. Наличие технической документации
|
||||
|
||||
### 3.1. Создана и актуальна
|
||||
|
||||
| Документ | Назначение | Расположение |
|
||||
|---|---|---|
|
||||
| **API integration guide** | Гайд для интеграторов | `docs/tech/api-integration.md` |
|
||||
| **Альтум integration ТЗ** | Согласованный план «Заказ съёмки» | `docs/integration/altum-imaging-order.md` |
|
||||
| **OpenAPI 3 spec (Swagger)** | Машиночитаемая спецификация | `https://ordinis.k8s.265.nstart.cloud/swagger-ui.html` + `/v3/api-docs` |
|
||||
| **Bundle manifest + schemas** | JSON Schema каждого справочника | `ordinis-cuod-bundle/src/main/resources/bundles/cuod/` |
|
||||
| **Postgres multi-instance deploy** 🆕 | Runbook апгрейда staging single → prod 3-instance HA | `docs/runbooks/postgres-multi-instance-deploy.md` |
|
||||
| **CNPG backup → external S3** 🆕 | Selectel/Yandex провижининг, IAM policy, ExternalSecret, Prometheus alerts | `docs/runbooks/cnpg-backup-s3-prod.md` |
|
||||
| **k6 benchmark** 🆕 | Pareto 80/20 setup, preflight, regression tracking | `k8s/benchmark/README.md` |
|
||||
| **CI/Helm values** | Параметризация per-env | `ordinis-infra/charts/ordinis/{values,values-staging,values-prod}.yaml` |
|
||||
|
||||
### 3.2. Отсутствует / требует написания
|
||||
|
||||
| Документ | Приоритет | Прогресс |
|
||||
|---|---|---|
|
||||
| **Operator runbook (full)** | 🔴 high | 70%: добавлены postgres-multi-instance + cnpg-backup. Остались: Kafka StrimziPodSet рестарт, DLQ-разбор, outbox-loop рестарт, vault unseal, поднятие hibernated prod. |
|
||||
| **DR plan** | 🔴 high → 🟡 partial | Backup runbook готов с RTO/RPO targets. Quarter restore drill в operations calendar — не настроен. |
|
||||
| **Архитектурный обзор (HLA)** | 🟡 medium | Single-pager не написан. |
|
||||
| **User docs / справка оператора** | 🟡 medium | Не написана. |
|
||||
| **Threat model + security review** | 🟡 medium | OWASP-чеклист не пройден. |
|
||||
| **CHANGELOG.md** | 🟢 low | git log + commit messages. |
|
||||
|
||||
---
|
||||
|
||||
## Резюме
|
||||
|
||||
**Прогресс v0.5 → v0.9:**
|
||||
- **27 из 39 требований v1 закрыто** (было 21/33). Прирост: items 18 (40 справочников), 22 (Альтум), 25 (tracing), 27 (SLO/alerts), 28 (full coverage), 35 (CNPG), 36 (Loki) + 3 новых item (CI auto-rollback, multi-instance ready, perf benchmark ready).
|
||||
- **Архитектурный фундамент остаётся прочным**, добавлены защиты от cascade failures.
|
||||
- **Главный риск**: prod stand-up зависит от DNS/cert (item 23) + multi-instance Postgres apply (item 37) + S3 creds (item 26). Все имеют готовые runbooks.
|
||||
- **Документация**: prod-deploy artifacts готовы (postgres HA + S3 backup + k6 benchmark). Остаётся operator runbook completion + threat model.
|
||||
|
||||
**Прогноз до prod-ready (v1):** ~1-2 недели при текущем темпе. Блокеры — прежде всего внешние (DNS, S3 provider creds, ЦУОД real data). Inside-team задачи — 3-5 дней работы на code-splitting + e2e tests + AlertmanagerConfig.
|
||||
|
||||
**Что сегодня закрыло прошлые риски:**
|
||||
- Хроническая нестабильность под нагрузкой → CNPG 1.25 + config-server probes + CI atomic.
|
||||
- Observability vacuum → 4 burn rate alerts + 2 dashboards + 7d Tempo.
|
||||
- INTERNAL словари невидимые → rolesClaim fix.
|
||||
- Stuck helm releases → CI pre-step recovery + migrate Job hook-failed.
|
||||
Reference in New Issue
Block a user