Архітектура 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.
Зв'язки¶
Потоки взаємодії¶
Запис клієнта¶
/start → головне меню → «Записатися»
→ вибір послуги (FSM: service)
→ вибір дати (FSM: date)
→ вибір часу (FSM: time)
→ коментар/підтвердження (FSM: note)
→ create_booking() → статус pending
→ сповіщення всім адмінам
Обробка адміном¶
/admin → Замовлення → вкладка «Нові»
→ відкрити замовлення
→ Підтвердити / Виконати / Скасувати / Видалити
→ зміна статусу + автосповіщення клієнту (notify_user)
Генерація слотів¶
Слоти не зберігаються в базі, а обчислюються на льоту (app/services.py):
available_dates()— від сьогодні наhorizon_daysуперед, лишаються тільки дні тижня зworking_days.available_times()— діапазонwork_start..work_endіз крокомslot_step_min, мінус уже зайняті слоти (pending/confirmed), мінус час, що вже минув сьогодні.slot_is_free()— перевірка перед створенням запису, щоб уникнути гонки/подвійного бронювання.
Завдяки цьому зміна графіка миттєво впливає на доступні слоти без міграцій.
Керування доступом¶
Адміністратор визначається функцією is_admin(db, telegram_id, username), яка перевіряє:
ADMIN_IDSз.env;ADMIN_USERNAMESз.env;- список
admin_usernames/admin_idsу таблиціsettings(додані з панелі); - роль
adminу таблиціusers.
Адмін-роутер захищений фільтром IsAdmin, що застосовано і до повідомлень, і до колбеків,
тож жоден адмін-хендлер не спрацює для звичайного користувача.
Ключові рішення¶
- Один процес, одна база. Простота розгортання; SQLite у режимі WAL дозволяє безпечні одночасні читання/записи.
- Слоти на льоту. Немає потреби заздалегідь матеріалізувати розклад.
- Налаштування як key-value (JSON). Гнучке розширення без зміни схеми.
- FSM для діалогів. Чисті багатокрокові сценарії (запис, додавання послуги, графік).
- Безпечне редагування повідомлень (
safe_edit) ігнорує помилку «message is not modified».