feat: align LegacyHUB with TeamHUB platform contract (D2/D4, assets, security)
Close 12 audit-driven platform-compliance gaps on a single branch. - D4 dispatch: app/integrations/dispatch_client.py participant `legacyhub`, emits LegacyhubDocumentIndexed + AssetDerivativeReady after the indexing commit (idempotent uuid5), http_inbox route (reindex/tombstone) with audit-based dedupe; docs/dispatch-contract.md. Celery+Redis stays intra-module. - D2 SSO: app/integrations/identity.py validates X-TeamHub-* + role/scope mapper; security.py adds trusted-header enforcement (AUTH_REQUIRE_IDENTITY) and a scope check on /search; docker-compose.teamhub.yml (external teamhub_net + internal db net, api not host-published); RUNBOOK network/firewall section. - Asset standard: SearchHit/Citation carry asset_id/owner_module; buckets renamed teamhub-legacyhub-* (+quarantine/tmp/exports); purge-by-asset_id with legal-hold guard (app/indexing/projection.py); OCR-markdown derivative event. - audit_log model + Alembic 0003 + record_audit on writes (same transaction). - Secret masking: app/common/json_logger.py recursive mask wired into structlog (+ensure_ascii=False); event payloads redacted before persistence. - Service X-API-Key mandatory on ingest endpoints (defence-in-depth). - Port: host API 8000->8050 (collision with SalesHUB/MailHUB resolved), container still listens on 8000. - Config: no plaintext secret defaults; fail-loud in non-dev (no value leak). - Docs drift: README PG 5440, layered-auth note, 5173 removed from CORS; ingest/folder gated by ENABLE_FOLDER_INGEST (410 by default). - ADRs: layers mapping, shared-core extraction, UI locale (RU-first). Tests: 78 passing (ruff, compileall, pytest, tsc, vite build, compose config). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
71
docs/ADR-shared-core.md
Normal file
71
docs/ADR-shared-core.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# ADR: Extract OCR / Markdown / Search into a shared `teamhub_core` engine
|
||||
|
||||
Status: accepted (staged) · 2026-06-15 · scope: `legacy-knowledge-indexer` + `TeamHUB/Engines`
|
||||
|
||||
## Контекст
|
||||
|
||||
Платформа (08_DECISIONS D10, CONVENTIONS «Shared engines», plans/LegacyHUB.md §4)
|
||||
требует вынести проверенный пайплайн LegacyHUB (OCR → Markdown → hybrid search)
|
||||
в переиспользуемое **stateless** ядро, чтобы QMS-Hub и MailHUB потребляли его, а
|
||||
не дублировали. LegacyHUB остаётся эталоном и первым потребителем.
|
||||
|
||||
## Решение
|
||||
|
||||
Ядро `teamhub_core` живёт в `C:\Users\manag\TeamHUB\Engines\engines/teamhub_core/`
|
||||
(НЕ в этом репозитории, НЕ в `TeamHUB-Platform`) и потребляется как pinned
|
||||
versioned dependency / git submodule (D10). Извлечение делается поэтапно, чтобы
|
||||
не дестабилизировать работающий эталон; на каждом шаге тесты зелёные.
|
||||
|
||||
### Границы ядра (stateless)
|
||||
|
||||
| Пакет ядра | Источник в LegacyHUB | Содержимое |
|
||||
|---|---|---|
|
||||
| `ingest` | `app/ingestion/{ocr,docling_extractor,chunker,normalizer,quality,table_processor,figure_processor}.py` | OCRmyPDF, Docling, chunker, quality-flags, нормализация (сохранение ГОСТ/ID) |
|
||||
| `search` | `app/indexing/{embeddings,reranker,hybrid_search,opensearch_client,qdrant_client}.py` | BGE-M3, reranker, `run_search`=RRF(BM25,dense)+rerank, bootstrap индексов |
|
||||
| `storage` | `app/storage/{minio_client,artifacts}.py` | put/get + retry, `ensure_artifact` |
|
||||
| `contracts` | search/citation Pydantic-типы | контракт поиска/цитирования |
|
||||
| `obs` | `app/common/json_logger.py` | JSON-логи с маскированием (уже app-agnostic) |
|
||||
|
||||
Персистентность (`app/db/*`, Alembic), эмиссия событий, имена бакетов/индексов/
|
||||
коллекций и REST-роуты ОСТАЮТСЯ в модуле.
|
||||
|
||||
## Что уже сделано для расцепления (этот репозиторий)
|
||||
|
||||
- **Имена параметризованы.** `opensearch_index_chunks`, `qdrant_collection_chunks`,
|
||||
все `minio_bucket_*` читаются из `Settings` (env-aliases). Дефолты приведены к
|
||||
платформенному стандарту (`teamhub-legacyhub-*`); потребитель (QMS/MailHUB)
|
||||
переопределяет их через env, не трогая код. Жёстко вшитых `legacyhub-*` имён в
|
||||
логике больше нет.
|
||||
- **`run_search` не зависит от БД.** `app/indexing/hybrid_search.py` импортирует
|
||||
только контракты (`app/api/schemas`), `Settings` и клиентов индексации — слой
|
||||
поиска уже stateless по отношению к Postgres/ORM.
|
||||
- **`obs`-ядро готово.** `app/common/json_logger.py` написан без app-specific
|
||||
импортов и переносится в ядро как есть.
|
||||
- **Плейтменеджмент секретов вынесен из дефолтов** (см. `_enforce_secret_policy`).
|
||||
|
||||
## Остаточные шаги (staged, координируются с QMS/MailHUB)
|
||||
|
||||
1. Создать `Engines/engines/teamhub_core/` с README (public API/CLI, inputs/outputs,
|
||||
profile/config model, команда проверки, release notes) и версионным тегом
|
||||
(`teamhub-core-v0.1.0`).
|
||||
2. Перенести `contracts` (типы поиска/цитирования) из `app/api/schemas` в
|
||||
`teamhub_core.contracts`; `app/api/schemas` ре-экспортирует их для совместимости.
|
||||
3. Перенести `search`/`ingest`/`storage`/`obs` в ядро; `run_search` принимает
|
||||
имена индекса/коллекции/бакетов аргументами/конфигом, а не глобальным
|
||||
`Settings` модуля.
|
||||
4. Переключить LegacyHUB на ядро как pinned submodule; `app/indexing`,
|
||||
`app/ingestion` становятся тонкими адаптерами. Временная vendored-копия — только
|
||||
с задокументированным сроком удаления.
|
||||
5. Контракт-тесты ядра единым сьютом (chunker/quality/hybrid/hashing/duplicates).
|
||||
6. Подключить QMS-Hub (свои бакеты `teamhub-qms-*`, индекс `qms_chunks`, своя PG) и
|
||||
MailHUB (поиск по письмам/вложениям) как вторых потребителей.
|
||||
|
||||
## Последствия
|
||||
|
||||
- Физический вынос затрагивает три репозитория (LegacyHUB, Engines, потребители) и
|
||||
выполняется отдельной скоординированной работой; в этом проходе закрыта
|
||||
**готовность к расцеплению** (параметризация имён, stateless `run_search`,
|
||||
app-agnostic obs-core) и зафиксирован план.
|
||||
- Риск регрессий минимизируется поэтапностью и зелёным тест-сьютом на каждом шаге.
|
||||
|
||||
См. также `docs/ADR-layers.md` (маппинг слоёв) и `docs/dispatch-contract.md`.
|
||||
Reference in New Issue
Block a user