# Состояние разработки НСИ (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.