Учебный кейс для портфолио. Мастерская «Срез» вымышленная: адрес, телефон и цены придуманы.

Проект показывает связку, которую сейчас часто заказывает малый бизнес: сайт, который приводит клиентов, и магазин прямо внутри Telegram, где заказ оформляется за пару минут, а статус приходит в чат.
Небольшой цветочной мастерской нужно было:
Три части, которые работают вместе:
| Часть | Что делает |
|---|---|
Лендинг (landing/) |
Рассказывает о мастерской, показывает букеты недели и живую демо-витрину, ведёт в бота |
Mini App (miniapp/) |
Витрина внутри Telegram: каталог, корзина, выбор дня и интервала, оформление, мои заказы |
Бот и API (bot/) |
Принимает заказы, проверяет их, отправляет флористу карточку с кнопками статусов и сообщает клиенту о каждом шаге |

art.js): какие цветы, сколько, какого цвета, какая упаковка. Никаких проблем с правами на картинки, а витрина и лендинг всегда показывают один и тот же букет.<details> без JavaScript.miniapp/catalog.json, поэтому цены на сайте и в витрине не расходятся.

/start с кнопкой «Выбрать букет», кнопка витрины в меню чата, /orders, /contacts, /help./today и /tomorrow: заказы на день по интервалам.Защита и надёжность
Стек: Python 3.11+, aiogram 3, aiohttp, aiosqlite, pytest; HTML, CSS и JavaScript без фреймворков и сборки.
bot/tests/: бизнес-логика и цены, подпись Telegram (сверяется с эталонной реализацией aiogram), база с гонкой за последнее место, всё API, диалог бота через подменённую сессию Telegram и статические файлы.cd bot
pip install -r requirements.txt
pytest
Лендинг и витрина работают как обычные статические страницы. Из корня проекта:
python -m http.server 8000
Откройте http://localhost:8000/landing/. Витрину в демо-режиме можно открыть и отдельно: http://localhost:8000/miniapp/.
cloudflared tunnel --url http://localhost:8080
Он выдаст адрес вида https://…trycloudflare.com.
bot/ скопируйте .env.example в .env и заполните:
BOT_TOKEN — токен от BotFather;ADMIN_IDS — свой Telegram id (его покажет @userinfobot);WEBAPP_URL — адрес туннеля с /app/ в конце.cd bot
python -m venv .venv
source .venv/bin/activate # на Windows: .venv\Scripts\activate
pip install -r requirements.txt
python -m app.main
/start со своего аккаунта: появится кнопка «Выбрать букет», а у флориста — команды /today и /tomorrow.Бот и витрина работают в одном процессе: сервер отдаёт витрину по адресу /app/ и API по /api/.
В landing/script.js впишите BOT_USERNAME (имя бота без @) и при желании MANAGER_USERNAME для вопросов о подписке. Пока они пустые, кнопки «Заказать» ведут к демо-витрине на странице. Каждая кнопка передаёт боту свою метку (?start=site_hero, site_footer), чтобы было видно, откуда пришёл клиент.
Всё в одном файле: miniapp/catalog.json. Там же интервалы доставки, число курьеров, стоимость доставки и порог бесплатной доставки. Сервер проверяет каталог при запуске и сообщит, если в нём ошибка.
art.js лежит в двух папках, miniapp/ и landing/, чтобы каждую можно было выложить отдельно. Если меняете рисунки, скопируйте файл в обе: тест напомнит, если копии разойдутся.
srez/
├── landing/ лендинг: index.html, styles.css, script.js, art.js
├── miniapp/ витрина: index.html, app.css, app.js, art.js, catalog.json
├── bot/
│ ├── app/
│ │ ├── main.py запуск бота и веб-сервера
│ │ ├── api.py API для витрины
│ │ ├── handlers.py диалог бота и кнопки флориста
│ │ ├── logic.py проверка заказа, цены, интервалы, статусы
│ │ ├── initdata.py проверка подписи Telegram
│ │ ├── db.py заказы в SQLite
│ │ ├── notify.py сообщения флористу и клиенту
│ │ ├── texts.py тексты бота
│ │ ├── keyboards.py кнопки
│ │ ├── catalog.py чтение каталога
│ │ └── config.py настройки из .env
│ └── tests/ 81 тест
└── docs/ картинки для README и Behance
Бот хранит имена, телефоны и адреса. В реальном проекте нужно согласие на обработку персональных данных и политика конфиденциальности, а база не должна быть доступна снаружи. Файл .env и базу *.db нельзя выкладывать в публичный репозиторий, они уже в .gitignore.