Files
GmRelayBot/docs/adr/0001-use-vertical-slice-native-aot-and-aspire.md
T

84 lines
4.2 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-0001: Vertical Slice Architecture, Native AOT, BackgroundService и Aspire
## Status
**Accepted** — 2026-04-03
## Context
GM-Relay — Telegram-бот для автоматизации игровых сессий, развёрнутый на Raspberry Pi (ARM64) за NAT.
Требования к стеку:
- **.NET 10 / C# 14** — целевой рантайм.
- **Native AOT** — минимальный размер бинарника, мгновенный cold start на ARM64.
- **Raspberry Pi 5** — ограниченные ресурсы (4–8 ГБ RAM).
- **Long Polling** — Pi за NAT, webhook невозможен без проброса портов.
Необходимо выбрать: архитектурный паттерн, планировщик задач, ORM и оркестрацию.
## Decision
### 1. Vertical Slice Architecture (VSA)
Каждый use case реализован как **вертикальный срез**: Command/Query record + Handler.
Handler содержит всю логику (SQL, Telegram API, валидацию) — без абстрактных репозиториев и сервисных слоёв.
**Почему не Clean Architecture:**
- Бот с 5–7 use cases не нуждается в 4+ проектах и абстракциях.
- Все зависимости (Npgsql, Telegram.Bot) стабильны — заменять их не планируется.
- VSA позволяет добавлять фичи без рефакторинга существующих.
### 2. BackgroundService + PeriodicTimer (вместо Quartz.NET)
Два триггера расписания (T-24ч: подтверждение, T-5мин: ссылка) реализованы через
`BackgroundService` с `PeriodicTimer(TimeSpan.FromMinutes(1))`.
**Stateless-дизайн:** сервис при каждом тике делает SELECT к PostgreSQL, обрабатывает
найденные сессии и обновляет статус в БД. При перезагрузке — ничего не теряется.
**Почему не Quartz.NET:**
- Quartz.NET **не совместим с Native AOT** (reflection-based job loading).
- Для двух простых WHERE-запросов Quartz — overkill.
- BackgroundService нативно поддерживается .NET и AOT.
### 3. Npgsql + Dapper.AOT (вместо EF Core)
EF Core 10 **не совместим с Native AOT** (reflection-heavy query pipeline, dynamic IL).
Npgsql ADO.NET — полностью AOT-совместим. Dapper.AOT использует source generators
для compile-time генерации маппинга.
Миграции — **DbUp** (embedded SQL scripts).
### 4. Aspire 13 для оркестрации
Aspire обеспечивает:
- Автоматический запуск PostgreSQL в dev-среде.
- Service discovery и передачу connection strings.
- OpenTelemetry (traces, metrics, logs) из коробки.
- Aspire Dashboard для мониторинга.
### 5. Telegram.Bot 22.x + Long Polling
- Long Polling — единственный вариант для Pi за NAT.
- Telegram.Bot поддерживает `System.Text.Json` source generators для AOT.
## Consequences
### Положительные
- **Один бинарник ~15–30 МБ** для ARM64 (Native AOT, self-contained).
- **Мгновенный cold start** (~50ms) на Raspberry Pi.
- **Простота**: каждая фича — один файл, один handler.
- **Устойчивость к перезагрузкам**: stateless scheduler + PostgreSQL.
### Отрицательные
- **Ручной SQL**: нет автогенерации запросов, миграции пишутся руками.
- **Нет LINQ-to-SQL**: все запросы — строки, ошибки только в runtime.
- **DI без reflection**: все handlers регистрируются явно (без assembly scanning).
### Риски
- Dapper.AOT — относительно молодой проект; при проблемах — fallback на чистый Npgsql.
- Telegram.Bot AOT-совместимость может потребовать кастомного `JsonSerializerContext`.