Skip to content

API Deploy

Швидкий деплой

bash
./deploy.sh

Скрипт виконує:

  1. git push pisduk main — пуш коду на сервер
  2. SSH до Hetzner → git pulldocker compose build --no-cachedocker compose up -d

WARNING

Пушимо в pisduk, а не в origin. Це різні GitHub-репозиторії.

Ручний деплой

bash
# Push до деплой-ремоуту
git push pisduk main

# SSH rebuild
ssh -i ~/.ssh/hetzner root@37.27.202.249 \
  "cd /opt/pisd/pisduk && git pull --ff-only && docker compose build --no-cache && docker compose up -d"

Docker Compose

На сервері в /opt/pisd/pisduk/:

yaml
services:
  api:
    build: .
    ports:
      - "3000:3000"
    env_file: .env
    depends_on:
      - postgres
      - redis

  postgres:
    image: postgis/postgis:16-3.4
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

Змінні середовища (.env)

ЗміннаОписЗначення prod
NODE_ENVСередовищеproduction
DATABASE_URLPostgreSQL URLpostgresql://pisd:***@postgres:5432/pisd
REDIS_URLRedis URLredis://redis:6379
JWT_SECRETJWT підписСильний випадковий рядок
JWT_REFRESH_SECRETRefresh JWT підписОкремий сильний рядок
TURBO_SMS_KEYTurboSMS API ключВід провайдера
TURBO_SMS_SENDERВідправник SMSPEACED
CORS_ORIGINSДозволені originhttps://m.pisd.uk,https://admin.pisd.uk,https://partner.peaced.uk
OTP_ALLOW_DEV_CODEDev-escape OTPfalse (ніколи в prod)
R2_ACCOUNT_IDCloudflare R2Від Cloudflare
R2_ACCESS_KEY_IDR2 ключВід Cloudflare
R2_SECRET_ACCESS_KEYR2 секретВід Cloudflare
R2_BUCKETR2 bucketpisd-media
R2_PUBLIC_URLПублічний CDNhttps://cdn.pisd.uk

DANGER

OTP_ALLOW_DEV_CODE=true — тільки для локальної розробки. На prod ніколи.

Міграції бази даних

synchronize: false у production. Всі зміни схеми — через onModuleInit у відповідному сервісі.

Патерн міграції

typescript
async onModuleInit() {
  await this.dataSource.query(`
    ALTER TABLE events
      ADD COLUMN IF NOT EXISTS template_id uuid REFERENCES event_templates(id),
      ADD COLUMN IF NOT EXISTS enabled_modules text[] DEFAULT '{}';
  `);
}

Правило

Завжди використовуй ADD COLUMN IF NOT EXISTS і CREATE TABLE IF NOT EXISTS — безпечно для повторних деплоїв.

Типові помилки

ПомилкаПричинаРішення
column already existsВідсутній IF NOT EXISTSДодай перевірку
relation does not existТаблиця ще не створенаПеревір порядок onModuleInit
duplicate keySeed виконався двічіДодай ON CONFLICT DO NOTHING

Логи

bash
# Real-time логи API
ssh -i ~/.ssh/hetzner root@37.27.202.249 \
  "cd /opt/pisd/pisduk && docker compose logs -f api"

# Останні 100 рядків
ssh -i ~/.ssh/hetzner root@37.27.202.249 \
  "cd /opt/pisd/pisduk && docker compose logs --tail=100 api"

Peaced — платформа подій