Files
AWatch-rus/docs/DPD_PORTAL_RU.md
T

5.1 KiB

DPD Parallel Portal

detmir-dpd-portal - параллельный gateway-портал DetMir. Он не заменяет текущий detmir-portal, а повторяет его функциональность через отдельный маршрут /dpd/.

Назначение

DPD нужен для безопасной эволюции интерфейса:

  • основной HTML-портал /portal/ остаётся стабильным;
  • /dpd/ работает как полный mirror текущего портала;
  • будущий React/Tauri UI сможет использовать те же API-контракты;
  • новые UI-решения проверяются без cutover и без дублирования бизнес-логики.
  • будущий UI не парсит HTML текущего портала как источник данных.

DPD проксирует:

  • вкладки;
  • API;
  • действия проверки;
  • дела;
  • расследования;
  • markdown/download endpoints;
  • материалы проверки.

DPD gateway сохраняет операторский контекст для симметрии с основным порталом: X-Remote-User, X-Gateway-User, X-Forwarded-*, User-Agent, Referer, Origin, Cookie и Authorization передаются в upstream, hop-by-hop заголовки не передаются. Это нужно, чтобы audit/review/case-действия через /dpd/ фиксировались так же, как через /portal/.

Архитектурное решение

Выбран зрелый путь:

detmir-portal Rust backend
        |
        | stable /api/contracts
        v
current HTML UI  +  DPD mirror  +  future React/Tauri UI

Не используется отдельный экспериментальный UI-фреймворк в production path. Сначала фиксируются API-контракты, тестируется совместимость и только затем добавляется новый frontend.

Запуск

detmir-dpd-portal \
  --bind 127.0.0.1:8722 \
  --upstream-base http://127.0.0.1:8720

Переменные окружения:

  • DETMIR_DPD_BIND;
  • DETMIR_DPD_UPSTREAM_BASE;
  • DETMIR_DPD_TIMEOUT_SECONDS - по умолчанию 60 секунд, чтобы первый холодный /api/reports после рестарта не выглядел как отказ DPD-портала.

Маршруты

  • /dpd/ - полный параллельный mirror текущего портала.
  • /dpd/_dpd/health - health самого DPD gateway.
  • /dpd/preview/ - компактный read-only preview-экран.

API-контракты

Контракты публикует основной detmir-portal, а DPD зеркалирует их:

  • /api/contracts;
  • /api/contracts/openapi.json;
  • /api/contracts/typescript.d.ts;
  • /dpd/api/contracts;
  • /dpd/api/contracts/openapi.json;
  • /dpd/api/contracts/typescript.d.ts.

Правила совместимости:

  • изменения API должны быть additive;
  • клиенты React/Tauri обязаны игнорировать неизвестные поля;
  • optional-поля могут отсутствовать;
  • null не должен ломать UI;
  • breaking changes требуют version bump контракта и отдельного architecture decision;
  • будущий React/Tauri UI не должен парсить HTML текущего портала.

Проверка симметрии

Минимальная проверка на сервере:

systemctl is-active detmir-dpd-portal detmir-portal nginx --no-pager
curl -sS http://127.0.0.1:8722/_dpd/health
curl -sS -o /dev/null -w 'dpd_index=%{http_code}\n' http://127.0.0.1:8722/
curl -sS -o /dev/null -w 'dpd_reports=%{http_code}\n' http://127.0.0.1:8722/api/reports
curl -sS -o /dev/null -w 'dpd_contracts=%{http_code}\n' http://127.0.0.1:8722/api/contracts

Браузерная проверка с ноутбука:

ssh -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
  -N -L 18720:127.0.0.1:8720 <GATEWAY_HOST>

detmir-dpd-portal \
  --bind 127.0.0.1:18722 \
  --upstream-base http://127.0.0.1:18720

DETMIR_PORTAL_SMOKE_URL=http://127.0.0.1:18722/ \
DETMIR_PORTAL_SMOKE_TIMEOUT_MS=70000 \
node scripts/detmir-portal-tabs-smoke.mjs

Ожидаемый результат: ok=true, все вкладки работают, нет JS/API ошибок, абсолютные /portal/... ссылки в HTML/JS переписаны в /dpd/....

Ограничения

  • DPD gateway не добавляет новые бизнес-сущности.
  • DPD gateway не заменяет текущий портал.
  • Данные берутся из существующего портала/API.
  • Новый React/Tauri UI должен появляться поверх контрактов, а не через копирование backend-логики.