Files
LegacyHUB/docs/ADR-layers.md
Vadim Malanov d27dd0ffbb 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>
2026-06-15 11:44:15 +03:00

56 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR: Layer mapping LegacyHUB ↔ platform CONVENTIONS
Status: accepted · 2026-06-15 · scope: `legacy-knowledge-indexer`
## Контекст
Платформенный `CONVENTIONS.md` описывает каноничную структуру pattern-B модуля:
```
app/{main, config, db, api, models, repositories, services, integrations, workers}
```
Исторический layout LegacyHUB сложился вокруг доменов обработки (`ingestion`,
`indexing`, `storage`), а не вокруг технических слоёв. Имена папок не совпадают
с конвенцией, но **доменные слои присутствуют**.
## Решение
Не переименовывать рабочие пакеты. Зафиксировать маппинг документально. Перекладка
проверенного OCR/Markdown/Search-кода ради совпадения имён — риск регрессий без
функциональной выгоды (governance: размер/имя изменения не повод для рефактора).
Новые платформенные слои (`integrations/`, аудит) добавлены явно.
| Канон CONVENTIONS | Фактический пакет | Назначение |
|---|---|---|
| `main` | `app/main.py` | FastAPI composition shell, CORS, middleware, lifespan |
| `config` | `app/config.py` | pydantic-settings, единственный читатель env |
| `db` | `app/db/session.py` | engine + `session_scope` транзакция |
| `models` | `app/db/models.py` | ORM (`documents`, `chunks`, `asset_ingest_jobs`, `audit_log`, …) |
| `repositories` | `app/db/models.py` + `app/db/audit.py` + `app/storage/artifacts.py` | data-access; запись `audit_log` на write через `record_audit` |
| `services` | `app/ingestion/*` + `app/indexing/*` | бизнес-пайплайн: OCR → извлечение → chunk → index → search |
| `integrations` | `app/integrations/` (`identity`, `dispatch_client`) | seam к шлюзу/SSO и шине dispatch |
| `workers` | `app/workers/` | Celery app + tasks (внутримодульный фон на Redis) |
| (infra/helpers) | `app/storage/*`, `app/utils/*` | MinIO/S3, hashing, language, pdf, text |
## Аудит на write
`CONVENTIONS` и `03_INTEGRATION_STANDARDS §10` требуют запись в `audit_log` в той
же транзакции, что и мутация. Реализация: `app/db/audit.py::record_audit(db, …)`
вызывается внутри активного `session_scope`. Покрытые write-операции:
- `knowledge_ingest.register_verified_manifest``asset.ingest.registered`
- `routes_ingestion.ingest_folder``ingest.folder.queued`
- (P4) переиндексация и purge проекций → `asset.reindex` / `asset.projection.purged`
## Слой/границы
Соблюдается направление `shell → router → service → repository/infra`. Feature-код
не импортирует composition shell. Кросс-доменные обращения идут через `integrations/`.
## Последствия
- Onboarding-ревьюер сверяет слои по этой таблице, а не по именам папок.
- Будущий вынос `ingestion`/`indexing` в shared-core (см. `docs/ADR-shared-core.md`)
не меняет этот маппинг — ядро становится зависимостью слоя `services`.