Files
iistwin/DOCKER.md
Ильяс Султанов 639036c87e security(rls): ENABLE_RLS обязателен в production (fatal без флага)
Шаг 0.1 (завершение) плана production-готовности:
- прод: ENABLE_RLS=true включён, 31 таблица ENABLE+FORCE проверена
- код: fatal при NODE_ENV=production без ENABLE_RLS
- .env.example + DOCKER.md: пометки об обязательности
2026-09-08 10:55:58 +03:00

317 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Запуск через Docker
Приложение поддерживает несколько режимов развёртывания через Docker Compose.
Каждый режим активируется профилями `--profile`.
---
## Режимы базы данных
| Режим | База данных | Команда |
|---|---|---|
| Внешняя (Neon, любой Postgres) | Ваш хост | `docker compose up --build` |
| Встроенная PostgreSQL | Docker-контейнер | `docker compose --profile with-postgres up --build` |
## Режимы хранилища файлов
| Режим | Хранилище | Команда |
|---|---|---|
| Локальный диск (по умолчанию) | Папка `uploads/` | *(без флагов)* |
| MinIO S3 + WebDAV | MinIO-контейнер | `--profile with-minio` |
Профили можно комбинировать. Самый полный вариант («устройство в коробке»):
```bash
docker compose --profile with-postgres --profile with-minio up --build
```
---
## Режим 1: Внешняя база, локальный диск
Файлы хранятся в папке `uploads/` (сбрасываются при пересборке).
```env
DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require
JWT_SECRET=...
SESSION_SECRET=...
API_KEY_HMAC_SECRET=...
VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...
```
```bash
docker compose up --build
```
---
## Режим 2: Встроенная PostgreSQL, локальный диск
```env
# PostgreSQL
POSTGRES_DB=appdb
POSTGRES_USER=appuser
POSTGRES_PASSWORD=your-strong-db-password
DATABASE_URL=postgresql://appuser:your-strong-db-password@db:5432/appdb
# App
JWT_SECRET=...
SESSION_SECRET=...
API_KEY_HMAC_SECRET=...
VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...
```
```bash
docker compose --profile with-postgres up --build
```
---
## Режим 3: MinIO S3 + WebDAV (рекомендуется для устройств)
Файлы хранятся в MinIO — не теряются при перезапуске. WebDAV позволяет
просматривать и добавлять файлы через Windows Explorer, Finder, Cyberduck.
### Переменные окружения
```env
# PostgreSQL (если используете встроенную)
POSTGRES_DB=appdb
POSTGRES_USER=appuser
POSTGRES_PASSWORD=your-strong-db-password
DATABASE_URL=postgresql://appuser:your-strong-db-password@db:5432/appdb
# MinIO S3 — приложение видит MinIO как "minio" внутри Docker-сети
MINIO_ENDPOINT=http://minio:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=your-strong-minio-password
MINIO_BUCKET=files
# WebDAV — доступ через браузер/файловый менеджер на порту 8080
WEBDAV_USER=admin
WEBDAV_PASSWORD=your-webdav-password
# App
JWT_SECRET=...
SESSION_SECRET=...
API_KEY_HMAC_SECRET=...
VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...
```
### Запуск (всё сразу: PostgreSQL + App + MinIO + WebDAV)
```bash
docker compose --profile with-postgres --profile with-minio up --build
```
### Доступные интерфейсы
| Сервис | Адрес | Описание |
|---|---|---|
| iistwin приложение | `http://device-ip:5000` | Основной интерфейс |
| MinIO Console | `http://device-ip:9001` | Веб-интерфейс MinIO (логин: MINIO_ACCESS_KEY) |
| WebDAV | `http://device-ip:8080` | Файловый менеджер (логин: WEBDAV_USER) |
### Подключение WebDAV
**Windows Explorer:** Нажмите «Подключить сетевой диск» → введите `\\device-ip@8080\DavWWWRoot`
**macOS Finder:** Нажмите ⌘K → введите `http://device-ip:8080`
**Cyberduck / WinSCP:** Протокол WebDAV, хост `device-ip`, порт `8080`
---
## Локальные LLM через Ollama
Профиль `with-ollama` запускает [Ollama](https://ollama.com/) — локальный LLM-сервер — как отдельный контейнер. Модели **не скачиваются автоматически**: вы выбираете и загружаете их через интерфейс iistwin в разделе **Настройки → LLM Провайдеры**.
### Запуск с Ollama
```bash
# Только приложение + Ollama (внешняя БД)
docker compose --profile with-ollama up --build
# Всё сразу: PostgreSQL + App + Ollama
docker compose --profile with-postgres --profile with-ollama up --build
# Максимальная конфигурация: PostgreSQL + MinIO + WebDAV + Ollama
docker compose --profile with-postgres --profile with-minio --profile with-ollama up --build
```
При активном профиле `with-ollama` переменная `OLLAMA_BASE_URL=http://ollama:11434` передаётся в контейнер приложения автоматически через `docker-compose.yml`. Переопределить адрес можно через `.env`.
### Управление моделями через UI
После запуска откройте **Настройки → LLM Провайдеры**, добавьте провайдер типа `Ollama` с URL `http://ollama:11434` (или `http://localhost:11434` для локального запуска вне Docker) и воспользуйтесь разделом **«Модели Ollama»**:
- **Скачать модель** — введите имя (например `qwen2.5:7b`) и нажмите «Скачать». Сервер запустит `ollama pull`, скачивание занимает несколько минут.
- **Удалить модель** — нажмите кнопку удаления рядом с установленной моделью.
- **Список установленных моделей** — отображается с размером на диске.
### Рекомендуемые модели
| Тип | Модели |
|---|---|
| Эмбеддинги (RAG) | `bge-m3`, `mxbai-embed-large`, `qwen3-embedding:8b` |
| Чат / AI-боты | `qwen2.5:3b`, `qwen2.5:7b` |
### NVIDIA GPU
Для использования GPU раскомментируйте секцию `deploy` в сервисе `ollama` в файле `docker-compose.yml` и убедитесь, что на хосте установлен [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html).
### Порты
| Сервис | Порт | Описание |
|---|---|---|
| Ollama API | `11434` | REST API для управления моделями и инференса |
### Volumes
| Volume | Данные |
|---|---|
| `ollama_data` | Скачанные модели Ollama |
Для сброса данных (удаление всех скачанных моделей):
```bash
docker compose --profile with-ollama down -v
```
---
## Генерация VAPID-ключей для веб-пушей
VAPID-ключи используются для web push уведомлений. Без постоянных ключей при каждом перезапуске сервера все push-подписки браузеров становятся невалидными.
**Генерация ключей (выполнить один раз):**
```bash
npx web-push generate-vapid-keys
```
Команда выведет пару ключей:
```
Public Key:
BAxxx...
Private Key:
xxx...
```
Скопируйте значения в переменные окружения `VAPID_PUBLIC_KEY` и `VAPID_PRIVATE_KEY`. Если ключи не заданы, сервер выведет предупреждение в лог и сгенерирует временные ключи (только для текущей сессии).
---
## Sequence при старте
Независимо от режима, контейнер приложения всегда:
1. Проверяет доступность базы данных (`scripts/check-db.js`)
2. Применяет SQL-миграции из папки `migrations/` (`npm run db:migrate`)
3. Создаёт MinIO bucket если настроен S3 (автоматически)
4. Запускает сервер приложения (`npm run start`)
**Row Level Security (RLS):** при `ENABLE_RLS=true` на старте включается ENABLE+FORCE RLS
на 31 таблице с проверкой политик (schema drift, count политик) — при расхождении процесс падает.
**В production (`NODE_ENV=production`) `ENABLE_RLS=true` обязателен** — без него процесс не стартует.
В development флаг можно не задавать (политики существуют, но не активны).
---
## Изменение схемы базы данных
При добавлении новых таблиц или колонок в `shared/schema.ts` необходимо
создать SQL-файл миграции, который будет применён на всех серверах автоматически.
### Шаги
1. **Внесите изменения** в `shared/schema.ts`.
2. **Сгенерируйте миграцию** (создаёт SQL-файл в папке `migrations/`):
```bash
npm run db:generate
```
Команда создаст файл вида `migrations/0004_<name>.sql`.
3. **Закоммитьте оба файла** — изменённый `shared/schema.ts` и новый SQL-файл миграции:
```bash
git add shared/schema.ts migrations/
git commit -m "feat: add <description>"
```
4. **При деплое новой версии** (`docker compose pull && docker compose up -d`)
`db:migrate` автоматически применит новую миграцию, не затрагивая уже существующие данные.
> **Важно:** SQL-файлы миграций нельзя редактировать после коммита — только добавлять новые.
> Применённые миграции отслеживаются в таблице `__drizzle_migrations` в самой БД.
### Проверка миграций после деплоя
Чтобы убедиться, что все миграции применились корректно, выполните в PostgreSQL:
```sql
SELECT * FROM "__drizzle_migrations" ORDER BY created_at;
```
Ожидаемый результат: строки `0000_baseline`, `0001_sync_missing_columns`, …, `0007_sync_missing_columns_v2` (плюс все последующие).
Если строки отсутствуют или возникла ошибка — смотрите логи контейнера: `docker compose logs app`.
---
## Хранение данных (volumes)
| Volume | Данные |
|---|---|
| `postgres_data` | База данных PostgreSQL |
| `minio_data` | Файлы (загруженные через iistwin) |
| `ollama_data` | Скачанные LLM-модели |
Для полного сброса данных:
```bash
docker compose --profile with-postgres --profile with-minio --profile with-ollama down -v
```
---
## Быстрый справочник
| Цель | Команда |
|---|---|
| Только приложение (внешняя БД + диск) | `docker compose up --build` |
| + встроенная PostgreSQL | `docker compose --profile with-postgres up --build` |
| + MinIO + WebDAV (без PostgreSQL) | `docker compose --profile with-minio up --build` |
| + локальные LLM (Ollama) | `docker compose --profile with-ollama up --build` |
| Всё сразу | `docker compose --profile with-postgres --profile with-minio --profile with-ollama up --build` |
---
## Бэкапы PostgreSQL (production)
**Автоматические (на сервере, cron):**
- 3:00 — `pg_dump -Fc | gzip` → `/opt/crm/backups/crm-YYYYMMDD-HHMMSS.dump.gz` (скрипт `/opt/crm/scripts/backup-db.sh`), ротация 14 дней;
- 3:30 — CSV-экспорт основных таблиц → `/opt/crm/backups/csv/YYYYMMDD-HHMMSS/` (скрипт `/opt/crm/scripts/backup-csv.sh`), 7 копий;
- логи: `/var/log/crm-backup.log`.
**RPO/RTO:**
- RPO (точка потери данных): до 24 часов (дамп раз в сутки). Для уменьшения — чаще расписание или WAL-архивация (не настроено).
- RTO (время восстановления): ~15–30 минут (остановка app, pg_restore ~11 МБ дампа за минуты, запуск).
**Восстановление из дампа:**
```bash
docker compose stop app document-worker
docker exec crm-db-1 psql -U appuser -d postgres -c 'DROP DATABASE appdb'
docker exec crm-db-1 psql -U appuser -d postgres -c 'CREATE DATABASE appdb'
zcat /opt/crm/backups/crm-<дата>.dump.gz | docker exec -i crm-db-1 pg_restore -U appuser -d appdb --no-owner --no-privileges
docker compose up -d
```
**Проверка восстановления:** выполнена 2026-09-07 — дамп за 03:00 восстановлен в scratch-БД без ошибок (125 таблиц, данные консистентны). Повторять такую проверку после изменений схемы бэкапа.
**Не входит в pg_dump (бэкапить отдельно):**
- файлы MinIO (`minio_data`) — tar volume вручную;
- модели Ollama (`ollama_data`) — tar volume вручную;
- `/app/data` (`crm_data` — JSON-конфиги финансов, google-токены).
**Известный риск:** бэкапы лежат на том же VPS — при отказе диска/сервера потеряются вместе с продом. Требуется выгрузка наружу (S3/другой хост) — в бэклоге.