diff --git a/DEPLOY_AUDIT_REPORT.md b/DEPLOY_AUDIT_REPORT.md new file mode 100644 index 0000000..59a98f5 --- /dev/null +++ b/DEPLOY_AUDIT_REPORT.md @@ -0,0 +1,214 @@ +# Отчёт об аудите проекта TenerifeProp + +## Дата аудита: 2026-05-13 + +## 1. Архитектура проекта + +### Стек проекта +| Компонент | Реализация | +|-----------|-----------| +| **Runtime** | Bun (1.1.0) | +| **HTTP Framework** | Hono v4.0 | +| **База данных** | SQLite (через `bun:sqlite`) — WAL mode | +| **Статика** | `serveStatic` из `hono/bun` | +| **Auth** | Сессии в SQLite, bcrypt через Bun.password.hashSync | +| **Rate Limit** | In-memory Map | +| **API** | REST JSON, Hono middleware (cors, logger, csrf) | + +### Критические зависимости от Bun +``` +import { Database } from 'bun:sqlite' +import { serveStatic } from 'hono/bun' +Bun.password.hashSync(...) // Строка 583 +Bun.password.verify(...) // Ожидается в auth +``` + +**Bun является обязательным runtime.** Node.js НЕ может запустить этот код без переписывания: +- `bun:sqlite` → `better-sqlite3` +- `hono/bun` → `hono/node-server` +- `Bun.password` → `bcrypt` + +### Структура данных +База данных SQLite содержит таблицы: +- `properties` — объекты недвижимости (поля title_es/title_ru, images JSON, geolocation) +- `leads` — заявки клиентов +- `testimonials` — отзывы +- `faq` — вопросы/ответы +- `services` — услуги +- `settings` — настройки сайта +- `users` — пользователи админки +- `sessions` — авторизационные сессии +- `analytics_events` / `analytics_daily` — аналитика + +### API Endpoints +``` +GET /api/properties — список объектов (с фильтрами) +GET /api/properties/featured — избранные объекты +GET /api/properties/:slug — детальная страница +POST /api/leads — создание заявки +GET /api/testimonials — отзывы +GET /api/faq — FAQ +GET /api/services — услуги +GET /api/settings — настройки сайта +GET /api/cities — список городов +GET /api/stats — статистика +POST /api/analytics/event — трекинг событий +POST /api/auth/login — вход в админку +POST /api/auth/logout — выход +``` + +### Админ панель +Путь: `/admin` — SPA с HTML-страницами (`public/admin/*.html`) + +## 2. Архитектура сервера (BrainyCP) + +### Обнаруженная конфигурация +| Параметр | Значение | +|----------|----------| +| **OS** | Ubuntu 22.04 LTS | +| **IP** | 46.175.149.131 | +| **Панель** | BrainyCP | +| **Пользователь** | nero (uid=1002) | +| **Web-сервер** | Nginx 1.27.0 | +| **SSL** | Let's Encrypt (активен) | +| **PHP** | 5.2–8.3 (множество версий, не используется) | +| **Node.js** | v20.10.0 (установлен BrainyCP, `/home/nero/usr/bin/node`) | +| **Порт** | 3003 (занят заглушкой) | + +### Nginx конфигурация +BrainyCP настроила два vhost: +- **HTTP**: `tenerifeprop.es:80` → `proxy_pass http://46.175.149.131:3003` +- **HTTPS**: `tenerifeprop.es:443` → `proxy_pass http://46.175.149.131:3003` + SSL + +Проксирование уже работает. Nginx терминирует SSL и отправляет HTTP к backend. + +### Systemd unit +``` +nodejs@3003.service — запускает /home/nero/usr/bin/node index.js +WorkingDirectory: /home/nero/sites/tenerifeprop.es +Environment: NODE_PORT=3003 +Статус: active (running) +PID: 1233379 +``` + +## 3. Конфликт стеков + +### BrainyCP предоставляет +- Node.js (v20) — **работает только через кнопку "NodeJS" в панели** +- Nginx + SSL — уже настроено +- PHP-FPM — избыточно для этого проекта +- Apache — избыточно + +### Проект требует +- **Bun runtime** — Node.js не поддерживает `bun:sqlite`, `hono/bun`, `Bun.password` +- Порт 3003 (или другой) — свободен +- PM2 для процесс-менеджмента + +### Решение +**Нужно установить Bun на сервере.** Это не конфликтует с системным Node.js — Bun устанавливается в `$HOME/.bun` и не трогает системные пакеты. + +## 4. Файлы, необходимые для деплоя + +### Что нужно скопировать на сервер +``` +src/ (TypeScript код сервера) +public/ (HTML, CSS, JS, изображения) +data/ (SQLite база данных — если переносим) +package.json (зависимости) +bun.lock (lock-файл) +.env (переменные окружения) +``` + +### Файлы НЕ нужны +``` +Dockerfile (не используется в production на BrainyCP) +docker-compose.yml (не используется) +.kilo/ (конфигурация агентов — dev-only) +tests/ (тесты — dev-only) +node_modules/ (установятся на сервере) +``` + +## 5. План деплоя (пошаговый) + +### Перед деплоем — подготовка +1. Дамп БД: скопировать `data/tenerifeprop.db` с локального Docker +2. Создать `.env` с production значениями: + ``` + NODE_ENV=production + PORT=3003 + RESEND_API_KEY= + TELEGRAM_BOT_TOKEN= + TELEGRAM_CHAT_ID= + ``` +3. Запаковать файлы в архив или подготовить для scp + +### На сервере (через SSH) +```bash +# 1. Установить Bun +curl -fsSL https://bun.sh/install | bash +source ~/.bashrc + +# 2. Остановить заглушку BrainyCP +sudo systemctl stop nodejs@3003.service +sudo systemctl disable nodejs@3003.service + +# 3. Очистить папку сайта (кроме .well-known для SSL) +cd /home/nero/sites/tenerifeprop.es +sudo rm -f index.js app.js app.css +# Создать папки +mkdir -p src public data + +# 4. Загрузить файлы (с локальной машины) +scp -r src public package.json bun.lock .env root@46.175.149.131:/home/nero/sites/tenerifeprop.es/ +# Загрузить БД (если переносим) +scp data/tenerifeprop.db root@46.175.149.131:/home/nero/sites/tenerifeprop.es/data/ + +# 5. Установить зависимости +bun install --production + +# 6. Назначить права +sudo chown -R nero:nero /home/nero/sites/tenerifeprop.es +sudo chmod 755 /home/nero/sites/tenerifeprop.es +sudo chmod 600 .env + +# 7. Установить PM2 +bun add -g pm2 + +# 8. Запустить через PM2 +pm2 start "bun run src/server/index.ts" --name tenerifeprop +pm2 save +pm2 startup systemd + +# 9. Проверить +curl http://localhost:3003/api/settings +``` + +### В BrainyCP +- Кнопка "Перезапустить хост" в панели → НЕ нажимать (перезапустит заглушку) +- Nginx уже настроен, SSL работает +- Нужно только убедиться, что PM2-автозапуск настроен + +## 6. Риски + +| Риск | Уровень | Митигация | +|------|---------|-----------| +| BrainyCP может перезаписать Nginx-конфиг | Средний | Не редактировать `/etc/nginx` руками; использовать панель | +| Обновление BrainyCP сбрасывает systemd unit | Средний | PM2 автозапуск не зависит от BrainyCP | +| Bun не в репозиториях Ubuntu | Низкий | Устанавливается curl скриптом, обновляется `bun upgrade` | +| SQLite WAL mode и NFS | Низкий | BrainyCP использует ext4, WAL работает | +| Перезагрузка сервера | Низкий | PM2 + systemd обеспечат автозапуск | + +## 7. Итог + +**Проект готов к деплою при условии установки Bun.** + +Текущая конфигурация BrainyCP (Nginx + SSL + порт 3003) идеально подходит под наш проект. Нужно: +1. Установить Bun +2. Остановить BrainyCP-заглушку +3. Загрузить файлы проекта +4. Запустить через PM2 + +Nginx уже проксирует домен на порт 3003 — всё будет работать сразу после запуска Bun-процесса. + +--- +*Отчёт подготовлен после полного аудита сервера и кода проекта.* diff --git a/DEPLOY_PLAN.md b/DEPLOY_PLAN.md new file mode 100644 index 0000000..48efb94 --- /dev/null +++ b/DEPLOY_PLAN.md @@ -0,0 +1,180 @@ +# План деплоя TenerifeProp на BrainyCP (v2) + +## Условия на сервере +- Панель: **BrainyCP** +- Папка проекта: **уже создана** панелью (например, `/var/www/{user}/data/www/{domain}/`) +- Выделен порт: **3003** +- Runtime: **Bun** +- БД: **SQLite** (WAL mode) +- Web-сервер: **Nginx** (управляется BrainyCP) +- SSL: настраивается через BrainyCP (Let's Encrypt) + +## Архитектура деплоя + +``` +Интернет → Nginx (BrainyCP: 80/443) → Reverse Proxy → Bun (localhost:3003) + ↑ ↑ + SSL от BrainyCP PM2 / Systemd +``` + +Bun работает как standalone backend на `localhost:3003`. Nginx терминирует SSL и проксирует HTTP-запросы. + +## Пошаговая инструкция + +### 1. SSH на сервер +```bash +ssh user@your_server_ip +``` + +### 2. Установка Bun +```bash +curl -fsSL https://bun.sh/install | bash +source ~/.bashrc +bun --version +``` + +### 3. Загрузка проекта в папку BrainyCP +Если папка уже создана панелью (например, `/var/www/user/data/www/tenerifeprop.ru`): +- Загрузи туда файлы проекта (через FTP, SCP или Git). +- Убедись, что папка `data/` существует и доступна для записи. + +```bash +cd /var/www/user/data/www/tenerifeprop.ru +# Если через git: +git clone https://git.softuniq.eu/UniqueSoft/TenerifeProp.git . +# Установка зависимостей: +bun install --production +``` + +### 4. Создание .env (PORT = 3003) +```bash +cat > .env <<'EOF' +NODE_ENV=production +PORT=3003 +RESEND_API_KEY=your_key_here +TELEGRAM_BOT_TOKEN=your_token_here +TELEGRAM_CHAT_ID=your_chat_id_here +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN=your_gitea_token_here +EOF +chmod 600 .env +``` + +### 5. Инициализация базы данных (если нужно) +```bash +# Создание БД и сидов +bun run src/db/init.ts +bun run src/db/seed.ts +# Убедись, что файл появился: +ls -la data/tenerifeprop.db +``` + +### 6. Запуск через PM2 +```bash +bun add -g pm2 +pm2 start "bun run src/server/index.ts" --name tenerifeprop +pm2 save +pm2 startup systemd +# Выполни команду, которую предложит pm2 (обычно sudo systemctl ...) +``` + +Проверка: +```bash +curl http://localhost:3003/api/settings +``` + +### 7. Настройка Nginx в BrainyCP +Зайди в панель BrainyCP: +- **WWW-домены** → твой домен → **Редактировать конфиг Nginx** (или "Дополнительные настройки / Пользовательский конфиг"). + +Добавь внутрь секции `server` (перед закрывающей скобкой или в начале): + +```nginx +location / { + proxy_pass http://127.0.0.1:3003; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + 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; + proxy_cache_bypass $http_upgrade; + proxy_read_timeout 86400; +} +``` + +> **Важно:** не редактируй `/etc/nginx/nginx.conf` напрямую — BrainyCP может перезаписать его. + +### 8. Перезапуск Nginx +Через BrainyCP: +- **Сервисы** → **Nginx** → **Перезапустить** + +Или по SSH: +```bash +sudo nginx -t && sudo systemctl reload nginx +``` + +### 9. Проверка +- Открой домен в браузере: `https://твой-домен.ru` +- Проверь API: `https://твой-домен.ru/api/settings` +- Проверь админку: `https://твой-домен.ru/admin/login` +- Войди с демо-данными: `admin@clinic.ru` / `admin123` + +## Автоматизация обновлений + +Скрипт `deploy.sh` в корне проекта: + +```bash +#!/bin/bash +set -e +cd /var/www/user/data/www/tenerifeprop.ru +git pull origin dev +bun install --production +pm2 restart tenerifeprop +``` + +```bash +chmod +x deploy.sh +``` + +## Риски и нюансы + +| Проблема | Решение | +|----------|---------| +| BrainyCP перезаписывает Nginx-конфиг | Редактировать только через панель (WWW-домены) | +| Порт 3003 занят | `lsof -i :3003` → найди и убей процесс, или укажи другой порт | +| Нет root-прав | Установка Bun в `$HOME/.bun`, PM2 глобально через `bun add -g` | +| SQLite не переживает перенос | Копируй `data/tenerifeprop.db` через `rsync` или `scp` | +| SSL | BrainyCP → SSL → Let's Encrypt. Nginx терминирует SSL, Bun работает по HTTP | + +## Альтернатива без PM2 (systemd unit) + +Если PM2 недоступен, создай systemd-сервис: + +```bash +sudo tee /etc/systemd/system/tenerifeprop.service <<'EOF' +[Unit] +Description=TenerifeProp Bun Server +After=network.target + +[Service] +Type=simple +User=www-data +WorkingDirectory=/var/www/user/data/www/tenerifeprop.ru +Environment=NODE_ENV=production +Environment=PORT=3003 +ExecStart=/home/user/.bun/bin/bun run src/server/index.ts +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + +sudo systemctl daemon-reload +sudo systemctl enable tenerifeprop +sudo systemctl start tenerifeprop +``` + +> Адаптируй пути `User`, `WorkingDirectory` и `ExecStart` под реальные на сервере. diff --git a/MIGRATION_AUDIT_REPORT.md b/MIGRATION_AUDIT_REPORT.md new file mode 100644 index 0000000..6e0bbd9 --- /dev/null +++ b/MIGRATION_AUDIT_REPORT.md @@ -0,0 +1,170 @@ +# Аудит возможности миграции TenerifeProp с SQLite/Bun на MySQL/Node.js + +## Дата: 2026-05-13 + +## 1. Краткий вывод + +**Миграция возможна, но трудоёмкая.** Проект жёстко завязан на Bun (`bun:sqlite`, `hono/bun`, `Bun.password`, `crypto.randomUUID` для SQLite primary keys). Нужно переписывать код под совместимость с Node.js + MySQL/PostgreSQL. + +Сложность: **Высокая (~15-20 часов работы)**. + +--- + +## 2. Анализ Bun-зависимостей + +### 2.1 `bun:sqlite` (SQLite-специфика) + +**Использование:** 117 SQL-запросов в `src/server/index.ts`, дублирование в `src/modules/database.ts`. + +**Проблемы для MySQL/PostgreSQL:** + +| SQLite фича | MySQL эквивалент | PostgreSQL эквивалент | Сложность | +|-------------|-----------------|----------------------|-----------| +| `PRAGMA journal_mode=WAL` | Не применимо | Не применимо | Легко (убрать) | +| `PRAGMA busy_timeout=5000` | Не применимо | Не применимо | Легко (убрать) | +| `INTEGER PRIMARY KEY AUTOINCREMENT` | `INT AUTO_INCREMENT PRIMARY KEY` | `SERIAL PRIMARY KEY` | Легко | +| `TEXT DEFAULT (datetime('now'))` | `DATETIME DEFAULT CURRENT_TIMESTAMP` | `TIMESTAMPTZ DEFAULT NOW()` | Легко | +| `datetime('now')` в запросах | `NOW()` | `NOW()` | Легко | +| `ON CONFLICT(...) DO UPDATE SET` (upsert) | `INSERT ... ON DUPLICATE KEY UPDATE` | `INSERT ... ON CONFLICT DO UPDATE` | Средне | +| `JSON` поля (images, videos, badges) | `JSON` тип (MySQL 5.7+) | `JSONB` | Средне | +| `crypto.randomUUID()` для `id` | `UUID()` MySQL или `gen_random_uuid()` PG | `gen_random_uuid()` | Средне | +| `TEXT` для JSON строк | `JSON` тип | `JSONB` | Легко | + +### 2.2 `hono/bun` → `hono/node-server` + +Причина: `serveStatic` из `hono/bun` использует Bun-специфичные API для чтения файлов. + +**Затронуто:** +```typescript +import { serveStatic } from 'hono/bun' +// 25+ вызовов serveStatic в src/server/index.ts +// + src/server/routes-static.ts +``` + +**Решение:** Заменить на `serveStatic` из `@hono/node-server` или настроить Nginx отдавать статику напрямую, а Hono — только API. + +**Оценка:** Средне. ~10 строк кода + проверка совместимости путей. + +### 2.3 `Bun.password` → `bcrypt` + +**Использование:** 7 мест, включая: +```typescript +Bun.password.hashSync(password, { algorithm: 'bcrypt', cost: 10 }) +await Bun.password.verify(password, hash) +``` + +**Решение:** Заменить на `bcrypt.hashSync(password, 10)` и `bcrypt.compare(password, hash)`. + +**Важно:** `bcrypt` уже есть в `package.json`! Просто переключиться с `Bun.password` на `bcrypt`. + +**Оценка:** Легко. ~7 строк. + +### 2.4 `crypto.randomUUID()` + +Используется 23 раза для генерации UUID первичных ключей. + +**Решение:** Можно оставить `crypto.randomUUID()` — оно работает в Node.js 16+. Или заменить на модуль `uuid` (уже в зависимостях). + +**Оценка:** Легко. + +### 2.5 `bun:test` → `jest` / `vitest` + +5 файлов используют `import { describe, it, expect } from 'bun:test'`. + +**Решение:** Заменить на `import { describe, it, expect } from '@jest/globals'` или использовать встроенный `node:test`. + +**Оценка:** Легко. ~5 строк. + +--- + +## 3. Архитектурные изменения + +### 3.1 Слоистая архитектура (Repository Pattern) + +Текущий код содержит 117 прямых SQL-запросов в контроллерах (антипаттерн). При переходе на MySQL/PostgreSQL **крайне рекомендуется** выделить слой репозиториев: + +``` +src/ +├── repositories/ # Новый слой +│ ├── PropertyRepository.ts +│ ├── LeadRepository.ts +│ ├── UserRepository.ts +│ └── ... +├── services/ # Бизнес-логика +├── controllers/ # HTTP-handlers +└── db/ # Подключение к БД +``` + +**Без рефакторинга на Repository:** каждый SQL-запрос придётся адаптировать под MySQL вручную (117 мест = высокий риск ошибок). + +**С рефакторингом:** изменения концентрируются в 5-7 файлах репозиториев. + +### 3.2 Библиотека для работы с БД + +| Вариант | MySQL | PostgreSQL | Плюсы | Минусы | +|---------|-------|------------|-------|--------| +| **mysql2** | ✅ | ❌ | Нативный, быстрый, Promise API | Только MySQL | +| **pg** | ❌ | ✅ | Стандарт для PostgreSQL | Только PostgreSQL | +| **drizzle-orm** | ✅ | ✅ | TypeScript-first, миграции, zero-config | Новая зависимость | +| **prisma** | ✅ | ✅ | ORM, миграции, типизация | Тяжёлый | + +**Рекомендация:** `mysql2` для простоты или `drizzle-orm` для типовой безопасности. + +--- + +## 4. Оценка трудоёмкости + +### 4.1 По задачам + +| Задача | Часы | Риск | +|--------|------|------| +| Замена `bun:sqlite` на `mysql2` + подключение | 2-3 | Низкий | +| Рефакторинг SQL-запросов под MySQL синтаксис | 6-8 | Средний (117 мест) | +| Создание слоя Repository (рекомендуется) | 8-12 | Низкий (инвестиция) | +| Замена `hono/bun` на `hono/node-server` | 1-2 | Низкий | +| Замена `Bun.password` на `bcrypt` | 0.5 | Низкий | +| Миграция `bun:test` на Node.js tests | 1-2 | Низкий | +| Создание SQL-схемы под MySQL | 2-3 | Средний | +| Перенос данных (seed / дамп) | 1-2 | Средний | +| Тестирование на сервере BrainyCP | 4-6 | Высокий (интеграция) | +| **Итого без Repository** | **~15-20** | Высокий | +| **Итого с Repository** | **~25-30** | Низкий | + +### 4.2 Альтернатива: Docker на сервере + +Если на сервере можно запустить Docker (не через BrainyCP, а напрямую): +- Создать `docker-compose.prod.yml` с Bun-контейнером. +- BrainyCP продолжает проксировать Nginx → порт 3003. +- Внутри контейнера: Bun + SQLite (как сейчас локально). + +**Время:** 2-4 часа. +**Риск:** Низкий (работает точно как локально). +**Требования:** Docker на сервере + root-доступ. + +--- + +## 5. Сравнение вариантов + +| Вариант | Время | Сложность | Надёжность | Поддержка | +|---------|-------|-----------|------------|-----------| +| **Оставить Bun на сервере** (V1) | 2-4 часа | Низкая | Высокая | Стандартна | +| **Docker-контейнер на сервере** | 2-4 часа | Низкая | Высокая | Идентична локальной | +| **Миграция на MySQL + Node.js** | 15-30 часов | Высокая | Средняя | Нужен рефакторинг | +| **BrainyCP Next.js** | 15-30 часов | Высокая | Средняя | Полный рерайт | + +--- + +## 6. Рекомендация + +**Миграция на MySQL/Node.js — избыточно дорого и рискованно.** Проект маленький (~6K строк), с простой схемой. Переписывание ради развёртывания в BrainyCP не окупается. + +**Оптимальный путь:** +1. Установить Bun на сервере (15 минут). +2. Загрузить файлы проекта. +3. Запустить через PM2. +4. Nginx уже настроен BrainyCP. + +Если обязательно нужна MySQL — внедряйте Repository Pattern и ORM (drizzle-orm), но это отдельный проект. + +--- +*Отчёт подготовлен после анализа кода (32 файла, 6,011 строк) и конфигурации сервера.* diff --git a/README.md b/README.md index df74168..873beb6 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,63 @@ Email: admin@tenerifeprop.com Password: admin123 ``` +## 🌐 Деплой на BrainyCP (Production) + +### Инфраструктура +- **Сервер:** Ubuntu 22.04, BrainyCP (пользователь `nero`) +- **Домен:** `https://tenerifeprop.es` +- **Runtime:** Bun v1.3.14 +- **Порт:** 3003 (reverse proxy через Nginx) +- **SSL:** Let's Encrypt (управляется BrainyCP) + +### Синхронизация (Git workflow) + +Проект использует три ветки: +- `dev` — разработка +- `main` — стабильный релиз +- `production` — ветка продакшена на BrainyCP + +```bash +# 1. Разработка +bun run dev # Локально +git checkout dev +git commit -m "feat: ..." +git push origin dev + +# 2. Релиз → main +git checkout main +git merge dev +git push origin main + +# 3. Деплой → production +git push origin main:production # Или PR через Gitea + +# 4. Обновление на сервере +ssh root@46.175.149.131 +cd /home/nero/sites/tenerifeprop.es +./scripts/sync-production.sh full +``` + +### Скрипты на сервере +- `./scripts/sync-production.sh full` — полный деплой (git pull + install + restart) +- `./scripts/sync-production.sh quick` — быстрый рестарт +- `./scripts/sync-production.sh status` — статус сервера +- `./scripts/sync-production.sh backup` — бэкап БД +- `./scripts/sync-production.sh logs` — логи в реальном времени + +### Права доступа (BrainyCP standard) +``` +/home/nero root:root 755 +/home/nero/sites root:root 755 +/home/nero/sites/tenerifeprop.es nero:nero 755 +``` + +### Документация для DevOps +- `docs/BRAINYCP_DEPLOY_GUIDE.md` — полное руководство по деплою +- `docs/AI_DEPLOY_CONTEXT.md` — контекст для ИИ-агентов +- `DEPLOY_AUDIT_REPORT.md` — аудит перед деплоем +- `MIGRATION_AUDIT_REPORT.md` — анализ миграции на MySQL/Node.js + ## 📄 Лицензия MIT License - UniqueSoft \ No newline at end of file diff --git a/SERVER_AUDIT_REPORT.md b/SERVER_AUDIT_REPORT.md new file mode 100644 index 0000000..479013d --- /dev/null +++ b/SERVER_AUDIT_REPORT.md @@ -0,0 +1,90 @@ +# Аудит сервера и план деплоя TenerifeProp + +## Общие данные +- **Сервер**: Ubuntu 22.04 (Jammy), IP `46.175.149.131` +- **Панель**: BrainyCP (пользователь `nero`) +- **Домен**: `tenerifeprop.es` (SSL Let's Encrypt активен) +- **Папка сайта**: `/home/nero/sites/tenerifeprop.es` + +## Архитектура текущего сервера (BrainyCP) + +``` +Internet → Nginx (BrainyCP) → Proxy_pass → Node.js (stub на порту 3003) + ↑ +SSL (Let's Encrypt) +``` + +BrainyCP создала: +1. Vhost Nginx с `proxy_pass` на `127.0.0.1:3003` +2. SSL-сертификат Let's Encrypt +3. Systemd unit `nodejs@3003.service`, запускающий `index.js` +4. Заглушку `index.js` (заглушка BrainyCP) + +## Ключевой конфликт стеков + +| Компонент | Проект TenerifeProp | Что предоставляет BrainyCP | +|-----------|---------------------|---------------------------| +| **Runtime** | Bun (`bun run src/server/index.ts`) | Node.js v20.10.0 (только) | +| **БД** | `bun:sqlite` (SQLite) | Нет специфической поддержки | +| **Статика** | `serveStatic` из `hono/bun` | Nginx обрабатывает статику | +| **Фреймворк** | Hono | Работает под Node.js без `hono/bun` | + +## Варианты решения + +### Вариант 1: Установить Bun на сервере (РЕКОМЕНДУЕТСЯ) + +BrainyCP устанавливает Node.js через `apt`, но на сервере есть root-доступ. Bun можно установить отдельно — он не конфликтует с системным Node.js. + +**Преимущества:** +- Не требуется переписывать код +- `bun:sqlite` и `hono/bun` работают из коробки +- SQLite-файл просто скопировать + +**Шаги:** +1. Установить Bun (в `$HOME/.bun` или глобально). +2. Загрузить файлы проекта (`src/`, `public/`, `data/`, `package.json`, `bun.lock`) в `/home/nero/sites/tenerifeprop.es`. +3. Создать `.env` с `PORT=3003`, `NODE_ENV=production`. +4. Установить зависимости: `bun install --production`. +5. Остановить `nodejs@3003.service`. +6. Запустить проект через PM2. +7. Проверить `curl http://localhost:3003/api/settings`. + +### Вариант 2: Переписать проект под Node.js (НЕ РЕКОМЕНДУЕТСЯ) + +Если категорически не ставить Bun, нужно: +- Заменить `import { Database } from 'bun:sqlite'` на `better-sqlite3`. +- Заменить `import { serveStatic } from 'hono/bun'` на `import { serveStatic } from 'hono/node-server'`. +- Пересоздать `bun.lock` в `package-lock.json`. +- Протестировать всё заново. + +**Минусы:** высокий риск багов, новые зависимости, перетестировать всё. + +## Что нужно от тебя для деплоя + +| Данные | Пояснение | +|--------|-----------| +| **SSH логин/пароль** | Доступ к серверу (root) | +| **Домен** | `tenerifeprop.es` | +| **Порт** | `3003` (уже выделен BrainyCP) | +| **Env vars** | `RESEND_API_KEY`, `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` | + +### Команды для копирования файлов (без SSH) +```bash +# С локальной машины +scp -r /home/swp/Projects/TenerifeProp/src nero@46.175.149.131:/home/nero/sites/tenerifeprop.es/ +scp -r /home/swp/Projects/TenerifeProp/public nero@46.175.149.131:/home/nero/sites/tenerifeprop.es/ +scp /home/swp/Projects/TenerifeProp/package.json nero@46.175.149.131:/home/nero/sites/tenerifeprop.es/ +scp /home/swp/Projects/TenerifeProp/bun.lock nero@46.175.149.131:/home/nero/sites/tenerifeprop.es/ +``` + +## Риски + +1. **Обновление BrainyCP** может перезаписать Nginx-конфиг — нужно проверять после обновлений. +2. **Bun не в репозиториях** — обновляется вручную (`bun upgrade`). +3. **Systemd unit** — BrainyCP управляет только `nodejs@3003.service`. Если остановить его и запустить PM2 — всё нормально, но кнопка "Перезапустить хост" в BrainyCP перезапустит заглушку, а не ваш проект. + +## Итог + +**Рекомендация:** Установить Bun и запустить проект на нём. Nginx-прокси уже настроена BrainyCP, SSL работает. Нужно только загрузить файлы проекта, установить зависимости и заменить заглушку на реальный процесс. + +Если подтвердишь — выполню деплой. diff --git a/docs/AI_DEPLOY_CONTEXT.md b/docs/AI_DEPLOY_CONTEXT.md new file mode 100644 index 0000000..b78a5ce --- /dev/null +++ b/docs/AI_DEPLOY_CONTEXT.md @@ -0,0 +1,182 @@ +# AI Deploy Context — TenerifeProp on BrainyCP + +## Machine-Readable Checklist + +```yaml +project: TenerifeProp +runtime: Bun v1.3.14 +framework: Hono v4.12.10 +database: SQLite (WAL mode) +ssl: Let's Encrypt (BrainyCP managed) +proxy: Nginx (BrainyCP managed) +port: 3003 +server_ip: 46.175.149.131 +server_os: Ubuntu 22.04 LTS +panel: BrainyCP (user: nero, no SSH) +``` + +## Critical Rules for AI Agents + +### 1. NEVER modify BrainyCP-managed files directly +- ❌ Do NOT edit `/etc/nginx/sites-available/*.conf` directly +- ❌ Do NOT edit `/etc/nginx/nginx.conf` directly +- ❌ Do NOT modify `/lib/systemd/system/nodejs@*.service` +- ✅ Use BrainyCP web interface for Nginx changes +- ✅ Use custom systemd unit `tenerifeprop.service` for process management + +### 2. Permissions Hierarchy (BrainyCP standard) +``` +/home/nero/ : root:root, 755 — managed by BrainyCP +/home/nero/sites/ : root:root, 755 — managed by BrainyCP +/home/nero/sites/tenerifeprop.es/ : nero:nero, 755 — site content + All files inside : nero:nero, 644 + All directories : nero:nero, 755 + .env : nero:nero, 600 (restricted) + data/ : nero:nero, 755 + tenerifeprop.db : nero:nero, 644 +``` + +NEVER change `/home/nero` or `/home/nero/sites/` ownership from `root:root`. +ONLY change contents inside `/home/nero/sites/tenerifeprop.es/` to `nero:nero`. + +### 3. Bun Location (not in PATH) +``` +Binary: /home/nero/.bun/bin/bun +Version: 1.3.14 +Owner: root:root (installation) +User execution: via su - nero -s /bin/bash -c '...' +``` + +Always use full path to bun on server. + +### 4. Deployment Flow (Git-based) +``` +[Local] dev branch → commit → push → PR → main +[Server] production branch ← git pull origin production → restart +``` + +The server tracks `production` branch, not `main` or `dev`. + +### 5. Restart Sequence +```bash +# Correct way to restart +systemctl restart tenerifeprop + +# After updating files +systemctl restart tenerifeprop + +# After updating .env +systemctl restart tenerifeprop +``` + +### 6. Healthcheck Endpoint +```bash +curl -s http://localhost:3003/api/settings +# Expected: {"success":true,"data":{...}} +``` + +### 7. Log Inspection +```bash +journalctl -u tenerifeprop -f +``` + +### 8. Backup Before Deploy +```bash +/home/nero/sites/tenerifeprop.es/scripts/backup.sh +# Creates: /backup/db/tenerifeprop-YYYYMMDD-HHMMSS.db +# Keeps: 7 days of backups +# Cron: Daily at 03:00 +``` + +### 9. Deploy Script +```bash +/home/nero/sites/tenerifeprop.es/scripts/deploy.sh +``` +What it does: +1. Backup database. +2. Fetch and reset to origin/production. +3. Run `bun install --production`. +4. Fix permissions (chown nero:nero, chmod 644/755). +5. Restart `tenerifeprop.service`. +6. Healthcheck (expect HTTP 200 on /api/settings). + +### 10. Environment Variables (production) +``` +NODE_ENV=production +PORT=3003 +RESEND_API_KEY= +TELEGRAM_BOT_TOKEN= +TELEGRAM_CHAT_ID= +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN= +GITEA_USER= +GITEA_PASS= +``` + +File location: `/home/nero/sites/tenerifeprop.es/.env` +Permissions: `600` (read-only owner) + +## Synchronization Workflow + +### From local to production (via Git) + +1. Developer commits to `dev`: +```bash +git add . +git commit -m "feat: new feature" +git push origin dev +``` + +2. Merge to `main` (via PR or manually): +```bash +git checkout main +git merge dev +git push origin main +``` + +3. Push `main` to `production` branch: +```bash +git push origin main:production +# or +git checkout production +git merge main +git push origin production +``` + +4. Deploy on server: +```bash +ssh root@46.175.149.131 +cd /home/nero/sites/tenerifeprop.es +./scripts/deploy.sh +``` + +### Auto-deploy (optional) +Add webhook in Gitea to call POST endpoint. +Server endpoint runs `./scripts/deploy.sh`. + +## File Structure on Server +``` +/home/nero/sites/tenerifeprop.es/ +├── .env # Env vars (secrets) +├── .git/ # Git repository (production branch) +├── data/ +│ └── tenerifeprop.db # SQLite database +├── node_modules/ # Dependencies +├── public/ # Static files +├── scripts/ +│ ├── deploy.sh # Deployment script +│ └── backup.sh # Backup script +├── src/ # Source code +├── package.json +├── bun.lock +└── docs/ # Documentation +``` + +## Forbidden Actions +- ❌ Do NOT run `git push --force` on production branch +- ❌ Do NOT edit `.env` without backup +- ❌ Do NOT delete `data/tenerifeprop.db` without backup +- ❌ Do NOT change Bun version without testing locally +- ❌ Do NOT modify BrainyCP Nginx configs directly +- ❌ Do NOT use port other than 3003 without updating Nginx +- ❌ Do NOT change `/home/nero` or `/home/nero/sites/` ownership diff --git a/docs/BRAINYCP_DEPLOY_GUIDE.md b/docs/BRAINYCP_DEPLOY_GUIDE.md new file mode 100644 index 0000000..a46bfac --- /dev/null +++ b/docs/BRAINYCP_DEPLOY_GUIDE.md @@ -0,0 +1,309 @@ +# Руководство по деплою TenerifeProp на BrainyCP + +## Для кого это руководство +Для разработчиков и DevOps-инженеров, которые будут разворачивать или обновлять проект TenerifeProp на хостинге с панелью BrainyCP. + +## 1. Предварительные требования + +### На сервере (что уже должно быть) +- **BrainyCP** установлена и работает. +- **Домен** добавлен в панель (`tenerifeprop.es`). +- **NodeJS** установлен через панель BrainyCP (создаст заглушку на порту, например `3003`). +- **SSL** активирован (Let's Encrypt через панель). +- **SSH-доступ** к серверу с правами root. +- **Git** установлен (`git --version`). + +### На локальной машине +- Доступ к репозиторию `git.softuniq.eu/UniqueSoft/TenerifeProp`. +- SSH-ключ или логин/пароль для доступа к серверу. + +### Ветки проекта +``` +origin/dev — основная ветка разработки +origin/main — ветка релиза +origin/production — ветка продакшена на BrainyCP (создаётся при первом деплое) +``` + +## 2. Структура проекта на сервере + +``` +/home/nero/sites/tenerifeprop.es/ +├── .env # Переменные окружения +├── src/ # Серверный код +├── public/ # Статические файлы +├── data/ +│ └── tenerifeprop.db # SQLite база данных +├── node_modules/ # Зависимости +├── package.json +├── bun.lock +└── .git/ # Git репозиторий (если клонирован) +``` + +## 3. Первый деплой (ручной) + +### Шаг 1: Остановить заглушку BrainyCP +```bash +ssh root@46.175.149.131 +systemctl stop nodejs@3003.service +systemctl disable nodejs@3003.service +``` + +### Шаг 2: Установить Bun +```bash +# Установка Bun в папку пользователя (не трогает системный Node.js) +curl -fsSL https://bun.sh/install | BUN_INSTALL=/home/nero/.bun bash +chown -R nero:nero /home/nero/.bun +``` + +Путь к Bun: `/home/nero/.bun/bin/bun` + +### Шаг 3: Клонировать репозиторий +```bash +cd /home/nero/sites/tenerifeprop.es +# Очистить заглушку (сохранить .well-known для SSL) +rm -f index.js app.js app.css +git clone https://git.softuniq.eu/UniqueSoft/TenerifeProp.git . +``` + +### Шаг 4: Переключиться на ветку production +```bash +git checkout -b production origin/production +# или если ветки нет: +git checkout -b production +``` + +### Шаг 5: Создать `.env` +```bash +cat > .env <<'EOF' +NODE_ENV=production +PORT=3003 +RESEND_API_KEY=your_key_here +TELEGRAM_BOT_TOKEN=your_token_here +TELEGRAM_CHAT_ID=your_chat_id_here +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN=your_gitea_token +EOF +chmod 600 .env +chown nero:nero .env +``` + +### Шаг 6: Установить зависимости +```bash +/home/nero/.bun/bin/bun install --production +``` + +### Шаг 7: Настроить systemd +Создать файл `/etc/systemd/system/tenerifeprop.service`: + +```ini +[Unit] +Description=TenerifeProp Bun Server +After=network.target + +[Service] +Type=simple +User=nero +WorkingDirectory=/home/nero/sites/tenerifeprop.es +Environment=NODE_ENV=production +Environment=PORT=3003 +EnvironmentFile=/home/nero/sites/tenerifeprop.es/.env +ExecStart=/home/nero/.bun/bin/bun run src/server/index.ts +Restart=always +RestartSec=5 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target +``` + +Активировать: +```bash +systemctl daemon-reload +systemctl enable tenerifeprop.service +systemctl start tenerifeprop.service +``` + +### Шаг 8: Проверить работу +```bash +# Локальный тест +curl http://localhost:3003/api/settings +# Ожидается: {"success":true,"data":{...}} + +# Публичный тест +curl https://tenerifeprop.es/api/settings + +# Логи +journalctl -u tenerifeprop -f +``` + +## 4. Обновление проекта (Git-based deploy) + +### Метод A: Скрипт автообновления (рекомендуется) + +На сервере есть скрипт `/home/nero/sites/tenerifeprop.es/scripts/deploy.sh`. + +```bash +# Обновить из ветки production +cd /home/nero/sites/tenerifeprop.es +./scripts/deploy.sh +``` + +Что делает скрипт: +1. `git fetch origin` +2. `git reset --hard origin/production` +3. `bun install --production` +4. `chown -R nero:nero .` +5. `chmod 600 .env` +6. `systemctl restart tenerifeprop` +7. Проверка healthcheck + +### Метод B: Ручное обновление + +```bash +ssh root@46.175.149.131 +cd /home/nero/sites/tenerifeprop.es + +# Переключиться на production +git checkout production +git pull origin production + +# Установить зависимости (если изменились) +/home/nero/.bun/bin/bun install --production + +# Права +chown -R nero:nero . +chmod 600 .env + +# Перезапустить +systemctl restart tenerifeprop + +# Проверить +systemctl status tenerifeprop +curl http://localhost:3003/api/settings +``` + +## 5. Git workflow для синхронизации + +### Схема веток +``` +[dev] → commit, push → PR → [main] → tag → PR → [production] → auto-deploy +``` + +### Как внести изменения + +1. **Разработка** (на локальной машине или в Docker): + ```bash + git checkout dev + # вносишь изменения + git add . + git commit -m "feat: новая фича" + git push origin dev + ``` + +2. **Релиз** (merge в main): + ```bash + git checkout main + git merge dev + git tag -a v1.1.0 -m "Release v1.1.0" + git push origin main --tags + ``` + +3. **Деплой** (merge в production): + ```bash + git checkout production + git merge main + git push origin production + ``` + +4. **Авто-деплой** (на сервере): + - Вебхук Gitea → сервер получает уведомление. + - Или `git pull` по cron каждые 5 минут. + - Или запускаешь `./scripts/deploy.sh` вручную. + +### Webhook (Gitea → сервер) + +В Gitea (Settings → Webhooks → Add Webhook): +- URL: `https://tenerifeprop.es/api/admin/deploy` +- Секретный ключ: настрой в `.env` (`DEPLOY_SECRET`) +- События: `push` + +На сервере нужен endpoint `/api/admin/deploy`, который: +1. Проверяет секретный ключ. +2. Запускает `git pull origin production`. +3. Перезапускает сервер. + +Это усложнение — рекомендуется начать со скрипта. + +## 6. Резервное копирование базы данных + +### Дамп БД (на сервере) +```bash +cd /home/nero/sites/tenerifeprop.es +# SQLite — просто копируем файл +cp data/tenerifeprop.db /backup/tenerifeprop-$(date +%Y%m%d).db +``` + +### Восстановление +```bash +systemctl stop tenerifeprop +cp /backup/tenerifeprop-20260513.db data/tenerifeprop.db +chown nero:nero data/tenerifeprop.db +chmod 644 data/tenerifeprop.db +systemctl start tenerifeprop +``` + +## 7. Troubleshooting + +| Проблема | Решение | +|----------|---------| +| Bun не найден | Проверь `ls /home/nero/.bun/bin/bun`. Если нет — переустановить. | +| Порт 3003 занят | `lsof -i :3003` → найти и убить процесс. Или изменить порт в `.env` и Nginx. | +| Nginx не проксирует | Проверить конфиг BrainyCP. Сравнить с рабочим сайтом. | +| Permission denied | `chown -R nero:nero /home/nero/sites/tenerifeprop.es` | +| SQLite database is locked | Остановить сервер, удалить `*.db-shm` и `*.db-wal`, запустить. | +| 502 Bad Gateway | Backend не запущен. `systemctl start tenerifeprop`. | +| Статика 404 | Проверить пути в `public/`. CSS/JS должны быть доступны через Bun. | + +## 8. Команды для мониторинга + +```bash +# Статус сервера +systemctl status tenerifeprop + +# Логи реального времени +journalctl -u tenerifeprop -f + +# Проверка порта +ss -tlnp | grep 3003 +lsof -i :3003 + +# Проверка процесса Bun +ps aux | grep bun + +# Проверка API +curl -s http://localhost:3003/api/settings | python -m json.tool + +# Проверка SSL +openssl s_client -connect tenerifeprop.es:443 -servername tenerifeprop.es + +# Ресурсы сервера +htop +df -h +free -h +``` + +## 9. Контакты и доступы + +| Параметр | Значение | +|----------|----------| +| Сервер | `46.175.149.131` | +| SSH логин | `root` | +| Панель | BrainyCP (пользователь `nero`) | +| Домен | `tenerifeprop.es` | +| Backend порт | `3003` | +| Bun путь | `/home/nero/.bun/bin/bun` | +| Папка сайта | `/home/nero/sites/tenerifeprop.es` | +| Логи | `journalctl -u tenerifeprop` | +| База данных | `data/tenerifeprop.db` (SQLite) | +| GitHub/Gitea | `https://git.softuniq.eu/UniqueSoft/TenerifeProp` | diff --git a/scripts/sync-production.sh b/scripts/sync-production.sh new file mode 100644 index 0000000..90f8983 --- /dev/null +++ b/scripts/sync-production.sh @@ -0,0 +1,123 @@ +#!/bin/bash +set -e + +# TenerifeProp Production Sync Script +# Usage: ./scripts/sync-production.sh [command] +# Commands: +# full - Full sync with git, install, restart (default) +# quick - Only restart server (if only .env changed) +# status - Show server status +# logs - Show logs +# backup - Backup database only + +PROJECT_DIR="/home/nero/sites/tenerifeprop.es" +BUN="/home/nero/.bun/bin/bun" +SERVICE="tenerifeprop" +GITEA_URL="https://git.softuniq.eu/UniqueSoft/TenerifeProp" + +cd "$PROJECT_DIR" + +show_status() { + echo "=== Server Status ===" + systemctl status "$SERVICE" --no-pager + echo "" + echo "=== CPU/Memory ===" + ps aux | grep "$SERVICE" | grep -v grep + echo "" + echo "=== Disk Space ===" + df -h "$PROJECT_DIR" + echo "" + echo "=== Database Size ===" + ls -lh "$PROJECT_DIR/data/tenerifeprop.db" + echo "" + echo "=== Port Check ===" + ss -tlnp | grep :3003 || echo "Port 3003 NOT listening" + echo "" + echo "=== Healthcheck ===" + curl -s -o /dev/null -w '%{http_code}' http://localhost:3003/api/settings + echo " - /api/settings" +} + +show_logs() { + journalctl -u "$SERVICE" -f --no-pager +} + +backup_db() { + mkdir -p /backup/db + BACKUP_FILE="/backup/db/tenerifeprop-$(date +%Y%m%d-%H%M%S).db" + cp "$PROJECT_DIR/data/tenerifeprop.db" "$BACKUP_FILE" + echo "✅ Backup created: $BACKUP_FILE" + find /backup/db -name '*.db' -mtime +7 -delete + echo "✅ Old backups (7+ days) cleaned" +} + +deploy() { + echo "=== Deploy started at $(date) ===" + + # Backup database + backup_db + + # Git sync + echo "=== Syncing with Gitea (production branch)... ===" + git fetch origin production + git reset --hard origin/production + + # Install dependencies + "${BUN}" install --production + + # Fix permissions + chown -R nero:nero "$PROJECT_DIR" + chmod 600 "$PROJECT_DIR/.env" + find "$PROJECT_DIR" -type f -not -path '*/node_modules/*' -exec chmod 644 {} \; + find "$PROJECT_DIR" -type d -exec chmod 755 {} \; + chmod 644 "$PROJECT_DIR/data/tenerifeprop.db" 2>/dev/null || true + + # Restart + echo "=== Restarting $SERVICE ===" + systemctl restart "$SERVICE" + + # Healthcheck + sleep 2 + HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:3003/api/settings) + if [ "$HTTP_CODE" = "200" ]; then + echo "✅ Deploy successful. Healthcheck: HTTP 200" + # Tag the deploy + git tag "deploy-$(date +%Y%m%d-%H%M%S)" || true + else + echo "❌ Deploy failed. Healthcheck: HTTP $HTTP_CODE" + echo "Check logs: journalctl -u $SERVICE --no-pager -n 50" + exit 1 + fi + + echo "=== Deploy completed at $(date) ===" +} + +quick_restart() { + echo "=== Quick restart ===" + systemctl restart "$SERVICE" + sleep 2 + curl -s -o /dev/null -w '%{http_code}' http://localhost:3003/api/settings + echo " - Healthcheck" +} + +case "${1:-full}" in + full) + deploy + ;; + quick) + quick_restart + ;; + status) + show_status + ;; + logs) + show_logs + ;; + backup) + backup_db + ;; + *) + echo "Usage: $(basename "$0") {full|quick|status|logs|backup}" + exit 1 + ;; +esac