diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..cd0ebb3 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,176 @@ +# 🚀 Деплой ProtekaAuto CMS + +## 📋 Что исправлено + +### ✅ Проблемы со стилями +- Исправлен `globals.css` для совместимости с Tailwind CSS v4 +- Обновлен синтаксис тем и цветовых переменных +- Стили теперь корректно загружаются в продакшене + +### ✅ Docker Compose конфигурация +- Добавлены все переменные окружения из `stack.env` +- Исправлена структура и комментарии +- Добавлена поддержка `PARTSINDEX_API_KEY` +- Добавлен динамический порт через `CMS_PORT` + +## 🔧 Подготовка к деплою + +### 1. Настройка переменных окружения + +Скопируйте `stack.env` и настройте все переменные: + +```bash +cp stack.env.example stack.env +nano stack.env +``` + +**Обязательные переменные для настройки:** +- `DATABASE_URL` - подключение к PostgreSQL +- `NEXTAUTH_SECRET` - секретный ключ для авторизации +- `JWT_SECRET` - секретный ключ для JWT токенов +- `NEXTAUTH_URL` - URL вашей CMS админки +- AWS S3 настройки для файлов +- API ключи для интеграций + +### 2. Проверка конфигурации + +```bash +# Проверка SMS конфигурации +npm run check:sms + +# Проверка Docker Compose +./scripts/test-docker-compose.sh + +# Проверка сборки +npm run build +``` + +## 🐳 Деплой через Docker + +### Запуск CMS + +```bash +# Сборка и запуск +docker-compose up -d + +# Просмотр логов +docker-compose logs -f + +# Остановка +docker-compose down +``` + +### Обновление + +```bash +# Обновление кода +git pull + +# Пересборка и перезапуск +docker-compose down +docker-compose up -d --build + +# Или используйте готовый скрипт +./scripts/update-container.sh +``` + +## 📊 Мониторинг + +### Проверка состояния + +```bash +# Статус контейнеров +docker-compose ps + +# Использование ресурсов +docker stats + +# Логи в реальном времени +docker-compose logs -f --tail=100 +``` + +### Health Check + +CMS доступна по адресу: `http://localhost:3000/api/health` + +## 🔧 Полезные команды + +### База данных + +```bash +# Генерация Prisma клиента +npm run db:generate + +# Применение изменений схемы +npm run db:push + +# Prisma Studio (GUI для БД) +npm run db:studio +``` + +### Разработка + +```bash +# Локальный запуск с hot reload +npm run dev + +# Линтинг +npm run lint + +# Тестирование сборки +npm run build +``` + +## 🚨 Troubleshooting + +### Проблемы со стилями +- Убедитесь, что используется Tailwind CSS v4 +- Проверьте `globals.css` и `tailwind.config.js` +- Очистите кеш: `rm -rf .next` + +### Проблемы с Docker +- Проверьте `stack.env` файл +- Убедитесь, что все переменные заданы +- Проверьте логи: `docker-compose logs` + +### Проблемы с базой данных +- Проверьте `DATABASE_URL` +- Убедитесь, что PostgreSQL доступен +- Запустите `npm run db:push` + +## 📝 Переменные окружения + +Полный список переменных в `stack.env`: + +### База данных +- `DATABASE_URL` - строка подключения к PostgreSQL + +### Авторизация +- `NEXTAUTH_SECRET` - секрет для NextAuth +- `JWT_SECRET` - секрет для JWT +- `NEXTAUTH_URL` - URL админки + +### AWS S3 +- `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` +- `AWS_BUCKET_NAME`, `AWS_S3_BUCKET`, `S3_ENDPOINT` + +### SMS API +- `BEELINE_SMS_USER`, `BEELINE_SMS_PASS`, `BEELINE_SMS_SENDER` + +### Интеграции +- Laximo API: `LAXIMO_LOGIN`, `LAXIMO_PASSWORD` +- YooKassa: `YOOKASSA_SHOP_ID`, `YOOKASSA_SECRET_KEY` +- AutoEuro: `AUTOEURO_API_KEY` +- PartsAPI: `PARTSAPI_*_KEY` +- PartsIndex: `PARTSINDEX_API_KEY` +- Яндекс: `YANDEX_*_API_KEY` + +## 🎯 Следующие шаги + +1. ✅ Настройте все переменные в `stack.env` +2. ✅ Запустите `npm run build` для проверки +3. ✅ Запустите `docker-compose up -d` +4. ✅ Проверьте доступность по `http://localhost:3000` +5. ✅ Настройте reverse proxy (nginx) для продакшена +6. ✅ Настройте SSL сертификаты +7. ✅ Настройте бэкапы базы данных \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index dcb5b84..eeca317 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,59 +4,80 @@ services: protekauto-cms: build: context: . - dockerfile: Dockerfile # Используем упрощенный вариант для обхода rate limits + dockerfile: Dockerfile args: - - BEELINE_SMS_USER=${BEELINE_SMS_USER} - - BEELINE_SMS_PASS=${BEELINE_SMS_PASS} - - BEELINE_SMS_SENDER=${BEELINE_SMS_SENDER} + # База данных - DATABASE_URL=${DATABASE_URL} + + # Авторизация - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - JWT_SECRET=${JWT_SECRET} + - NEXTAUTH_URL=${NEXTAUTH_URL} + + # AWS S3 - AWS_REGION=${AWS_REGION} - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_BUCKET_NAME=${AWS_BUCKET_NAME} - AWS_S3_BUCKET=${AWS_S3_BUCKET} - S3_ENDPOINT=${S3_ENDPOINT} - - NEXTAUTH_URL=${NEXTAUTH_URL} + + # SMS API Билайн + - BEELINE_SMS_USER=${BEELINE_SMS_USER} + - BEELINE_SMS_PASS=${BEELINE_SMS_PASS} + - BEELINE_SMS_SENDER=${BEELINE_SMS_SENDER} + + # Laximo API - LAXIMO_LOGIN=${LAXIMO_LOGIN} - LAXIMO_PASSWORD=${LAXIMO_PASSWORD} - LAXIMO_DOC_LOGIN=${LAXIMO_DOC_LOGIN} - LAXIMO_DOC_PASSWORD=${LAXIMO_DOC_PASSWORD} + + # YooKassa платежи - YOOKASSA_SHOP_ID=${YOOKASSA_SHOP_ID} - YOOKASSA_SECRET_KEY=${YOOKASSA_SECRET_KEY} + + # AutoEuro API - AUTOEURO_API_KEY=${AUTOEURO_API_KEY} + + # PartsAPI ключи - PARTSAPI_CATEGORIES_KEY=${PARTSAPI_CATEGORIES_KEY} - PARTSAPI_ARTICLES_KEY=${PARTSAPI_ARTICLES_KEY} - PARTSAPI_MEDIA_KEY=${PARTSAPI_MEDIA_KEY} + + # PartsIndex API + - PARTSINDEX_API_KEY=${PARTSINDEX_API_KEY} + + # Яндекс API ключи - YANDEX_MAPS_API_KEY=${YANDEX_MAPS_API_KEY} - YANDEX_DELIVERY_TOKEN=${YANDEX_DELIVERY_TOKEN} - YANDEX_GEOSUGGEST_API_KEY=${YANDEX_GEOSUGGEST_API_KEY} - YANDEX_DELIVERY_SOURCE_STATION_ID=${YANDEX_DELIVERY_SOURCE_STATION_ID} + ports: - - "3000:3000" + - "${CMS_PORT:-3000}:3000" environment: - # База данных (внешняя) + # База данных - DATABASE_URL=${DATABASE_URL} - # NextAuth и JWT + # Авторизация - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - JWT_SECRET=${JWT_SECRET} + - NEXTAUTH_URL=${NEXTAUTH_URL} - # AWS S3 для файлов + # AWS S3 - AWS_REGION=${AWS_REGION} - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - AWS_BUCKET_NAME=${AWS_BUCKET_NAME} - - # URL для доступа к админке - - NEXTAUTH_URL=${NEXTAUTH_URL} + - AWS_S3_BUCKET=${AWS_S3_BUCKET} + - S3_ENDPOINT=${S3_ENDPOINT} # SMS API Билайн - BEELINE_SMS_USER=${BEELINE_SMS_USER} - BEELINE_SMS_PASS=${BEELINE_SMS_PASS} - BEELINE_SMS_SENDER=${BEELINE_SMS_SENDER} - + # Laximo API - LAXIMO_LOGIN=${LAXIMO_LOGIN} - LAXIMO_PASSWORD=${LAXIMO_PASSWORD} @@ -75,19 +96,20 @@ services: - PARTSAPI_ARTICLES_KEY=${PARTSAPI_ARTICLES_KEY} - PARTSAPI_MEDIA_KEY=${PARTSAPI_MEDIA_KEY} + # PartsIndex API + - PARTSINDEX_API_KEY=${PARTSINDEX_API_KEY} + # Яндекс API ключи - YANDEX_MAPS_API_KEY=${YANDEX_MAPS_API_KEY} - YANDEX_DELIVERY_TOKEN=${YANDEX_DELIVERY_TOKEN} - YANDEX_GEOSUGGEST_API_KEY=${YANDEX_GEOSUGGEST_API_KEY} - YANDEX_DELIVERY_SOURCE_STATION_ID=${YANDEX_DELIVERY_SOURCE_STATION_ID} - # S3 дополнительные настройки - - AWS_S3_BUCKET=${AWS_S3_BUCKET} - - S3_ENDPOINT=${S3_ENDPOINT} - # Окружение - NODE_ENV=production restart: unless-stopped + env_file: + - stack.env diff --git a/scripts/test-docker-compose.sh b/scripts/test-docker-compose.sh new file mode 100755 index 0000000..3495730 --- /dev/null +++ b/scripts/test-docker-compose.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +echo "🔧 Тестирование Docker Compose конфигурации..." + +# Проверяем наличие stack.env +if [ ! -f "stack.env" ]; then + echo "❌ Файл stack.env не найден!" + exit 1 +fi + +echo "✅ Файл stack.env найден" + +# Проверяем синтаксис docker-compose.yml +echo "🔍 Проверка синтаксиса docker-compose.yml..." + +if docker-compose config > /dev/null 2>&1; then + echo "✅ Синтаксис docker-compose.yml корректен" +else + echo "❌ Ошибка в синтаксисе docker-compose.yml:" + docker-compose config + exit 1 +fi + +# Показываем итоговую конфигурацию (без секретов) +echo "📋 Итоговая конфигурация (переменные окружения):" +docker-compose config --services + +echo "🎉 Конфигурация Docker Compose готова к использованию!" +echo "" +echo "Для запуска используйте:" +echo " docker-compose up -d" +echo "" +echo "Для просмотра логов:" +echo " docker-compose logs -f" \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index 9cf4564..c18beae 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,118 +1,82 @@ @import "tailwindcss"; -@import "tw-animate-css"; -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); - --color-sidebar-ring: var(--sidebar-ring); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar: var(--sidebar); - --color-chart-5: var(--chart-5); - --color-chart-4: var(--chart-4); - --color-chart-3: var(--chart-3); - --color-chart-2: var(--chart-2); - --color-chart-1: var(--chart-1); - --color-ring: var(--ring); - --color-input: var(--input); - --color-border: var(--border); - --color-destructive: var(--destructive); - --color-accent-foreground: var(--accent-foreground); - --color-accent: var(--accent); - --color-muted-foreground: var(--muted-foreground); - --color-muted: var(--muted); - --color-secondary-foreground: var(--secondary-foreground); - --color-secondary: var(--secondary); - --color-primary-foreground: var(--primary-foreground); - --color-primary: var(--primary); - --color-popover-foreground: var(--popover-foreground); - --color-popover: var(--popover); - --color-card-foreground: var(--card-foreground); - --color-card: var(--card); - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); +@theme { + --color-background: hsl(0 0% 100%); + --color-foreground: hsl(0 0% 3.9%); + --color-card: hsl(0 0% 100%); + --color-card-foreground: hsl(0 0% 3.9%); + --color-popover: hsl(0 0% 100%); + --color-popover-foreground: hsl(0 0% 3.9%); + --color-primary: hsl(0 0% 9%); + --color-primary-foreground: hsl(0 0% 98%); + --color-secondary: hsl(0 0% 96.1%); + --color-secondary-foreground: hsl(0 0% 9%); + --color-muted: hsl(0 0% 96.1%); + --color-muted-foreground: hsl(0 0% 45.1%); + --color-accent: hsl(0 0% 96.1%); + --color-accent-foreground: hsl(0 0% 9%); + --color-destructive: hsl(0 84.2% 60.2%); + --color-destructive-foreground: hsl(0 0% 98%); + --color-border: hsl(0 0% 89.8%); + --color-input: hsl(0 0% 89.8%); + --color-ring: hsl(0 0% 3.9%); + --color-chart-1: hsl(12 76% 61%); + --color-chart-2: hsl(173 58% 39%); + --color-chart-3: hsl(197 37% 24%); + --color-chart-4: hsl(43 74% 66%); + --color-chart-5: hsl(27 87% 67%); + --color-sidebar: hsl(0 0% 98%); + --color-sidebar-foreground: hsl(0 0% 3.9%); + --color-sidebar-primary: hsl(0 0% 9%); + --color-sidebar-primary-foreground: hsl(0 0% 98%); + --color-sidebar-accent: hsl(0 0% 96.1%); + --color-sidebar-accent-foreground: hsl(0 0% 9%); + --color-sidebar-border: hsl(0 0% 89.8%); + --color-sidebar-ring: hsl(0 0% 3.9%); + --radius-sm: 0.375rem; + --radius-md: 0.5rem; + --radius-lg: 0.625rem; + --radius-xl: 0.75rem; } -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); +@theme dark { + --color-background: hsl(0 0% 3.9%); + --color-foreground: hsl(0 0% 98%); + --color-card: hsl(0 0% 3.9%); + --color-card-foreground: hsl(0 0% 98%); + --color-popover: hsl(0 0% 3.9%); + --color-popover-foreground: hsl(0 0% 98%); + --color-primary: hsl(0 0% 98%); + --color-primary-foreground: hsl(0 0% 9%); + --color-secondary: hsl(0 0% 14.9%); + --color-secondary-foreground: hsl(0 0% 98%); + --color-muted: hsl(0 0% 14.9%); + --color-muted-foreground: hsl(0 0% 63.9%); + --color-accent: hsl(0 0% 14.9%); + --color-accent-foreground: hsl(0 0% 98%); + --color-destructive: hsl(0 62.8% 30.6%); + --color-destructive-foreground: hsl(0 0% 98%); + --color-border: hsl(0 0% 14.9%); + --color-input: hsl(0 0% 14.9%); + --color-ring: hsl(0 0% 83.1%); + --color-chart-1: hsl(220 70% 50%); + --color-chart-2: hsl(160 60% 45%); + --color-chart-3: hsl(30 80% 55%); + --color-chart-4: hsl(280 65% 60%); + --color-chart-5: hsl(340 75% 55%); + --color-sidebar: hsl(0 0% 3.9%); + --color-sidebar-foreground: hsl(0 0% 98%); + --color-sidebar-primary: hsl(0 0% 98%); + --color-sidebar-primary-foreground: hsl(0 0% 9%); + --color-sidebar-accent: hsl(0 0% 14.9%); + --color-sidebar-accent-foreground: hsl(0 0% 98%); + --color-sidebar-border: hsl(0 0% 14.9%); + --color-sidebar-ring: hsl(0 0% 83.1%); } @layer base { * { - @apply border-border outline-ring/50; + @apply border-border; } body { @apply bg-background text-foreground;