Files
Zimin A.N. bcfb07f547 docs: split integrator guide (Diplodoc) vs internal docs + add build-docs CI
Чёткое разделение audiences:
- docs/ — consumer-facing only, Diplodoc-built. Public contract для
  интеграторов (Альтум, BI, third-party).
- docs-internal/ — operator runbooks, status snapshots, legacy tech pages.
  НЕ в Diplodoc build, НЕ публикуются.

Изменения:
- Move docs/{ops,status,tech} → docs-internal/{ops,status,tech}
- docs/toc.yaml: убраны секции Operations, Архитектура (legacy), Status
- docs/index.md: убран tab "оператор / on-call", focus на integrators
- docs/README.md: rewritten — scope только integrator guide, editorial
  guidelines (no leak internal architecture, stable API contract)
- .yfm: убран явный ignore status/* (теперь не нужно — папка переехала)
- docs-internal/README.md: index для внутренней документации с rationale
  разделения

Scrubbing implementation details из Diplodoc страниц:
- events.md: убраны Strimzi/cluster.142 references, OutboxPoller детали,
  internal alert names (OrdinisOutboxLagHigh, OrdinisOutboxDLQNonEmpty),
  metric names (nsi_outbox_*). Заменены на consumer-observable contract.
- webhooks.md: убраны metric names (nsi_webhook_ssrf_rejected_total),
  alert table (OrdinisWebhookHighFailureRate и т.д.). Retry policy
  переписана на user-side perspective.
- errors.md: убран alert name OrdinisReadApiErrorBudgetBurnFast, Tempo
  endpoint URL, internal connection details.
- x-references.md: OrphanReferenceScanner → general "Ordinis периодически
  детектирует". Убраны metric/alert names. Cascade roadmap без link на
  internal design doc.
- auth.md: убран file path ScopeContext.java.
- bundle-cuod.md: убран Maven module path.
- caching.md: cascade design link заменён на text reference.

CI:
- .gitlab-ci.yml: новый job build-docs (stage: build) — Node 20 alpine,
  pnpm install --frozen-lockfile + pnpm build, artifact docs/_dist на
  неделю. Triggers: auto на docs/**, либо manual web. Готов к follow-up
  pages-deploy job когда host решён.
- Новый pattern .docs-changes для rules.

Build verified clean: 13 HTML pages, 6.9M, no broken links/refs.
2026-05-07 23:27:03 +03:00

16 KiB
Raw Permalink Blame History

Состояние разработки НСИ (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. Архитектурные открытые вопросы

  1. Realtime invalidation для consumer'ов. TTL 5 мин кэша достаточен для v1, но при критичных операциях (закрытие КА за день до запуска) нужен push. Kafka topic nsi.dictionary.changed запланирован на v2 — критичность для consumer'ов оценивается.

  2. Геоданные. В spacecraft.schema есть orbit-параметры, в ground_station — geometry (PostGIS). Но Альтум-задача (заказ съёмки) использует bbox/polygon — bitemporal-выборка по геометрии не реализована. Нужно подтверждение от ЦУОД что геопоиск нужен в v1 или v2.

  3. Multi-tenancy. Сейчас bundle: cuod — anchor customer. Второй клиент → второй bundle, своя тройка Kafka топиков. Но шаринг справочников между bundle (например spacecraft общий для ЦУОД и геопортала) не определён архитектурно.

  4. Object storage / большие справочники. Если справочник вырастет до 100k+ записей (например climate zones), JSONB в одной таблице может стать узким местом. Партиционирование dictionary_records по dictionary_id — потенциальное решение, нужна оценка.

2.3. Operational

  1. Vault-agent-init backoff. ~3 минут при transient Vault unavailability — слишком долго. Нужен tuning либо переход на CSI Driver.

  2. JDK 25 + Mockito inline несовместим. Перешли на subclass mock-maker. При апгрейде до Java 26 проверить.

  3. CI path-filter. Был костыль, рассыпался при односторонних изменениях. Сейчас все docker jobs запускаются всегда (~30s extra на layer-cache). Можно вернуться к smart-filter когда GitLab variable interpolation в trigger jobs будет надёжной.

  4. OTel exporter logs/metrics 404. Tempo на staging принимает только traces, logs/metrics endpoint отсутствует. Pod-логи замусориваются. Либо отключить logs/metrics export, либо поднять Loki/Mimir.

2.4. Compliance / правовые

  1. Audit retention policy. Сейчас audit_log пишется бессрочно. По регламенту ЦУОД нужно определить срок хранения (5 лет? 10 лет?) и автоматическую архивацию.

  2. Personal data handling. В audit_log пишется user_id (Keycloak sub) + IP. ФЗ-152 — нужна оценка / DPA если в realm будут юзеры — не-сотрудники.

  3. Электронная подпись изменений. Если потребуется юридически значимая фиксация изменений справочников (КЭП оператора при 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.