From de6f82bd00e6dce527599b6d5345d720096801e1 Mon Sep 17 00:00:00 2001 From: Z User Date: Wed, 5 Aug 2026 23:27:35 +0000 Subject: [PATCH] feat: add Docker deployment (Dockerfile, docker-compose, .dockerignore) and update docs - Multi-stage Dockerfile (node:22-slim, bun build, standalone output, non-root) - docker-compose.yml with DB volume, healthcheck, memory limits - .dockerignore to exclude dev artifacts from build context - docs: full deployment guide with docker compose, manual docker, env vars, reverse proxy configs (Caddy/Nginx), update instructions, server requirements - docs: comparison table old (Node.js bot) vs new (Next.js admin) --- .dockerignore | 27 +++++++ Dockerfile | 59 ++++++++++++++ docker-compose.yml | 32 ++++++++ docs/admin-nextjs-guide.md | 160 +++++++++++++++++++++++++++++++++++-- 4 files changed, 270 insertions(+), 8 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d11c998 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +node_modules +.next +.git +git +*.md +db/*.db +db/*.db-journal +tool-results/ +agent-ctx/ +.zscripts/ +screenshot-*.png +keepalive.js +seed-standalone.ts +standalone-server.js +gitea-*.json +*.log +dev.log +server.log +.env +.dev +tests/ +examples/ +mini-services/ +upload/ +download/ +Claude.md +.claude diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1869e00 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,59 @@ +# --- Stage 1: Build --- +FROM node:22-slim AS builder + +WORKDIR /app + +# Install bun for faster installs +RUN npm install -g bun + +# Install dependencies +COPY package.json bun.lock ./ +RUN bun install --frozen-lockfile + +# Copy source +COPY prisma ./prisma/ +COPY tsconfig.json next.config.ts postcss.config.mjs tailwind.config.ts components.json ./ +COPY public ./public/ +COPY src ./src/ + +# Generate Prisma client +RUN npx prisma generate + +# Build Next.js (output: standalone) +RUN npx next build + +# Copy static assets into standalone +RUN cp -r .next/static .next/standalone/.next/ && \ + cp -r public .next/standalone/ + +# --- Stage 2: Production --- +FROM node:22-slim AS runner + +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +# Create non-root user +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +# Copy standalone output +COPY --from=builder /app/.next/standalone ./ + +# Copy static files +COPY --from=builder /app/.next/standalone/.next ./.next + +# Copy Prisma schema for potential migrations +COPY --from=builder /app/prisma ./prisma/ + +# Create db directory +RUN mkdir -p /app/db && chown nextjs:nodejs /app/db + +# Switch to non-root +USER nextjs + +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..14d8d63 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +services: + admin: + build: + context: . + dockerfile: ./Dockerfile + container_name: tg_shop_admin + restart: always + ports: + - "3000:3000" + environment: + # === Обязательные === + - DATABASE_URL=file:/app/db/custom.db + - ADMIN_SECRET=${ADMIN_SECRET:-changeme} + - SUPER_ADMIN_SECRET=${SUPER_ADMIN_SECRET:-changeme_super} + # === ИИ-чатбот (опционально) === + - CHATBOT_API_KEY=${CHATBOT_API_KEY:-} + - CHATBOT_API_ENDPOINT=${CHATBOT_API_ENDPOINT:-https://api.openai.com/v1} + volumes: + # Персистентная база данных + - ./db:/app/db + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 256M + healthcheck: + test: ["CMD", "node", "-e", "const http = require('http'); http.get('http://localhost:3000/api/auth/session', r => { process.exit(r.statusCode === 401 ? 0 : 1) }).on('error', () => process.exit(1))"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 15s diff --git a/docs/admin-nextjs-guide.md b/docs/admin-nextjs-guide.md index 1b30b1f..c3899f6 100755 --- a/docs/admin-nextjs-guide.md +++ b/docs/admin-nextjs-guide.md @@ -243,18 +243,162 @@ model Lead { - Оператор видит всю историю переписки - При отключении — бот снова отвечает -## Docker (ARM) +## Развертывание (Docker) + +### Сравнение со старой версией + +| | Старая (Node.js бот) | Новая (Next.js админка) | +|---|---|---| +| Dockerfile | `FROM node:22`, `npm install`, `CMD node src/index.js` | Multi-stage build, standalone output, non-root user | +| docker-compose | 1 сервис, BOT_TOKEN + ADMIN_IDS | 1 сервис, ADMIN_SECRET + CHATBOT_API_KEY | +| БД | `./db/shop.db` (sqlite3 напрямую) | `./db/custom.db` (через Prisma ORM) | +| Порт | Нет (только TG webhook) | 3000 (веб-интерфейс + API) | +| RAM | ~64 MB | ~256–512 MB | + +### Быстрый старт (docker compose) ```bash -docker build -t tg-admin . -docker run -p 3000:3000 -v ./db:/app/db \ - -e ADMIN_SECRET=your_secret \ - -e SUPER_ADMIN_SECRET=super_secret \ - -e CHATBOT_API_KEY=sk-xxx \ - tg-admin +# 1. Клонировать ветку +GIT_LFS_SKIP_SMUDGE=1 git clone -b feat/nextjs-admin https://git.softuniq.eu/Telegram-Market/telegram-shop.git +CD telegram-shop + +# 2. Создать .env файл +cat > .env << 'EOF' +ADMIN_SECRET=your_admin_password +SUPER_ADMIN_SECRET=your_super_admin_password +CHATBOT_API_KEY=sk-your-openai-key # опционально, для ИИ-бота +CHATBOT_API_ENDPOINT=https://api.openai.com/v1 # или другой провайдер +EOF + +# 3. Создать папку для БД +mkdir -p db + +# 4. Собрать и запустить +COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose up -d --build + +# 5. Дождаться запуска (15-30 сек) +docker compose logs -f ``` -Требования: минимум 512 МБ RAM, ARM64/ARMv7/x86_64. +После запуска админка доступна на `http://:3000`. + +### Ручной Docker (без compose) + +```bash +# Сборка +docker build -t tg-shop-admin . + +# Запуск +docker run -d \ + --name tg_shop_admin \ + --restart always \ + -p 3000:3000 \ + -v $(pwd)/db:/app/db \ + -e ADMIN_SECRET=your_admin_password \ + -e SUPER_ADMIN_SECRET=your_super_admin_password \ + -e CHATBOT_API_KEY=sk-xxx \ + -m 512m \ + tg-shop-admin +``` + +### Переменные окружения + +| Переменная | Обязательна | По умолчанию | Описание | +|---|---|---|---| +| `DATABASE_URL` | Нет | `file:/app/db/custom.db` | Путь к SQLite БД внутри контейнера | +| `ADMIN_SECRET` | **Да** | `changeme` | Пароль для роли admin | +| `SUPER_ADMIN_SECRET` | Нет | — | Пароль для роли super_admin | +| `CHATBOT_API_KEY` | Нет | — | API-ключ для ИИ-бота (OpenAI/DeepSeek/etc) | +| `CHATBOT_API_ENDPOINT` | Нет | `https://api.openai.com/v1` | Endpoint LLM-провайдера | + +### Запуск без Docker (разработка) + +```bash +# Установить зависимости +bun install + +# Инициализация БД +bun run db:push + +# Создать .env +echo 'DATABASE_URL=file:./db/custom.db' > .env +echo 'ADMIN_SECRET=admin123' >> .env +echo 'SUPER_ADMIN_SECRET=superadmin456' >> .env + +# Генерация тестовых данных (опционально) +curl -X POST http://localhost:3000/api/seed/demo \ + -H 'Cookie: admin_token=' + +# Dev-сервер +bun run dev # http://localhost:3000 + +# Production +bun run build # сборка standalone +bun run start # запуск production +``` + +### Первоначальная настройка после деплоя + +1. Открыть `http://:3000` +2. Войти с паролем из `ADMIN_SECRET` +3. Перейти в **Settings** (`#/settings`) — настроить параметры магазина +4. Перейти в **AI Chatbot** (`#/chatbot`) — настроить ИИ-бота: + - Ввести API-ключ и выбрать провайдера + - Настроить системный промпт + - Добавить базу знаний (словарный лексикон) +5. Перейти в **Danger Zone** → **Seed Demo Data** для заполнения тестовыми данными +6. Очистить тестовые данные через **Clear Database** перед продакшеном + +### Обновление + +```bash +# docker compose +git pull +docker compose up -d --build + +# ручной +git pull +docker build -t tg-shop-admin . +docker stop tg_shop_admin && docker rm tg_shop_admin +# повторить docker run ... +``` + +**Важно:** БД хранится в volume `./db`, она сохраняется при пересборке. + +### Требования к серверу + +| Ресурс | Минимум | Рекомендуется | +|---|---|---| +| CPU | 1 ядро | 2 ядра | +| RAM | 256 MB | 512 MB | +| Диск | 500 MB (образ) + БД | 1 GB | +| Архитектура | x86_64, ARM64 | — | + +### Reverse Proxy (Caddy / Nginx) + +**Caddy** (авто HTTPS): +``` +admin.yourdomain.com { + reverse_proxy localhost:3000 +} +``` + +**Nginx**: +```nginx +server { + listen 443 ssl; + server_name admin.yourdomain.com; + # ... ssl certs ... + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` ## Seed-данные