8319edda38
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
70 lines
3.6 KiB
Markdown
70 lines
3.6 KiB
Markdown
# ADR 002: Platform-Neutral Batch Rendering
|
|
|
|
## Status
|
|
|
|
**Accepted** — implemented in v1.10.0 (PR #42).
|
|
|
|
## Context
|
|
|
|
`SessionBatchRenderer` жил в `GmRelay.Shared` и напрямую зависел от `Telegram.Bot` (`InlineKeyboardMarkup`, `ParseMode.Html`). Это создавало проблемы:
|
|
|
|
1. **Shared не был platform-neutral.** Любой платформенный проект (Discord, Slack, WebSocket) тащил Telegram-зависимость.
|
|
2. **Дублирование логики.** `GmRelay.Web` использовал тот же рендерер через прямую зависимость от `Shared`, но Web — это не Telegram-клиент.
|
|
3. **Невозможно написать unit-тесты без Telegram-объектов.** Smoke-тесты создавали InlineKeyboardMarkup даже для проверки чисто доменной логики.
|
|
|
|
## Decision
|
|
|
|
Разделить рендеринг на две стадии:
|
|
|
|
1. **View Builder (platform-neutral)** — собирает view model из доменных DTO.
|
|
2. **Platform Renderer (platform-specific)** — превращает view model в платформенное представление.
|
|
|
|
```
|
|
Domain DTOs
|
|
│
|
|
▼
|
|
SessionBatchViewBuilder (Shared)
|
|
│
|
|
▼
|
|
SessionBatchViewModel (platform-neutral)
|
|
│
|
|
├──► TelegramSessionBatchRenderer ──► HTML + InlineKeyboardMarkup
|
|
│
|
|
└──► DiscordSessionBatchRenderer ──► Discord embeds + buttons
|
|
```
|
|
|
|
### Изменённые компоненты
|
|
|
|
| Компонент | Было | Стало |
|
|
|---|---|---|
|
|
| `SessionBatchRenderer` | `GmRelay.Shared.Rendering` | Удалён |
|
|
| `SessionBatchViewBuilder` | — | `GmRelay.Shared.Rendering` |
|
|
| `SessionBatchViewModel` | — | `GmRelay.Shared.Rendering` |
|
|
| `TelegramSessionBatchRenderer` | — | `GmRelay.Bot` + `GmRelay.Web` |
|
|
| `DiscordSessionBatchRenderer` | — | `GmRelay.DiscordBot.Rendering` |
|
|
| `BatchMessageEditor` | `GmRelay.Shared.Rendering` | `GmRelay.Bot` + `GmRelay.Web` |
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
- `GmRelay.Shared` больше не зависит от `Telegram.Bot`. Чистый platform-agnostic проект.
|
|
- Discord renderer lives in `GmRelay.DiscordBot`, so NetCord stays out of `Shared`.
|
|
- Unit-тесты ViewBuilder не создают `InlineKeyboardMarkup`.
|
|
- Логика подсчёта игроков, сортировки сессий и генерации действий — в одном месте (ViewBuilder).
|
|
|
|
### Negative
|
|
|
|
- **Временное дублирование.** `TelegramSessionBatchRenderer` и `BatchMessageEditor` скопированы в `Bot` и `Web`. Планируется вынести в `GmRelay.Shared.Telegram` при появлении третьего Telegram-потребителя.
|
|
- **Дополнительная стадия.** Теперь два вызова вместо одного: `Build` + `Render`. Этоtrade-off за чистоту абстракции.
|
|
|
|
## Related
|
|
|
|
- Issue #22 — этот рефакторинг.
|
|
- Issue #26 — Discord Bot MVP (потребитель новой архитектуры).
|
|
- Issue #30 — Discord reschedule voting использует `IPlatformMessenger`.
|
|
- Issue #31 — scheduler notifications и reschedule deadline updates через `IPlatformMessenger`.
|
|
- Issue #32 — compose wiring для Discord bot (healthcheck :8082).
|
|
- Issue #33 — регрессионные тесты platform rendering (Telegram + Discord).
|
|
- ADR 001 — vertical slice, native AOT, Aspire (`docs/adr/0001-use-vertical-slice-native-aot-and-aspire.md`).
|