feat(portal): add api contracts for future ui
This commit is contained in:
+82
-25
@@ -1,13 +1,19 @@
|
||||
# DPD/Dioxus Pilot Portal
|
||||
# DPD Parallel Portal
|
||||
|
||||
`detmir-dpd-portal` - параллельный DPD-портал DetMir. Основной режим работает
|
||||
как полный mirror текущего `detmir-portal`, а экспериментальный компактный экран
|
||||
оставлен отдельно как preview.
|
||||
`detmir-dpd-portal` - параллельный gateway-портал DetMir. Он не заменяет
|
||||
текущий `detmir-portal`, а повторяет его функциональность через отдельный
|
||||
маршрут `/dpd/`.
|
||||
|
||||
## Назначение
|
||||
|
||||
Портал не заменяет текущий `detmir-portal`. Он работает рядом с ним и
|
||||
проксирует все функции текущего портала через отдельный маршрут `/dpd/`:
|
||||
DPD нужен для безопасной эволюции интерфейса:
|
||||
|
||||
- основной HTML-портал `/portal/` остаётся стабильным;
|
||||
- `/dpd/` работает как полный mirror текущего портала;
|
||||
- будущий React/Tauri UI сможет использовать те же API-контракты;
|
||||
- новые UI-решения проверяются без cutover и без дублирования бизнес-логики.
|
||||
|
||||
DPD проксирует:
|
||||
|
||||
- вкладки;
|
||||
- API;
|
||||
@@ -17,22 +23,27 @@
|
||||
- markdown/download endpoints;
|
||||
- материалы проверки.
|
||||
|
||||
Компактный experimental preview доступен отдельно и показывает:
|
||||
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/`.
|
||||
|
||||
- главный вывод;
|
||||
- события безопасности;
|
||||
- полнота данных;
|
||||
- риски подразделений;
|
||||
- очередь проверки;
|
||||
- связь рисков и активности.
|
||||
## Архитектурное решение
|
||||
|
||||
## Почему отдельный бинарник
|
||||
Выбран зрелый путь:
|
||||
|
||||
Dioxus 0.7 fullstack использует разделение client/server и отдельные web/server
|
||||
feature flags. Для безопасного первого этапа создан параллельный Rust shell,
|
||||
который не меняет боевой портал, но уже повторяет его функциональность через
|
||||
mirror-proxy. Это оставляет место для постепенного переноса UI на
|
||||
Dioxus-компоненты без риска разъезда данных и API.
|
||||
```text
|
||||
detmir-portal Rust backend
|
||||
|
|
||||
| stable /api/contracts
|
||||
v
|
||||
current HTML UI + DPD mirror + future React/Tauri UI
|
||||
```
|
||||
|
||||
Не используется отдельный экспериментальный UI-фреймворк в production path.
|
||||
Сначала фиксируются API-контракты, тестируется совместимость и только затем
|
||||
добавляется новый frontend.
|
||||
|
||||
## Запуск
|
||||
|
||||
@@ -53,11 +64,57 @@ detmir-dpd-portal \
|
||||
|
||||
- `/dpd/` - полный параллельный mirror текущего портала.
|
||||
- `/dpd/_dpd/health` - health самого DPD gateway.
|
||||
- `/dpd/preview/` - компактный preview-экран для будущего Dioxus-подхода.
|
||||
- `/dpd/preview/` - компактный read-only preview-экран.
|
||||
|
||||
## Ограничения v0.1
|
||||
## API-контракты
|
||||
|
||||
- DPD gateway не добавляет новые бизнес-сущности;
|
||||
- без замены текущего портала;
|
||||
- данные берутся из существующего портала/API;
|
||||
- preview-экран остается read-only.
|
||||
Контракты публикует основной `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-поля.
|
||||
|
||||
## Проверка симметрии
|
||||
|
||||
Минимальная проверка на сервере:
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Браузерная проверка с ноутбука:
|
||||
|
||||
```bash
|
||||
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-логики.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# API-контракты портала DetMir
|
||||
|
||||
## Цель
|
||||
|
||||
Закрепить стабильный слой API для текущего HTML-портала и будущего
|
||||
React/Tauri-интерфейса без переписывания backend-логики.
|
||||
|
||||
Текущий HTML-портал остаётся рабочим и основным. Новый UI должен подключаться к
|
||||
тем же endpoint-ам через documented contract.
|
||||
|
||||
## Контрактные endpoint-ы
|
||||
|
||||
Основной портал:
|
||||
|
||||
- `GET /api/contracts`
|
||||
- `GET /api/contracts/openapi.json`
|
||||
- `GET /api/contracts/typescript.d.ts`
|
||||
|
||||
DPD mirror:
|
||||
|
||||
- `GET /dpd/api/contracts`
|
||||
- `GET /dpd/api/contracts/openapi.json`
|
||||
- `GET /dpd/api/contracts/typescript.d.ts`
|
||||
|
||||
## Правила совместимости
|
||||
|
||||
- Изменения API должны быть additive.
|
||||
- Нельзя удалять существующие поля без отдельной migration window.
|
||||
- Клиенты обязаны игнорировать неизвестные поля.
|
||||
- Клиенты обязаны корректно обрабатывать отсутствующие optional-поля.
|
||||
- Поля с `null` не должны ломать UI.
|
||||
- Ошибки API должны отображаться пользователю на русском языке.
|
||||
|
||||
## Минимальный набор для будущего React/Tauri UI
|
||||
|
||||
Для первого production-grade клиента достаточно:
|
||||
|
||||
- `GET /api/contracts` - discovery и версия контракта;
|
||||
- `GET /api/reports` - главный управленческий payload;
|
||||
- `GET /api/operator` - обзор портала;
|
||||
- `GET /api/incidents` - проверки и события;
|
||||
- `GET /api/cases` - расследования;
|
||||
- `POST /api/incident-review` - ручное решение по кандидату;
|
||||
- `POST /api/cases` - ручное создание дела;
|
||||
- `GET /api/investigation-pack/{candidate_id}` - пакет расследования;
|
||||
- `GET /api/readiness/latest` - готовность системы;
|
||||
- `GET /api/workforce/policy/explain` - объяснение расчёта показателей.
|
||||
|
||||
## Что не меняется
|
||||
|
||||
- HTML-портал не удаляется.
|
||||
- Маршрут `/portal/` остаётся стабильным.
|
||||
- DPD `/dpd/` остаётся параллельным mirror.
|
||||
- Backend-расчёты, JSON-хранилища и workflow не дублируются во frontend.
|
||||
|
||||
## Проверка
|
||||
|
||||
```bash
|
||||
curl -sS http://127.0.0.1:8720/api/contracts | jq .
|
||||
curl -sS http://127.0.0.1:8720/api/contracts/openapi.json | jq .openapi
|
||||
curl -sS http://127.0.0.1:8720/api/contracts/typescript.d.ts | head
|
||||
curl -sS http://127.0.0.1:8722/api/contracts | jq .
|
||||
```
|
||||
|
||||
Ожидаемый результат:
|
||||
|
||||
- `ok=true`;
|
||||
- `contract_version` заполнен;
|
||||
- OpenAPI JSON валиден;
|
||||
- TypeScript declarations доступны;
|
||||
- DPD отдаёт те же контрактные endpoints через mirror.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Архитектурный baseline UI AWatch-rus
|
||||
|
||||
Дата фиксации: 2026-06-05
|
||||
|
||||
## Baseline
|
||||
|
||||
```text
|
||||
Backend/API: Rust
|
||||
Agent: Rust
|
||||
Current Portal: Rust server-rendered HTML + HTMX-ready static UI
|
||||
Future Enterprise UI: React + TypeScript
|
||||
Future Desktop Forensics: Tauri + React + Rust core
|
||||
Dioxus: out of scope / не рассматривается
|
||||
```
|
||||
|
||||
## Правила
|
||||
|
||||
- Текущий HTML/HTMX-ready портал остаётся основным pilot/production
|
||||
интерфейсом.
|
||||
- JSON API является контрактным слоем для будущих UI.
|
||||
- Бизнес-логика не должна зависеть от HTML.
|
||||
- Будущий React/Tauri UI не должен ломать текущий портал.
|
||||
- Agent и backend остаются Rust-first.
|
||||
- Новые UI-фреймворки не добавлять без отдельного architecture decision.
|
||||
- Dioxus не добавлять и не рассматривать.
|
||||
|
||||
## Практическое следствие
|
||||
|
||||
Развитие интерфейса выполняется в таком порядке:
|
||||
|
||||
1. Укрепить текущий Rust web portal.
|
||||
2. Зафиксировать стабильные JSON API-контракты.
|
||||
3. Поддерживать DPD `/dpd/` как параллельный mirror для проверки совместимости.
|
||||
4. Готовить будущий React/Tauri UI только поверх опубликованных контрактов.
|
||||
|
||||
## Контрактный слой
|
||||
|
||||
Основные endpoints:
|
||||
|
||||
- `/api/contracts`;
|
||||
- `/api/contracts/openapi.json`;
|
||||
- `/api/contracts/typescript.d.ts`.
|
||||
|
||||
DPD mirror endpoints:
|
||||
|
||||
- `/dpd/api/contracts`;
|
||||
- `/dpd/api/contracts/openapi.json`;
|
||||
- `/dpd/api/contracts/typescript.d.ts`.
|
||||
|
||||
Правило совместимости: изменения API должны быть additive. Клиенты обязаны
|
||||
игнорировать неизвестные поля и корректно обрабатывать отсутствующие optional
|
||||
поля.
|
||||
Reference in New Issue
Block a user