- TypeScript 50.2%
- Svelte 48.2%
- CSS 0.9%
- Dockerfile 0.3%
- JavaScript 0.3%
Replace sharp with sandboxed ImageMagick commands from Debian security packages, preserving resize, WebP conversion, upload limits, and accent color extraction without requiring SSE4.2 or WebAssembly SIMD. |
||
|---|---|---|
| .vscode | ||
| bot | ||
| drizzle | ||
| image | ||
| src | ||
| static | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| .prettierignore | ||
| components.json | ||
| compose.prod.yaml | ||
| compose.yaml | ||
| Dockerfile | ||
| drizzle.config.ts | ||
| eslint.config.js | ||
| IDEAS.md | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| prettier.config.js | ||
| raw.md | ||
| README.md | ||
| shell.nix | ||
| tsconfig.json | ||
| vite.config.ts | ||
Табачная контора
SvelteKit-приложение, PostgreSQL и Telegram-бот на grammY.
Первый запуск
Установите зависимости и создайте локальный файл окружения:
pnpm install
cp .env.example .env
В .env обязательно замените OWNER_USERNAME и OWNER_PASSWORD. Логин состоит из 3–32 латинских букв, цифр, _ или -. Пароль владельца должен содержать не менее 12 символов.
Запустите PostgreSQL, примените миграции и один раз создайте владельца:
docker compose up -d db
pnpm db:migrate
pnpm db:seed
После этого можно запустить сайт и бота одновременно:
pnpm dev:all
Отдельно сайт и бот запускаются командами pnpm dev и pnpm bot:dev.
Вход в панель расположен по адресу /admin/login. Публичной регистрации сотрудников нет: владелец создаёт администраторов и продавцов в разделе /admin/employees.
Production в Coolify
Для production используется compose.prod.yaml. Он собирает единый Node-образ и запускает три сервиса:
web— SvelteKit на внутреннем порту3000;bot— grammY-бот с long polling;db— PostgreSQL, доступный только внутри Docker-сети.
Миграции и идемпотентное создание владельца выполняются перед каждым запуском web. PostgreSQL и изображения сохраняются в volumes pgdata и images.
В Coolify создайте приложение из приватного Git-репозитория со следующими параметрами:
Build Pack: Docker Compose
Branch: main
Base Directory: /
Docker Compose Location: /compose.prod.yaml
Назначьте домен https://zhizha.grechkagk.com сервису web на внутренний порт 3000. Сервисы bot и db не должны иметь публичных доменов или опубликованных портов.
Добавьте в Coolify runtime-переменные:
POSTGRES_USER=zhizha
POSTGRES_PASSWORD=<длинный случайный пароль>
POSTGRES_DB=zhizha
DATABASE_URL=postgresql://zhizha:<тот же пароль>@db:5432/zhizha
BOT_TOKEN=<токен BotFather>
APP_URL=https://zhizha.grechkagk.com
OWNER_NAME=Владелец
OWNER_USERNAME=owner
OWNER_PASSWORD=<пароль не короче 12 символов>
BODY_SIZE_LIMIT=42M
Для пароля PostgreSQL удобно использовать openssl rand -hex 32: такой пароль не требует URL-кодирования внутри DATABASE_URL. TELEGRAM_PROXY_URL на VPS не задавайте, если сервер подключается к Telegram напрямую.
До первого деплоя DNS-запись A для zhizha.grechkagk.com должна указывать на VPS, а TCP-порты 80 и 443 должны быть открыты. После деплоя проверьте:
https://zhizha.grechkagk.com/api/health
https://zhizha.grechkagk.com/admin/login
Первый адрес должен вернуть {"status":"ok"}. После проверки загрузите тестовое изображение, выполните повторный деплой и убедитесь, что изображение сохранилось. Настройте резервное копирование обоих volumes: volume сам по себе не является бэкапом.
Telegram-бот
Добавьте BOT_TOKEN в .env, затем запустите:
pnpm bot:dev
Необязательная настройка прокси описана в bot/README.md.
Для рабочих кнопок укажите APP_URL. Добавьте бота в группу региона, выполните там /chatid и сохраните полученный ID в разделе «Регионы и точки». Бот отправляет в эту группу новые заказы, назначения и изменения статуса.
Заказы
В режиме разработки главная страница работает без Telegram от имени демо-клиента. Она проходит полную цепочку: регион → точка встречи → каталог → оплата → резерв. В production создавать заказ может только клиент с проверенной Telegram Mini App-сессией.
Авторизация Telegram Mini App
Клиент отправляет неизменённую строку Telegram.WebApp.initData на сервер:
POST /api/auth/telegram
Content-Type: application/json
{"initData":"<Telegram.WebApp.initData>"}
Сервер проверяет HMAC-подпись и срок данных, создаёт или обновляет Telegram-пользователя и устанавливает отдельную HttpOnly-сессию клиента.
Команды базы данных
pnpm db:generate # создать миграцию после изменения schema.ts
pnpm db:migrate # применить миграции
pnpm db:seed # создать владельца, если его ещё нет
pnpm db:studio # открыть Drizzle Studio
Динамические изображения
В PostgreSQL хранятся метаданные, а сами файлы — в каталоге IMAGE_STORAGE_PATH. По умолчанию для локальной разработки это ./image. Загрузки внутри неё игнорируются Git.
При запуске без Docker на VPS укажите абсолютный постоянный путь:
IMAGE_STORAGE_PATH=/var/lib/zhizha/uploads
BODY_SIZE_LIMIT=42M
PROTOCOL_HEADER=x-forwarded-proto
Процессу сайта нужны права на запись в этот каталог. Его нужно резервировать вместе с PostgreSQL. JPEG, PNG и WebP проверяются по содержимому, очищаются от метаданных и сохраняются в WebP. Лимит исходного файла — 5 МБ.
В Docker Compose используется /app/image, подключённый к постоянному volume images; вручную создавать каталог на VPS не требуется.
pnpm db:seed один раз импортирует OWNER_AVATAR_PATH как аватар владельца. Затем аватары можно менять в профиле и в разделе сотрудников.
В Nginx нужно передавать реальный протокол, иначе Node-адаптер отклонит POST-формы как межсайтовые:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;