stage 02 system status screen

This commit is contained in:
2026-04-13 21:47:59 +03:00
parent 7565aa485e
commit 9acf1b10e3
5 changed files with 174 additions and 15 deletions

View File

@@ -0,0 +1,91 @@
from __future__ import annotations
import platform
from dataclasses import dataclass
from src.core.constants import APP_NAME, APP_VERSION
from src.core.config import load_settings
@dataclass(slots=True)
class ComponentStatus:
name: str
state: str
details: str
@dataclass(slots=True)
class SystemSnapshot:
app_name: str
app_version: str
app_env: str
python_version: str
os_name: str
timezone_name: str
components: list[ComponentStatus]
def get_system_snapshot() -> SystemSnapshot:
settings = load_settings()
components = [
ComponentStatus(
name="Бот",
state="🟢 работает",
details="Процесс бота запущен и обрабатывает команды.",
),
ComponentStatus(
name="Telegram",
state="🟢 OK",
details="Polling активен, базовая маршрутизация подключена.",
),
ComponentStatus(
name="Биржа",
state="🟡 не подключена",
details="Интеграция с биржей будет добавлена на следующем этапе.",
),
ComponentStatus(
name="База данных",
state="🟡 не подключена",
details="Слой хранения пока только подготовлен структурно.",
),
]
return SystemSnapshot(
app_name=APP_NAME,
app_version=APP_VERSION,
app_env=settings.app_env,
python_version=platform.python_version(),
os_name=f"{platform.system()} {platform.release()}",
timezone_name=settings.tz,
components=components,
)
def build_system_text() -> str:
snapshot = get_system_snapshot()
component_lines = []
for component in snapshot.components:
component_lines.append(
f"{component.state} <b>{component.name}</b>\n"
f"{component.details}"
)
components_block = "\n\n".join(component_lines)
return (
"<b>⚙️ Система</b>\n\n"
"<b>Статус компонентов</b>\n"
f"{components_block}\n\n"
"<b>Окружение</b>\n"
f"- приложение: {snapshot.app_name} {snapshot.app_version}\n"
f"- env: {snapshot.app_env}\n"
f"- python: {snapshot.python_version}\n"
f"- os: {snapshot.os_name}\n"
f"- timezone: {snapshot.timezone_name}\n\n"
"<b>Справка</b>\n"
"/start — стартовый экран\n"
"/menu — показать меню\n"
"/help — открыть системную справку"
)

View File

@@ -1,9 +1,12 @@
from __future__ import annotations
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.types import Message
from src.core.system_status import build_system_text
from src.telegram.keyboards.reply import build_main_menu_keyboard
from src.telegram.menus import MAIN_MENU_TEXT, SYSTEM_TEXT
from src.telegram.menus import MAIN_MENU_TEXT
router = Router(name="start")
@@ -11,19 +14,31 @@ router = Router(name="start")
@router.message(Command("start"))
async def cmd_start(message: Message) -> None:
await message.answer(MAIN_MENU_TEXT, reply_markup=build_main_menu_keyboard())
await message.answer(
MAIN_MENU_TEXT,
reply_markup=build_main_menu_keyboard(),
)
@router.message(Command("menu"))
async def cmd_menu(message: Message) -> None:
await message.answer(MAIN_MENU_TEXT, reply_markup=build_main_menu_keyboard())
await message.answer(
MAIN_MENU_TEXT,
reply_markup=build_main_menu_keyboard(),
)
@router.message(Command("help"))
async def cmd_help(message: Message) -> None:
await message.answer(SYSTEM_TEXT, reply_markup=build_main_menu_keyboard())
await message.answer(
build_system_text(),
reply_markup=build_main_menu_keyboard(),
)
@router.message(F.text == "Меню")
async def menu_shortcut(message: Message) -> None:
await message.answer(MAIN_MENU_TEXT, reply_markup=build_main_menu_keyboard())
await message.answer(
MAIN_MENU_TEXT,
reply_markup=build_main_menu_keyboard(),
)

View File

@@ -1,10 +1,9 @@
import platform
from __future__ import annotations
from aiogram import F, Router
from aiogram.types import Message
from src.core.constants import APP_NAME, APP_VERSION
from src.telegram.menus import SYSTEM_TEXT
from src.core.system_status import build_system_text
router = Router(name="system")
@@ -12,10 +11,4 @@ router = Router(name="system")
@router.message(F.text.in_({"⚙️ Система", "⚙ Система"}))
async def open_system(message: Message) -> None:
runtime_info = (
"\n\n<b>Runtime</b>\n"
f"- app: {APP_NAME} {APP_VERSION}\n"
f"- python: {platform.python_version()}\n"
f"- os: {platform.system()} {platform.release()}"
)
await message.answer(SYSTEM_TEXT + runtime_info)
await message.answer(build_system_text())

View File

@@ -0,0 +1,14 @@
# 0004 — System Screen
## Решение
Сделать `Система` отдельным системным экраном, который показывает не только справку, но и снимок состояния приложения.
## Причины
- это удобно для диагностики
- это удобно для локальной разработки
- это удобно для проверки на Synology
- это закладывает основу для health checks
## Последствия
- справка больше не живет отдельно от системного экрана
- системный экран становится точкой входа для технического контроля проекта

View File

@@ -0,0 +1,46 @@
# Stage 02 — System
## Цель
Сделать раздел `⚙️ Система` реальным центром контроля приложения, а не просто статическим экраном.
## Что добавляется
- сервис `system_status`, который собирает снимок состояния приложения
- единый текст системы, который используется и кнопкой `⚙️ Система`, и командой `/help`
- отображение:
- статуса бота
- статуса Telegram-слоя
- статуса интеграции с биржей
- статуса слоя хранения
- текущего окружения
## Что должен увидеть пользователь
Экран вида:
- Бот: работает
- Telegram: OK
- Биржа: не подключена
- База данных: не подключена
- env / python / os / timezone
## Почему это важно
На следующих этапах сюда будут добавляться:
- ping биржи
- статус WebSocket
- статус БД
- статус Redis
- последние ошибки
- health checks
## Как проверить
1. Запустить бота локально
2. Открыть Telegram
3. Нажать `⚙️ Система`
4. Проверить команду `/help`
5. Убедиться, что экран одинаково полезен из кнопки и из команды
## Commit message
Рекомендуемый commit:
```bash
git commit -m "stage 02 system status screen"
```