# module-09. Наблюдаемость production-like контура > Статус: целевая спецификация наблюдаемости MVP для ВМ1/ВМ2 и отдельного private SigNoz. > Источники: [`README.md`](README.md), [`arch-00-glossary.md`](arch-00-glossary.md), [`arch-01-system-architecture.md`](arch-01-system-architecture.md), [`arch-02-api-contracts.md`](arch-02-api-contracts.md), [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md), [`arch-04-settings-and-content.md`](arch-04-settings-and-content.md), [`arch-05-agent-development-process.md`](arch-05-agent-development-process.md), [`module-01-api-backend.md`](module-01-api-backend.md)–[`module-08-keycloak.md`](module-08-keycloak.md). ## 1. Цели и границы Наблюдаемость должна позволять: - найти пользовательский запрос по `request_id`, `trace_id` или `ux_session_id`; - восстановить путь «frontend → nginx → API → Safety → S3/Open Lines»; - измерять доступность, задержку, ошибки и насыщение каждого сервиса; - обнаруживать backlog, DLQ, circuit open, потерю telemetry и истечение TLS; - расследовать security/audit события без записи PII и секретов; - проверять SLO по данным, независимым от бизнес-логов. Telemetry не является источником бизнес-истины и не влияет на auth, safety verdict или доставку сообщений. Недоступность Collector не должна блокировать запросы. Audit в `han_app` — отдельный durable контур. ## 2. Production-like решение MVP ### 2.1. Обязательный минимум в основном Compose Каждый root Compose (ВМ1 и ВМ2) обязан содержать локальный `otel-collector`. Prometheus/Grafana/Loki/Tempo не обязаны размещаться на application VM. Предпочтительный operable-вариант после выбора backend: 1. приложения на каждой VM экспортируют OTLP gRPC только в свой local `otel-collector:4317`; 2. Collector отправляет telemetry в выбранный удалённый управляемый OTLP backend провайдера; 3. JSON stdout остаётся аварийным локальным журналом Docker с rotation; 4. пока удалённый backend не выбран, допустим архитектурный минимум из arch-03: bounded JSON stdout/platform logs и Collector `debug` exporter с sampling в acceptance; такой режим не считается полноценным production-хранением и не закрывает alerting/SLO. Требуемые возможности удалённого backend: OTLP ingest, поиск traces, PromQL-совместимые или эквивалентные metrics, поиск структурированных logs, alerting, RBAC, retention и TLS. ### 2.2. Самостоятельно размещаемая опция Опциональный Compose profile `observability-local` может включать: - Prometheus — scrape метрик Collector/Redis/Keycloak/nginx exporters; - Grafana — dashboards и alerts; - Loki — логи; - Tempo — traces. Он **не включается по умолчанию на малой VM**: стек требует дополнительной RAM/диска и сам становится объектом backup/monitoring. Для operable local-варианта нужны отдельный volume каждому backend, retention limits, compaction, auth через ops/VPN и отсутствие host ports. Grafana доступна только через отдельный защищённый ops route/VPN, не через публичный `/`. Рекомендуемый минимум VM при local profile: дополнительно 4 vCPU, 8 ГБ RAM и 100+ ГБ SSD сверх приложения; точный размер — после измерения ingest. ## 3. Архитектура Collector ### 3.1. Компоненты ```text backend services ─OTLP gRPC/HTTP─┐ nginx/Redis/Keycloak exporters ──┼─> otel-collector Docker JSON stdout ─filelog───────┘ ├─ OTLP/TLS remote backend ├─ Prometheus endpoint (optional) └─ debug exporter (acceptance only) ``` Collector запускается одним сервисом MVP. При росте разделяется на agent/gateway: локальный agent принимает и буферизует, remote gateway выполняет policy/export. ### 3.2. Receivers - `otlp` gRPC `0.0.0.0:4317` — основной internal receiver; - `otlp` HTTP `0.0.0.0:4318` — совместимость SDK; - `prometheus` — scrape самого Collector, Keycloak metrics, Redis exporter, nginx exporter и сервисных `/metrics`, если они не идут OTLP; - `filelog` — только если Docker logging driver предоставляет read-only каталог/volume; парсит JSON stdout без чтения secret-файлов; - `hostmetrics` — CPU, memory, filesystem, network VM/container host, если Collector получает только необходимые read-only mounts. Порты `4317`, `4318`, `8888`, `8889` используют `expose`, не `ports`. Receiver доступен только в сети `observability`. ### 3.3. Processors и порядок Во всех pipelines первым стоит защита памяти, последним — batch: 1. `memory_limiter`: check interval 1s, soft/hard limit относительно container memory; 2. `resource`: нормализует `service.namespace=han-chat`, `deployment.environment`, `service.version`; 3. `attributes`: удаляет/маскирует sensitive attributes; 4. `transform`: нормализует route/status/error semantic conventions; 5. `filter`: исключает health noise, debug events и запрещённые поля; 6. `probabilistic_sampler` или tail sampling для traces; 7. `batch`: bounded batch/timeout; 8. при remote export — `queued_retry`/sending queue и `file_storage` extension. `memory_limiter` не заменяется Docker OOM limit. При pressure Collector отбрасывает telemetry контролируемо и увеличивает `otelcol_processor_refused_*`. ### 3.4. Exporters - `otlp/remote`: TLS verify, endpoint и auth header из secret env/mount; - `prometheus`: optional pull endpoint только internal; - `debug`: только `APP_ENV=test|acceptance`, verbosity normal; production debug exporter по умолчанию выключен; - `loki`/`otlphttp` — только если выбран backend и его контракт закреплён. Секрет exporter-а не должен появляться в rendered config, логах или `/debug/configz`. Config монтируется read-only; secret подставляется env. ### 3.5. Extensions - `health_check` — internal endpoint, используется Compose; - `pprof`/`zpages` — только при явном ops profile, internal network; - `file_storage` — persistent sending queue на volume `otel-queue`; - `basicauth`/`oauth2client` — если требует remote backend. ### 3.6. Принципиальная конфигурация ```yaml receivers: otlp: protocols: grpc: {endpoint: 0.0.0.0:4317} http: {endpoint: 0.0.0.0:4318} prometheus: config: scrape_configs: - job_name: otel-collector static_configs: [{targets: ["127.0.0.1:8888"]}] processors: memory_limiter: check_interval: 1s limit_mib: 384 spike_limit_mib: 96 resource/common: attributes: - {key: service.namespace, value: han-chat, action: upsert} - {key: deployment.environment, value: "${env:APP_ENV}", action: upsert} attributes/redact: actions: - {key: http.request.header.authorization, action: delete} - {key: http.request.header.cookie, action: delete} - {key: url.query, action: delete} - {key: db.statement, action: delete} filter/noise: error_mode: ignore traces: span: - 'attributes["http.route"] == "/health/live"' batch: send_batch_size: 1024 timeout: 5s exporters: otlp/remote: endpoint: "${env:OTEL_REMOTE_ENDPOINT}" tls: {insecure: false} headers: {authorization: "${env:OTEL_REMOTE_AUTH_HEADER}"} extensions: health_check: {endpoint: 0.0.0.0:13133} file_storage: {directory: /var/lib/otelcol/queue} service: extensions: [health_check, file_storage] pipelines: traces: receivers: [otlp] processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch] exporters: [otlp/remote] metrics: receivers: [otlp, prometheus] processors: [memory_limiter, resource/common, attributes/redact, batch] exporters: [otlp/remote] logs: receivers: [otlp] processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch] exporters: [otlp/remote] telemetry: metrics: {address: 0.0.0.0:8888} ``` Конкретная версия schema проверяется командой Collector `validate`; image закрепляется по digest. Значения memory/batch/queue — стартовые, не SLO. ## 4. Resource attributes и корреляция Обязательные resource attributes: - `service.name`: `nginx`, `api-backend`, `message-safety`, `bitrix-local-app`, `bitrix-sync`, `keycloak`, `redis`, `otel-collector`; - `service.namespace=han-chat`; - `service.version=`; - `deployment.environment=production-like|production`; - `host.name`/`service.instance.id` без публичного IP. Обязательные поля request-события: - `request_id`; - `trace_id`, `span_id`; - `ux_session_id` — nullable, только когда передан; - `service.name`; - `environment` либо canonical `deployment.environment`. `request_id` формирует/валидирует nginx; сервис возвращает его клиенту и передаёт downstream. `trace_id` берётся из active span. `ux_session_id` не является auth и не должен использоваться как metric label. ## 5. W3C propagation - принимаются только валидные `traceparent` и опциональный `tracestate`; - nginx передаёт context в API; при edge instrumentation создаёт server span; - API создаёт child spans для PostgreSQL, Redis, S3, Safety, Open Lines и JWKS; - internal calls передают `traceparent`, `tracestate`, `X-Request-ID`; - `baggage` по умолчанию не принимается от внешнего клиента; если включён, allow-list исключает PII; - Bitrix24/S3 могут не вернуть context: внешний client span всё равно закрывается результатом; - async outbox/inbox связывается span link с исходным trace; новый worker trace не притворяется продолжением спустя долгий срок. Frontend может отправлять валидный `traceparent`, но backend не доверяет его sampling/security атрибутам. ## 6. JSON stdout contract Одна JSON-запись на строку UTF-8: ```json { "timestamp": "2026-07-10T09:00:00.123Z", "level": "INFO", "service.name": "api-backend", "service.version": "git-abcdef0", "environment": "production-like", "module": "message_service", "event": "message.delivery.completed", "message": "Message delivery completed", "request_id": "01J...", "trace_id": "32hex", "span_id": "16hex", "ux_session_id": "uuid-or-null", "route": "/api/v1/dialogs/{dialog_id}/messages", "method": "POST", "status_code": 201, "duration_ms": 742, "dependency": "bitrix-local-app", "outcome": "success", "error_code": null } ``` Правила: - `event` — стабильная mnemonic, `message` — безопасное описание; - route — template, никогда raw URI с id/query; - stack trace допускается только в internal error log после redaction; - message text, callback body, SQL values и file content запрещены; - Docker driver ограничен `50m × 5`, но это buffer, не retention backend; - multiline stack trace сериализуется полем JSON, не отдельными строками. ## 7. Redaction и data minimization Удаляются или маскируются: - `Authorization`, Cookie, Set-Cookie, JWT, OAuth/code/refresh/access tokens; - raw OTP/mock code, Keycloak admin/client password; - phone/email/full name, device id, IP по policy (допустим HMAC/truncated); - message text, filenames с PII, document/file contents; - DSN/password, Redis URL, S3 keys; - presigned URL и любая query string; - Bitrix raw payload/download URL/application token; - `db.statement` с literals; предпочтительно operation/table, не SQL. Redaction выполняется в SDK/logger **до stdout**, затем повторяется Collector processor. Collector не может считаться единственной защитой. Автотесты отправляют canary secrets/PII и требуют отсутствие во всех трёх сигналах. ## 8. Instrumentation по компонентам ### 8.1. FastAPI-сервисы - OpenTelemetry ASGI/FastAPI server spans с route template; - HTTPX client spans с sanitized host/method/status; - SQLAlchemy/asyncpg spans без параметров и raw statement; - Redis instrumentation с command name и DB index, без key/value; - boto/S3 spans: operation/bucket logical name, без object key/query; - background workers: span на claim/process/finalize, links на origin; - исключить `/health/live` из traces; readiness оставить в metrics и sampled logs. ### 8.2. PostgreSQL Собираются pool wait/checked-out, transaction duration, error class, migrations revision, managed PG provider metrics (CPU, storage, connections, locks, replication/PITR state). `user_id`, SQL text и row data не labels. ### 8.3. Redis `redis_exporter` подключается отдельным ACL user только на `INFO`, `PING`, безопасные latency/keyspace metrics. Нужны memory ratio, evictions, expirations, blocked/rejected clients, command latency, AOF status/rewrite, Pub/Sub buffers, key count/TTL агрегаты. Keys/values не экспортируются. ### 8.4. Keycloak Включаются management metrics/JVM/HTTP/DB pool. Custom OTP provider публикует counters send/verify/limit/settings-cache без phone labels. Login events идут в JSON/audit с masked/HMAC destination. Public OIDC synthetic проверяется отдельно. ### 8.5. nginx JSON access log содержит `request_id`, извлечённый `trace_id`, route class, method, normalized path, status, bytes, request/upstream duration/status, TLS version, cache status. `$request` с query не используется. Collector `filelog` parser: - разбирает JSON, timestamp и severity; - переносит `service.name=nginx`; - превращает пустые/`-` в null; - route class нормализует в bounded set; - отбрасывает ACME/health success noise; - не парсит raw URI в labels. Native nginx OTEL module предпочтителен, если image/version закреплены. Без него nginx только передаёт W3C context и коррелирует access log; первый server span создаёт API. ### 8.6. Host/Docker CPU, load, memory/swap, disk usage/inodes/IO, network, container restarts/OOM, Docker daemon health и clock sync. Container name/version — bounded labels; container id не хранится как долгосрочный high-cardinality label. ## 9. Метрики бизнес-потоков ### API и auth - `han_http_requests_total{service,route,method,status_class}`; - `han_http_request_duration_seconds`; - `han_auth_bootstrap_total{outcome}`; - `han_ux_session_start_total{reason}`; - `han_jwks_refresh_total{outcome}`; - `han_rate_limit_decisions_total{scope,outcome}`. ### Message Safety - checks/verdicts по `allow|deny|pending|error`; - `processing_mode`, active/used `config_version`, config activation result, `message_safety_mock_enabled` и forced outcomes по `text|file`/`allow|deny`; - poll duration/count buckets, timeout и recovery backlog age; - stub mode info и terminal `400` отдельно, пока действует test-only контракт; - cache hit, Redis latency, task expired/not-found. ### Open Lines/Bitrix - message submitted → delivered end-to-end latency; - local app outbound result/retry/ambiguous/DLQ; - inbox depth/oldest age/forward retries/duplicate; - OAuth time-to-expiry/refresh result; - connector desired/observed state; - Bitrix 429, circuit state, setup failure. ### Files/S3 - init/complete/promote/delete; - quarantine object age/orphans; - checksum/MIME/size reject; - presigned download issued; - S3 dependency latency/error by operation and logical bucket. ### Frontend synthetic - public config/content; - OIDC discovery/authorization page; - WS handshake; - test-user end-to-end flow в отдельной тестовой identity без реального PII. Никакие UUID/user/session/dialog/task/message id не labels. Они допустимы только в sampled logs/traces при принятой retention. ## 10. Dashboards 1. **Executive/SLO**: availability, error budget burn, p50/p95/p99, message delivery, auth, active incidents. 2. **nginx ingress по VM**: отдельные панели/filters ВМ1 и ВМ2; RPS, 4xx/5xx, upstream latency/status, 429, WS, TLS, cache, CRM webhook на ВМ2. 3. **api-backend**: routes, DB/Redis pools, JWKS, circuits, outbox/safety backlog, S3. 4. **message-safety**: capabilities, verdicts, `202` poll, PG queue age/leases/fencing, ClamAV/signature age, file/link cache и DNS dependency. 5. **bitrix-local-app**: install/OAuth, connector, outbound/inbox/DLQ, API/Bitrix latency. 6. **bitrix-sync**: mode/readiness, queue depth/oldest age, workflow/command transitions, CRM batch latency/subcommand outcome, limiter/throttle, retry/DLQ, webhook/reconciliation lag, mapping invariants и business-alert SLA. 7. **Keycloak**: login/OTP/lockout, sessions/tokens, provider settings cache, JVM/DB. 8. **Redis**: memory/evictions/AOF/latency/clients/keyspace. 9. **PostgreSQL/S3**: provider metrics, storage, connections, backup/PITR, object errors. 10. **Business flow**: guest config → OTP → bootstrap → session → dialog → safety → Open Lines → operator reply. 11. **Collector health**: accepted/sent/refused/dropped, queue, retry, exporter errors, memory/CPU. Каждая панель содержит release annotation, environment filter и links trace→logs по `trace_id`. ## 11. SLI, SLO и alerts Значения — начальная production-like политика до load/product review: | SLI | Initial SLO, 30 дней | |---|---| | HTTPS edge availability | 99.9% | | public config/content successful requests | 99.9% | | protected read API successful requests | 99.5% | | Keycloak login flow availability | 99.5% | | text message accepted и доставлен в Open Lines | 99.0% | | operator inbox applied без permanent loss | 99.5% | | p95 protected read API | < 750 ms | | p95 text send без внешнего rate limit | < 5 s | | telemetry Collector ingest availability | 99.0%, не входит в business availability | Файловый send измеряется отдельно: p95 не должен превышать configured safety poll budget; user-cancel, safety deny, 4xx validation и edge abuse 429 не считаются server failure. 503/504 и unexpected 5xx считаются. ### Paging alerts - multi-window burn: 14.4× за 5m/1h или 6× за 30m/6h; - edge/API 5xx >5% 5 минут; - text delivery failure >5% 10 минут; - oldest outbox/inbox/safety task >5 минут либо DLQ >0; - Keycloak login failures infrastructure class >10% 5 минут; - PostgreSQL unavailable/connection saturation >90%; - Redis unavailable, AOF error или sustained evictions; - Collector exporter queue >80%, dropped/refused telemetry >0 sustained; - TLS expiry <14 дней warning, <7 дней page; - disk >85% warning, >92% page; OOM/restart loop; - managed PG backup/PITR failure. - Message Safety active config missing/invalid, referenced artifact unavailable или config refresh stale >5 с. - `message_safety_mock_enabled=1` — active page/high-severity alert без auto-resolve по времени; закрывается только после возврата в standard. - bitrix-sync invalid/revoked credential или обязательная configuration/grant missing; - bitrix-sync technical DLQ >0, mapping invariant violation или worker/limiter heartbeat stale; - bitrix-sync queue oldest age >30 с при healthy CRM либо sustained рост; - Contact webhook/reconciliation cursor lag выше двух configured intervals. ### Ticket/warning alerts - p95 regression 20% release-over-release; - settings/JWKS cache stale; - bitrix-sync CRM last success stale, rate-limit errors выше baseline или business alert SLA overdue; - OAuth expires <24h без успешного refresh; - quarantine orphan growth; - cardinality/ingest growth >2× baseline. Alert содержит service, environment, symptom, dashboard, runbook, release и безопасный query; не содержит PII. ## 12. Sampling, cardinality и retention ### Traces - errors/5xx, circuit, timeout, DLQ, safety final deny и slow requests — 100%; - обычные успешные requests — 5–10%; - health/ACME success — 0%; - tail sampling предпочтителен в Collector, но head sample SDK должен оставлять достаточно данных; - sampling decision передаётся W3C. ### Metrics Allow-list labels; route template вместо raw path; status class/known code; dependency enum. Cardinality budget: целевой <10 000 active series на MVP environment. CI проверяет запрещённые labels. ### Retention initial - metrics: 30 дней high resolution, 13 месяцев downsampled при доступности backend; - traces: 7 дней, errors 14 дней; - technical logs: 14 дней, security/auth logs 30 дней; - audit `han_app`: 365 дней **только как временное допущение до legal policy**; - raw Bitrix callback не хранится в telemetry; - local Docker logs: не более 250 МБ/container и 5 файлов. Legal retention/erasure имеет приоритет; изменение требует обновления policy и backup lifecycle. ## 13. Collector health и отказоустойчивость Контролируются: - `/health` extension; - process CPU/RSS/restarts; - accepted/refused/sent/failed spans, points, records; - batch send size/latency; - exporter queue capacity/size, enqueue failures, retry age; - file storage usage/corruption; - scrape failures; - config reload/validation. При remote outage queue хранится на `otel-queue` с bounded size/age. При заполнении отбрасываются сначала low-priority success traces/logs; приложение продолжает работу. Нельзя позволять queue заполнить системный диск. ## 14. Docker Compose `otel-collector`: - pinned contrib image; - networks: только `observability`, а для scrape internal targets — минимально необходимая `backend`; - `expose`: 4317, 4318, 13133, 8888/8889; - без host ports; - config read-only, `otel-queue` volume rw; - non-root, read-only rootfs, tmpfs `/tmp`, drop capabilities, no-new-privileges; - перед collector запускается idempotent `otel-queue-init`: one-shot без сети и secrets, с `user: 0:0`, `cap_drop: ALL` и только `CHOWN/FOWNER`, выставляет mount root `10001:10001 0700`; collector зависит от `service_completed_successfully`; - initial limit: 0.5 CPU/512 MiB, queue disk 5–10 ГБ; уточнить load test; - healthcheck extension; - restart policy с backoff; - приложения имеют bounded non-blocking OTLP exporter queue. Collector существует отдельным экземпляром на ВМ1 и ВМ2. Каждый имеет собственный `otel-queue` volume/limits и экспортирует в private SigNoz `192.168.0.5:4317`; ВМ2 никогда не использует Docker hostname collector ВМ1. Telemetry outage/overflow fail-open для business и Safety readiness, но создаёт alert. Новый named volume считается потенциально `root:root`; основной collector не запускается от root и volume не получает `0777`. Ownership init проверяется после первого create и повторного recreate. Доступ к Docker socket запрещён. Для container metrics используется безопасный exporter/hostmetrics, а не unrestricted socket mount. ## 15. Security - OTLP receiver internal-only; при переходе между hosts — mTLS; - remote exporter только TLS verify, credentials least privilege; - Grafana/Prometheus/Loki/Tempo не публичны; - RBAC: viewer/operator/admin; audit доступа к logs/traces; - dashboards не показывают PII; - config/secret permissions 0400/0600; - dependency/image scan и SBOM; - защита от log injection: JSON encoding, control chars, bounded field lengths; - telemetry input не исполняет expressions из пользовательских значений; - регулярная secret-canary проверка и incident deletion procedure. ## 16. Runbooks ### Collector not-ready 1. `docker compose ps otel-collector` и bounded logs. 2. Проверить config validation, memory/OOM, queue volume. 3. Проверить DNS/TLS/auth remote exporter. 4. Не рестартовать бесконечно при полной queue; сначала освободить/расширить безопасно. 5. Бизнес-сервисы оставить работающими; подтвердить local JSON logs. 6. После восстановления проверить drain и gap. ### Telemetry отсутствует у одного сервиса 1. Проверить `service.name`, endpoint/protocol и сеть `observability`. 2. Проверить SDK queue/drop counters и clock. 3. Отправить synthetic request с `X-Request-ID`. 4. Найти его в stdout, Collector accepted и backend. 5. Проверить sampling/filter/redaction rules. ### Remote backend outage 1. Подтвердить exporter errors, а не application outage. 2. Оценить queue fill rate/time-to-full. 3. Ограничить debug exporter; не включать verbose. 4. При длительном outage увеличить sampling только через reviewed config. 5. После восстановления подтвердить drain и создать incident note о потере данных. ### Cardinality/ingest spike 1. Найти новое metric/log attribute по release annotation. 2. Отключить offending instrument/filter в Collector. 3. Проверить raw path/id/user/session labels. 4. Rollback instrumentation при риске стоимости/доступности. 5. Добавить CI regression test. ### Высокая latency сообщения 1. Открыть trace по request id. 2. Разделить API, Safety poll, S3, local app, Bitrix. 3. Проверить circuit, queue age, DB pool и Redis. 4. Не повторять ambiguous message без исходного idempotency key. 5. Следовать runbook зависимого модуля. ### Логи содержат секрет/PII 1. Ограничить доступ и остановить offending export. 2. Сохранить только incident metadata, не копировать значение. 3. Ротировать скомпрометированный secret. 4. Удалить данные по процедуре backend/provider. 5. Исправить source redaction + Collector defense; добавить canary test. ## 17. Проверки и Definition of Done - Collector config проходит validate и запускается в root Compose каждой VM; - OTLP gRPC и HTTP принимают три сигнала; - все сервисы имеют правильные resource attributes; - request проходит nginx/API/Safety/Open Lines с одним `request_id` и связанным trace; - `ux_session_id` есть только где передан и не является label; - FastAPI/HTTPX/PG/Redis/S3 workers instrumented; - nginx JSON parsing и trace correlation проверены; - Redis/Keycloak/host/Collector metrics доступны; - dashboards и alerts provisioned из versioned files для выбранного telemetry backend; до его выбора это остаётся acceptance/TBD, а не выполненный production DoD; - remote outage, queue full, Collector restart и backend recovery rehearsed; - local profile, если включён, имеет volumes/retention/auth и не публикует порты; - secret/PII canary отсутствует в logs/traces/metrics; - cardinality и sampling tests проходят; - SLO queries воспроизводимы и исключения документированы; - runbooks связаны с alerts. ## 18. Допущения, TBD и конфликты ### Решения - O1: обязательный архитектурный минимум — local Collector на каждой application VM; выбран self-hosted SigNoz на отдельной VM `192.168.0.5`, доступный по приватному OTLP gRPC. - O2: Prometheus/Grafana/Loki/Tempo — отдельный operable profile, не скрытая обязательная нагрузка основной VM. - O3: JSON stdout — аварийный локальный buffer; audit App DB — durable. - O4: telemetry fail-open для business path, но потеря telemetry alertится. - O5: ID/PII не labels; source redaction обязательна до Collector. ### TBD - O-TBD1 закрыт: self-hosted SigNoz, `192.168.0.5:4317`, plaintext только внутри доверенной приватной сети; UI через SSH jump host. - O-TBD2: утвердить SLO/RPS/error-budget с product owner. - O-TBD3: legal retention/erasure и допустимость IP/user-agent. - O-TBD4: точные sampling и resource limits после load test. - O-TBD5: поддерживаемый nginx OTEL module и Keycloak native tracing по pinned versions. - O-TBD6: нужен ли local observability profile в первой VM. ### Обнаруженные архитектурные конфликты 1. `arch-03` разрешает stdout/platform exporter как минимум, но production-like расследования и alerts без backend ограничены. Здесь remote OTLP backend рекомендован, но не объявлен выбранным: провайдер остаётся TBD. 2. `module-05` использует test-only terminal `400` и non-sticky verdict вместо canonical `403`/sticky production verdict. Dashboards обязаны маркировать сервис `stub`; production SLO Safety на нём недостоверен. 3. `module-07` задаёт full sync target; до code/portal cutover dashboard обязан показывать `sync_disabled`, а не синтетический CRM success. Queue/CRM SLI включаются только после module-07 preflight. 4. Retention, RPO/RTO и production SLO открыты в module-01/04/06/08; значения этого документа являются initial ops policy, не закрывают legal/product TBD. 5. Observability env (`OTEL_REMOTE_*`, service names, sampling/queue limits) добавлены в arch-04 и `.env.example`; sampling/queue limits уточняются после load test. ## 19. Ссылки на прототип и исходные документы - VM/Docker logging и firewall: [`../../HAN_chat/deploy/setup-vm-han-chat.sh`](../../HAN_chat/deploy/setup-vm-han-chat.sh). - Прототипный nginx stdout/access log: [`../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf`](../../HAN_chat/bitrix-local-app/deploy/nginx/nginx.conf). - Архитектурный observability contract: [`arch-02-api-contracts.md`](arch-02-api-contracts.md). - Compose topology: [`arch-03-docker-compose-blueprint.md`](arch-03-docker-compose-blueprint.md).