No description
  • TypeScript 50.2%
  • Svelte 48.2%
  • CSS 0.9%
  • Dockerfile 0.3%
  • JavaScript 0.3%
Find a file
grechkagk f2e92d8752 fix: support image processing on legacy CPUs
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.
2026-10-21 14:13:26 +03:00
.vscode chore: initial project setup 2026-10-06 00:38:47 +03:00
bot feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
drizzle feat: add regional order flow and Telegram group notifications 2026-10-12 23:28:52 +03:00
image feat: add regional catalog and media management 2026-10-07 00:18:11 +03:00
src fix: support image processing on legacy CPUs 2026-10-21 14:13:26 +03:00
static feat: refine admin tables reports and error pages 2026-10-12 22:05:51 +03:00
.dockerignore feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
.env.example feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
.gitignore feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
.npmrc chore: initial project setup 2026-10-06 00:38:47 +03:00
.prettierignore feat: add database schema and authentication 2026-10-06 10:50:21 +03:00
components.json chore: initial project setup 2026-10-06 00:38:47 +03:00
compose.prod.yaml feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
compose.yaml chore: initial project setup 2026-10-06 00:38:47 +03:00
Dockerfile fix: support image processing on legacy CPUs 2026-10-21 14:13:26 +03:00
drizzle.config.ts chore: initial project setup 2026-10-06 00:38:47 +03:00
eslint.config.js chore: initial project setup 2026-10-06 00:38:47 +03:00
IDEAS.md chore: initial project setup 2026-10-06 00:38:47 +03:00
package.json fix: support image processing on legacy CPUs 2026-10-21 14:13:26 +03:00
pnpm-lock.yaml fix: support image processing on legacy CPUs 2026-10-21 14:13:26 +03:00
pnpm-workspace.yaml fix: bundle sharp binaries for production 2026-10-21 13:41:17 +03:00
prettier.config.js chore: initial project setup 2026-10-06 00:38:47 +03:00
raw.md chore: initial project setup 2026-10-06 00:38:47 +03:00
README.md feat: prepare storefront for production deployment 2026-10-21 13:05:21 +03:00
shell.nix fix: support image processing on legacy CPUs 2026-10-21 14:13:26 +03:00
tsconfig.json chore: initial project setup 2026-10-06 00:38:47 +03:00
vite.config.ts feat: add regional catalog and media management 2026-10-07 00:18:11 +03:00

Табачная контора

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;