Zimin A.N.
930df5b888
feat(api): Swagger UI + docs/integration для Альтума и других consumer'ов
...
Springdoc-openapi генерирует OpenAPI 3 spec из аннотаций контроллеров —
интеграторам не нужно поддерживать markdown-ТЗ синхронно с кодом.
- /swagger-ui.html (UI), /v3/api-docs (JSON), /v3/api-docs.yaml.
- OpenApiConfig: title/description/contact/servers (staging+prod+local),
bearerAuth security scheme (Keycloak JWT).
- SecurityConfig: permitAll на swagger paths.
Документация:
- docs/integration/altum-imaging-order.md — ТЗ интеграции «Заказ съёмки».
Согласованы: m2m service account через Keycloak, BFF в altum-backend
(FastAPI), 4 справочника со схемами, cascading select через
instrument.supported_*_codes, snapshot strategy для аудита.
- docs/tech/api-integration.md — общий гайд для интеграторов: auth flow,
endpoints, кэш-стратегии, bitemporal модель, current dictionaries,
cross-refs, best practices.
Скрипты codegen openapi-generator-cli работают off /v3/api-docs.
2026-05-04 15:45:09 +03:00
Александр Зимин
6ee7a70ad1
feat(auth): JWT scope authorization (@nstart/auth контракт)
...
Новый модуль ordinis-auth:
- OrdinisAuthProperties — public-key, issuer, requireAuthentication, allowQueryScope
- ScopeContext — резолвит current scopes из JWT claim 'scopes' (приоритет),
потом legacy ?as_scope=, потом anonymous=PUBLIC
- SecurityConfig — Spring Security OAuth2 Resource Server + RSA public-key
decoder. Если public-key пуст — JWT validation отключён (permissive
fallback); rollout без auth-сервера не ломает API.
Read controller теперь делегирует scope resolution в ScopeContext вместо
прямого парсинга ?as_scope=. Backward compat: legacy query параметр
работает пока ordinis.auth.allow-query-scope=true (по умолчанию true в
dev/staging, false в prod после интеграции с @nstart/auth).
Vault: public-key читается из secret/ordinis/cuod/jwt-public-key (key=key).
Spring Cloud Vault flatten'ит в property 'key', resolved в
ordinis.auth.public-key=${key:}.
2026-05-04 00:28:27 +03:00
Zimin A.N.
be77c30687
feat(validation,rest-api,outbox): write-side end-to-end working
...
ordinis-validation:
- ValidationError, ValidationResult, ValidationException
- RecordValidator: networknt JSON Schema (Draft-7) + custom rule для
x-localized полей. Walk schema, для каждого x-localized:true property
проверяет: значение это object с locale keys (BCP 47 pattern xx-XX),
все ключи в supported_locales, default_locale обязательно присутствует,
значения non-empty strings.
ordinis-outbox:
- KafkaTopicResolver: ordinis.<bundle>.events.<scope>
- OutboxRecorder: запись события в outbox в той же транзакции (MANDATORY
propagation), с tracer для trace_id/span_id из MDC если OTel доступен
- OutboxPoller: @Scheduled, batch_size + poll_interval из config, метрики
ordinis_outbox_published_total / publish_errors_total / kafka_publish_duration_seconds
- OutboxLagGauge: ordinis_outbox_pending_events (gauge для алертов)
- ConditionalOnProperty ordinis.outbox.enabled — отключаем в read-api/projection-writer
ordinis-rest-api:
- DTOs: CreateDictionaryRequest, DictionaryResponse, CreateRecordRequest,
RecordResponse (с WKT serialization geometry)
- DictionaryDefinitionService: CRUD definitions, outbox events DefinitionCreated/Updated
- DictionaryRecordService: bitemporal write-side, SERIALIZABLE isolation,
bound check FAR_FUTURE valid_to. Update = close current + create new
(никогда in-place). Outbox event RecordCreated/Updated/Deleted.
- DictionaryDefinitionController: GET list/by-name, POST create, PUT update
- DictionaryRecordController: GET active/history, POST create, PUT update,
DELETE (close)
- OrdinisException + ApiErrorResponse + GlobalExceptionHandler
(422 validation, 404 not found, 409 conflict, 500 internal)
ordinis-app:
- @EnableJpaRepositories + @EntityScan для multi-package сканирования
- application.yml profile-based: dev (PG localhost через port-forward,
ddl-auto=update, OTel disabled), k8s (Cloud Config + Vault Kubernetes auth)
- spring.kafka producer config с SASL SCRAM-SHA-512
ordinis-domain:
- JpaAuditingConfig: добавлен DateTimeProvider возвращающий OffsetDateTime
(Spring Data Auditing по дефолту его не поддерживает, без него падает
IllegalArgumentException 'Cannot convert LocalDateTime to OffsetDateTime')
- @ConditionalOnBean(DataSource) убран — race с lifecycle ломал auditing
E2E test (port-forward к cluster PG+Kafka):
- POST dictionary 'ground_station' → 201, JSONB schema сохранена,
supported_locales = {ru-RU, en-US}, default_locale = ru-RU
- POST record MOSCOW-1 multi-locale name + geometry POINT(37.618 55.751) → 201
- POST record с en-US без ru-RU → 422 с двумя ошибками:
* networknt 'required property ru-RU not found'
* custom 'x-localized.missing_default Default locale ru-RU is required'
- outbox_events: 2 row (DefinitionCreated + RecordCreated), topic
ordinis.cuod.events.public, ключи правильные
- revinfo + dictionary_records_aud: 1 row (Envers tx-time history активен)
2026-05-03 13:04:36 +03:00
Zimin A.N.
a28fd0b352
feat: Maven multimodule scaffolding for Ordinis MDM service
...
- 10 модулей (domain, validation, events-api, outbox, rest-api, app, read-api, projection-writer, cuod-bundle, migrations)
- Parent pom + BOM с Spring Boot 3.4.2, Spring Cloud 2024.0.0, Vault Config 4.2.0
- ordinis-app: Spring Boot main с Actuator/Prometheus/Logstash JSON encoder/OpenTelemetry/Cloud Config/Vault skeleton
- ordinis-migrations: Liquibase changelogs (dictionary_definitions/records, audit_log, outbox_events, idempotency_keys, EXCLUSION CONSTRAINT через btree_gist)
- Multi-stage Dockerfiles для app и migrations
2026-05-03 00:41:53 +03:00