# Как устроен Tablo Flask-приложение с фабрикой `create_app`, блюпринтами и сервисным слоем. База — PostgreSQL (структура расписания хранится в JSON-поле), миграции — Flask-Migrate (Alembic). ``` app/ __init__.py фабрика приложения, расширения (SQLAlchemy, Migrate, Login, CSRF) config.py настройки из окружения access.py права: владелец или редактор по ссылке models/ User, Schedule, SubjectConfig, Metric, Share, ShareEditor routes/ auth, schedules, subjects, shares, export services/ ai_scan.py распознавание расписания по фото (vision-модель) ai_metrics.py генерация трекера по текстовому запросу merge.py слияние нескольких расписаний schedule_helpers.py разбор периодов, сборка дня и недели export.py PNG и версия для печати через Playwright/Chromium templates/, static/ migrations/ ревизии Alembic tests/ pytest на PostgreSQL ``` ## Формат расписания `Schedule.data` — список предметов. У предмета — типы занятий (лекция, практика…), у типа — цвет и периоды, в периоде — слоты `[день, время, аудитория, преподаватель]`: ```json [ { "subject": "Базы данных", "types": { "Лекция": {"color": "blue", "dates": {"01.09-31.12": [["понедельник", "09:00-10:30", "АВ-301", "Смирнова Е.А."]]}} } } ] ``` Период `ДД.ММ-ДД.ММ` может переходить через Новый год (`01.09-03.01`), «Весь период» — без ограничений. Время сортируется как число, поэтому `9:00` и `09:00` равнозначны. ## Распознавание и трекеры `ai_scan.py` отправляет фото и подробный системный промпт в OpenAI-совместимый API и разбирает ответ в JSON указанного формата. `ai_metrics.py` по запросу вида «8 лабораторных и экзамен» подбирает тип трекера и его настройки. Ошибки провайдера пишутся в лог, пользователь видит общее сообщение. Типы трекеров: контрольные точки, накопление баллов, счётчик, этапы, чеклист, посещаемость, оценки с весами, дедлайны, серия дней, трудозатраты, история оценок. Трекеры лежат на сетке из 12 колонок, положение и размер сохраняются. ## Доступ | Кто | Что может | |---|---| | владелец | всё, включая экспорт и удаление | | редактор (добавлен в ссылку на редактирование) | просматривать и править по id, экспортировать | | любой со ссылкой на просмотр `/shared/` | только смотреть, без входа | | вошедший пользователь со ссылкой-шаблоном | получить копию расписания себе | Проверка прав — одна функция `app/access.py`. Формы защищены CSRF (Flask-WTF), пароли хранятся в виде хешей Werkzeug, переход после входа (`?next=`) — только внутри сайта.