81c959b7e2
Закрыло за сутки: 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 файл оставлен как историческая запись.
158 lines
16 KiB
Markdown
158 lines
16 KiB
Markdown
# Состояние разработки НСИ (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.
|