Перевести ядро на единый контракт источника
Карточка, очередь и отсев работают с SourceItem (SourceRef + SourceContent); Telegram-поля убраны из домена, персистентности, конвейера и wire, остались только в адаптере приёма. Tenant-миграции пересозданы с нуля. Фронт переведён на generic source/content с просмотрщиком вложений.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Дизайн: единый контракт источника + общий Storage-сервис данных
|
||||
|
||||
Дата: 2026-09-11. Статус: на согласовании (контракт не плодит типы вложений; файлы — в общем Storage).
|
||||
Дата: 2026-09-11. Статус: реализовано в ядре (домен, Storage-сервис, персистентность, конвейер, wire, фронт); адаптер/провайдер telegram-сервиса и Storage-выгрузка — следующие шаги. Контракт не плодит типы вложений; файлы — в общем Storage.
|
||||
|
||||
## 1. Принцип
|
||||
|
||||
@@ -127,3 +127,45 @@ API ядра: `GET /api/cards/{id}/source` → generic контент.
|
||||
6. Frontend: generic источник + универсальный просмотрщик.
|
||||
7. Telegram: адаптер + провайдер исходника (только в telegram-сервисе) + выгрузка в Storage.
|
||||
8. Комментарии: убрать упоминания Telegram из ядра и задачи/этапы — везде.
|
||||
|
||||
## 9. Реализация: зафиксированные сигнатуры
|
||||
|
||||
### Ядро: домен
|
||||
|
||||
- `SourceRefs` (Deal.Modules.Cards/Application/Sources): `Empty`, `DefaultHue = "#666"`,
|
||||
`HueKey = "hue"`, расширения `DedupeKey()` (вид|оригинал|внешний id), `ResolveHue()`.
|
||||
- `CardSnapshot`: вместо `ChannelName/ChannelHandle/ChannelHue/SourceMsg/SourceDialogId/SourceMsgId` —
|
||||
`SourceRef Source` + `SourceContent Content`; `ReceivedAt` остаётся.
|
||||
- `CardDto`: вместо `Channel`/`SourceMsg`/`SourceDialogId`/`SourceMsgId`/прежнего `Source` —
|
||||
`SourceRef Source` + `SourceContent Content`; `ReceivedAtMs` остаётся. `CardChannelDto`/`CardSourceDto` удалены.
|
||||
- `ICardStore.GetCardBySourceAsync(SourceRef source, CancellationToken ct)`.
|
||||
|
||||
### Ядро: конвейер
|
||||
|
||||
- `QueuedMessage { required SourceItem Item; bool Force; }`.
|
||||
- `QueueItemDto { string Id; SourceRef Source; SourceContent Content; string Text; string Status;
|
||||
long MsgAtMs; long QueuedAtMs; bool Force; }` (JsonIgnore на Force).
|
||||
- `RejectRecord { SourceRef Source; SourceContent Content; string Text; long MsgAtMs;
|
||||
string DecidedBy; string Stage; string Reason; string Kw; string? DeterministicId; }`
|
||||
(`DeterministicId = r_{Kind}_{OriginRef}_{ExternalId}`).
|
||||
- `RejectedItemDto`: `Source`/`Content`, `DecidedBy`/`DecidedByLabel` (решение), остальное как было.
|
||||
- `IPipelineStore.ExistsDuplicateAsync(SourceRef source, CancellationToken ct)`.
|
||||
- `PipelineChannelDto` удалён.
|
||||
|
||||
### Схема БД (схема тенанта)
|
||||
|
||||
- Cards: удалить `ChannelName/ChannelHandle/ChannelHue/SourceMsg/SourceDialogId/SourceMsgId`;
|
||||
добавить `SourceKind`, `SourceExternalId`, `SourceOriginRef` (text, для запросов), `SourceJson` (text),
|
||||
`ContentJson` (text), `SourceText` (text). FTS: Title+Summary+SourceText+Contact.
|
||||
- QueueItems: удалить `DialogId/ChannelName/ChannelHandle/ChannelHue/MsgId`; добавить
|
||||
`SourceKey` (text, уникальный ключ дедупа), `SourceJson`, `ContentJson`. `Text/MsgAt/Status/Force/CreatedAt/UpdatedAt` остаются.
|
||||
- RejectedItems: удалить `DialogId/MsgId/ChannelName/ChannelHandle/ChannelHue`; добавить
|
||||
`SourceKey`, `SourceJson`, `ContentJson`. FTS — по `Text`.
|
||||
- Миграции tenant: старые удалить, сгенерировать новый init с нуля (данных нет).
|
||||
|
||||
### Маппинг источника
|
||||
|
||||
- Адаптер Telegram (в ядре — тонкий край приёма): `Kind="telegram"`, `ExternalId=MsgId`,
|
||||
`OriginRef=DialogId`, `DisplayName=ChannelName`, `Extra["hue"]=ChannelHue` (иначе дефолт),
|
||||
`ReceivedAt=msgAt`, `Content.Text=Text`, `Content.Author=ChannelName`.
|
||||
- Дашборды/карточки/конвейер работают только с `SourceRef`/`SourceContent`; Telegram-поля не проходят дальше адаптера.
|
||||
|
||||
Reference in New Issue
Block a user