SaaS-мониторинг Telegram: ядро (модули Cards/Kanban/Pipeline/Tenants/Settings/ Discovery, Api, Infrastructure), сервисы telegram/ai/ml/storage, фронт Vue, контракты и grpc-hosting, деплой-конфиги (dev/prod/observability/CI-раннер), Gitea Actions CI, документация (ТЗ, техдок, api-map, код-стайл, планы, бэклог). Текущее состояние: все этапы роадмапа 0–12 закрыты, сборка 5 sln 0/0, тесты 1340/130/52/38/9 зелёные.
6.6 KiB
Дейл — единая модель карточки (unified card)
Исторический документ (дизайн этапа 9, 2026-09-09). Актуальное состояние —
docs/superpowers/STATUS.mdиdocs/technical/Техническая-документация-Дейл.md.
Дата: 2026-09-09 Статус: дизайн согласован с владельцем продукта (в чате), начало реализации. Связанные документы:
docs/spec/ТЗ-дейл-новая-архитектура.md,docs/architecture/2026-09-05-deal-architecture-design.md.
Проблема
Сейчас в системе два «домена» карточек, хотя по смыслу это одна сущность:
Канбан (/api/leads) |
«Выбранные» (/api/projects) |
|
|---|---|---|
| Таблица | Cards |
ProjectCards |
| Контейнер | колонка inbox/board/archive/trash/taken |
стадия planned…finished/rejected |
| «Взять в работу» | col=taken + копия полей в ProjectCards |
создание второй записи |
| Драйвер/карточка | CardDto |
ProjectCardDto |
Переход «лид → проектная карточка» — это клонирование в другую сущность: у карточки меняется id, теряется связность истории, третий вид карточки/дашборда потребует третьей таблицы и третьего конвейера.
Решение (согласовано): карточка — один агрегат во всех дашбордах. Понятие «лид» упраздняется: сообщение из канала — это входные данные, из которых создаётся карточка. «Взял в работу» — это переход карточки в другой контейнер той же доски пространства «Выбранные», а не создание новой записи.
Модель (C#)
Ядро
/// Единственное, что есть у любой карточки.
public interface ICard
{
string Id { get; }
string Title { get; }
ISource Source { get; } // откуда пришла (см. ниже)
}
/// Типизированная проекция для сценариев, которым нужен конкретный источник.
public interface ICard<TSource> : ICard where TSource : ISource
{
new TSource Source { get; }
}
Источники (ISource) — иерархия, а не enum-свойство
ISource— общее:DisplayName,OriginRef,RawPayload,ReceivedAt.- Простые:
ILocalSource,IWebSource,IFileSource. - Сложные:
ITelegramSource(dialogId/messageId/peer/topic),IRowSource(импорт колонки/строки),IApiSource,IAiSource(провайдер+модель+агент),ICompositeSource { Origin, Pipeline[] }.
Модули-роли карточки (опциональные части одного агрегата)
IContentCard (блок «О заявке»), IBudgetedCard, IContactCard, IAttributedCard (стек/грейд/локация — настраиваемые атрибуты тенанта), ICommentableCard, ILinkCard, IFileCard, ITzCard, ITraceableCard (история), IRemindableCard, ILocatedCard (контейнер + prev + isNew).
Вид карточки = композиция модулей, не класс-наследник. Новый дашборд/вид — новая композиция + при необходимости новый модуль.
Контейнеры (общая база колонок/стадий/зон)
public interface IContainer
{
string Id { get; }
string Name { get; }
string Color { get; }
int Order { get; }
IContainerRules? Rules { get; } // фильтры попадания (пользовательские колонки)
IContainerPolicy Policy { get; } // поведение (роль, не enum)
}
Политики: возврат/очистка (корзина 7д, архив 90д), терминальность («Отклонено/Выполнено» — только ручная очистка), «выбранные не попадают в архив дашборда». Отсев пайплайна — не карточка, вне этой модели.
Переходы
Один ICardMover.MoveAsync(card, toContainerId, ctx); правила — в политиках контейнеров и «воротах» между пространствами; побочные эффекты карточка делает через свои модули (ITraceableCard пишет историю, IRemindableCard сбрасывает напоминание, ILocatedCard.IsNew=false).
Терминология
лид, lead→ карточка (card); входное сообщение → сообщение-источник.проектная карточка→ карточка в контейнерах пространства «Выбранные».- «Взять в работу» → переход в контейнер
planned.
Что меняется
- БД: таблицы
Cards+ProjectCards→ однаCards(+ модульные данные); доски и стадии — единый реестр контейнеров; удаляетсяProjectCards, переносLeadCommentsв модуль карточки. - Бэк: модули Kanban и Projects объединяются в один модуль карточки/контейнеров; порты/сервисы/адаптеры/DTO — единые.
- Pipeline: создаёт карточку (не «лид»), кладёт в контейнер по правилам.
- API: единый контракт
/api/cards+/api/containers;/api/leads,/api/projectsупраздняются (фронт переписывается). - Фронт: один state-слайс карточек, один рендер карточки/драйвера, один канбан-компонент.
Границы этапа
Данные тестовые — схема пересоздаётся, миграции данных нет. Вне рамок: Kafka, «третьи» дашборды (архитектура готова), разовые миграции.