docs: add deployment guides, audit reports, and production sync scripts

- BRAINYCP_DEPLOY_GUIDE.md: complete human deployment guide
- AI_DEPLOY_CONTEXT.md: machine-readable deploy instructions for AI agents
- sync-production.sh: universal deployment script (full/quick/status/logs/backup)
- DEPLOY_PLAN.md: step-by-step deployment plan
- DEPLOY_AUDIT_REPORT.md: server audit results
- MIGRATION_AUDIT_REPORT.md: MySQL migration complexity analysis
- SERVER_AUDIT_REPORT.md: server environment audit
- Update README.md with BrainyCP deploy workflow and Git sync instructions

Refs: production server 46.175.149.131, domain tenerifeprop.es
This commit is contained in:
APAW Agent Sync
2026-05-13 23:44:38 +01:00
parent b7afaadb96
commit 3bcc705e3b
8 changed files with 1325 additions and 0 deletions

214
DEPLOY_AUDIT_REPORT.md Normal file
View File

@@ -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.28.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-процесса.
---
*Отчёт подготовлен после полного аудита сервера и кода проекта.*

180
DEPLOY_PLAN.md Normal file
View File

@@ -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` под реальные на сервере.

170
MIGRATION_AUDIT_REPORT.md Normal file
View File

@@ -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 строк) и конфигурации сервера.*

View File

@@ -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

90
SERVER_AUDIT_REPORT.md Normal file
View File

@@ -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 работает. Нужно только загрузить файлы проекта, установить зависимости и заменить заглушку на реальный процесс.
Если подтвердишь — выполню деплой.

182
docs/AI_DEPLOY_CONTEXT.md Normal file
View File

@@ -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

View File

@@ -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` |

123
scripts/sync-production.sh Normal file
View File

@@ -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