Create wiki page 'Architecture'
+80
@@ -0,0 +1,80 @@
|
||||
# Architecture
|
||||
|
||||
GM-Relay состоит из нескольких .NET-проектов и общей PostgreSQL БД.
|
||||
|
||||
## Проекты
|
||||
|
||||
- `src/GmRelay.AppHost` — Aspire AppHost. Поднимает PostgreSQL с PgAdmin и запускает bot/web проекты.
|
||||
- `src/GmRelay.Bot` — Worker Service с Telegram long polling, миграциями, планировщиком и вертикальными срезами бота.
|
||||
- `src/GmRelay.Web` — Blazor Server UI для ГМа.
|
||||
- `src/GmRelay.Shared` — общие доменные значения и rendering-код Telegram-сообщений.
|
||||
- `src/GmRelay.ServiceDefaults` — общие Aspire defaults: OpenTelemetry, service discovery, resilience, health checks.
|
||||
|
||||
## Архитектурное решение
|
||||
|
||||
В проекте принят подход Vertical Slice Architecture. Логика бота лежит в `src/GmRelay.Bot/Features/*`, где каждый сценарий содержит свой handler и локальные DTO.
|
||||
|
||||
Причины такого выбора зафиксированы в `docs/adr/0001-use-vertical-slice-native-aot-and-aspire.md`:
|
||||
|
||||
- сценариев немного, отдельный Clean Architecture слой был бы лишним;
|
||||
- зависимости Npgsql и Telegram.Bot стабильны;
|
||||
- Native AOT требует явной регистрации зависимостей и аккуратного SQL-маппинга;
|
||||
- BackgroundService + PeriodicTimer проще и надёжнее Quartz.NET для двух периодических проверок.
|
||||
|
||||
## Поток Telegram updates
|
||||
|
||||
`TelegramBotService` получает updates через long polling и передаёт их в `UpdateRouter`.
|
||||
|
||||
`UpdateRouter` явно маршрутизирует:
|
||||
|
||||
- `/start`, `/help`, `/newsession`, `/listsessions`, `/exportcalendar`;
|
||||
- callback `join_session:<sessionId>`;
|
||||
- callback `cancel_session:<sessionId>`;
|
||||
- callback `delete_session:<sessionId>`;
|
||||
- callback `reschedule_session:<sessionId>`;
|
||||
- callback `reschedule_vote:<yes|no>:<proposalId>`;
|
||||
- callback `rsvp:<confirm|decline>:<sessionId>`;
|
||||
- обычные текстовые сообщения ГМа как ввод нового времени для активного переноса.
|
||||
|
||||
Маршрутизация не использует reflection или assembly scanning.
|
||||
|
||||
## Планировщик
|
||||
|
||||
`SessionSchedulerService` — stateless background service. Он запускается сразу при старте, затем раз в минуту:
|
||||
|
||||
1. Ищет сессии `Planned`, у которых `scheduled_at - 24h <= now()`.
|
||||
2. Вызывает `SendConfirmationHandler` и переводит сессию в `ConfirmationSent`.
|
||||
3. Ищет сессии `Confirmed`, у которых `scheduled_at - 5min <= now()` и `link_message_id IS NULL`.
|
||||
4. Вызывает `SendJoinLinkHandler`.
|
||||
|
||||
Состояние хранится в PostgreSQL, поэтому после рестарта сервис продолжает работу без in-memory очередей.
|
||||
|
||||
## Web UI
|
||||
|
||||
Blazor Server-приложение использует cookie auth и Telegram Login Widget.
|
||||
|
||||
Основные сервисы:
|
||||
|
||||
- `TelegramAuthService` валидирует HMAC-SHA256 подпись Telegram Login Widget и `auth_date`.
|
||||
- `SessionService` читает и обновляет группы/сессии через Dapper.
|
||||
- `AuthorizedSessionService` проверяет, что текущий Telegram ID является ГМом группы.
|
||||
|
||||
Основные страницы:
|
||||
|
||||
- `/login` — вход через Telegram.
|
||||
- `/` — список групп ГМа.
|
||||
- `/group/{GroupId}` — будущие сессии группы.
|
||||
- `/session/edit/{SessionId}` — редактирование названия, времени и ссылки.
|
||||
|
||||
## Shared domain
|
||||
|
||||
`GmRelay.Shared` содержит:
|
||||
|
||||
- `SessionStatus`: `Planned`, `ConfirmationSent`, `Confirmed`, `Cancelled`.
|
||||
- `RsvpStatus`: `Pending`, `Confirmed`, `Declined`.
|
||||
- `MoscowTime`: парсинг и форматирование МСК (`UTC+3`).
|
||||
- `SessionBatchRenderer`: единый renderer для Telegram-сообщения пачки сессий.
|
||||
|
||||
## Диаграммы
|
||||
|
||||
C4-диаграммы хранятся в `docs/c4-system-context.md`. Там описаны system context, container view и component view для `GmRelay.Bot`.
|
||||
Reference in New Issue
Block a user