Перейти до змісту

Архітектура GlowCRM

Документ описує внутрішню будову системи: компоненти, модель даних, потоки взаємодії та ключові інженерні рішення.

Зміст


Загальний огляд

GlowCRM — монолітний застосунок на Python. Один процес запускає Telegram-бота (aiogram), який обслуговує і клієнтів, і адміністраторів. Стан зберігається у SQLite через SQLAlchemy.

┌──────────────────────────────────────────────────────────┐
│                      Telegram                              │
│   Клієнти ◄────────────► Бот ◄────────────► Адміни         │
└─────────────────────────────┬──────────────────────────────┘
                              │ aiogram (long polling)
                ┌─────────────▼─────────────┐
                │         app.bot           │
                │  ┌─────────┐ ┌──────────┐ │
                │  │ user.py │ │ admin.py │ │  handlers (роутери)
                │  └────┬────┘ └────┬─────┘ │
                │       │  keyboards │       │
                │       │  states    │       │
                │       │  filters   │       │
                └───────┼────────────┼───────┘
                        │  app.services (бізнес-логіка)
                ┌───────▼────────────▼───────┐
                │        app.models          │  SQLAlchemy ORM
                │        app.database        │  engine + сесії (WAL)
                └─────────────┬──────────────┘
                     data/glowcrm.sqlite3

Компоненти

Модуль Відповідальність
app/config.py Завантаження .env, парсинг списків адмінів
app/database.py Engine, сесії, session_scope, ініціалізація, WAL/PRAGMA
app/models.py ORM-моделі та статуси записів
app/seed.py Початкові послуги та налаштування
app/services.py Бізнес-логіка: налаштування, слоти, записи, статистика, адміни
app/bot/main.py Створення Bot/Dispatcher, реєстрація роутерів, polling
app/bot/handlers/user.py Сценарії клієнта
app/bot/handlers/admin.py Адмін-панель
app/bot/keyboards.py Інлайн-клавіатури
app/bot/states.py FSM-стани діалогів
app/bot/filters.py Фільтр IsAdmin
app/bot/utils.py Сповіщення, безпечне редагування, форматування

Модель даних

users

Поле Тип Опис
id int, PK Внутрішній ідентифікатор
telegram_id bigint, unique Telegram ID користувача
username str Telegram username
full_name str Ім'я
phone str Телефон (необов'язково)
role str user або admin
notify bool Чи отримує сповіщення
is_blocked bool Прапорець блокування
created_at datetime Дата реєстрації

services

Поле Тип Опис
id int, PK
name str Назва послуги
description text Опис
duration_min int Тривалість, хв
price float Ціна
color str HEX-колір
emoji str Піктограма
active bool Чи показується клієнтам
sort_order int Порядок сортування

bookings

Поле Тип Опис
id int, PK
user_id FK → users Клієнт
service_id FK → services Послуга
date str YYYY-MM-DD Дата
time str HH:MM Час
status str pending / confirmed / completed / cancelled
note text Коментар клієнта
source str bot / admin
created_at datetime Дата створення

broadcasts

Журнал розсилок: text, sent, total, created_at.

settings

Сховище ключ-значення (JSON у полі value). Ключі: business_name, working_days, work_start, work_end, slot_step_min, horizon_days, bot_welcome, admin_usernames, admin_ids.

Зв'язки

User 1───∞ Booking ∞───1 Service

Потоки взаємодії

Запис клієнта

/start → головне меню → «Записатися»
   → вибір послуги (FSM: service)
   → вибір дати     (FSM: date)
   → вибір часу     (FSM: time)
   → коментар/підтвердження (FSM: note)
   → create_booking() → статус pending
   → сповіщення всім адмінам

Обробка адміном

/admin → Замовлення → вкладка «Нові»
   → відкрити замовлення
   → Підтвердити / Виконати / Скасувати / Видалити
   → зміна статусу + автосповіщення клієнту (notify_user)

Генерація слотів

Слоти не зберігаються в базі, а обчислюються на льоту (app/services.py):

  1. available_dates() — від сьогодні на horizon_days уперед, лишаються тільки дні тижня з working_days.
  2. available_times() — діапазон work_start..work_end із кроком slot_step_min, мінус уже зайняті слоти (pending/confirmed), мінус час, що вже минув сьогодні.
  3. slot_is_free() — перевірка перед створенням запису, щоб уникнути гонки/подвійного бронювання.

Завдяки цьому зміна графіка миттєво впливає на доступні слоти без міграцій.


Керування доступом

Адміністратор визначається функцією is_admin(db, telegram_id, username), яка перевіряє:

  1. ADMIN_IDS з .env;
  2. ADMIN_USERNAMES з .env;
  3. список admin_usernames / admin_ids у таблиці settings (додані з панелі);
  4. роль admin у таблиці users.

Адмін-роутер захищений фільтром IsAdmin, що застосовано і до повідомлень, і до колбеків, тож жоден адмін-хендлер не спрацює для звичайного користувача.


Ключові рішення

  • Один процес, одна база. Простота розгортання; SQLite у режимі WAL дозволяє безпечні одночасні читання/записи.
  • Слоти на льоту. Немає потреби заздалегідь матеріалізувати розклад.
  • Налаштування як key-value (JSON). Гнучке розширення без зміни схеми.
  • FSM для діалогів. Чисті багатокрокові сценарії (запис, додавання послуги, графік).
  • Безпечне редагування повідомлень (safe_edit) ігнорує помилку «message is not modified».