Files
site_aegisone/service/docs/AEGISONE_INFRASTRUCTURE_PLAN.md
T
2026-05-17 05:22:06 +03:00

837 lines
43 KiB
Markdown
Raw 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.
# AegisOne Engineering — План миграции инфраструктуры и переписывания сервисной части
> **Статус:** План утверждён, готов к реализации
> **Дата:** 2026-05-17
> **Команда:** Владелец + AI-ассистент
> **Примечание:** Если при реализации возникнут вопросы — лучше уточнить, чем переделывать потом.
---
## 1. Текущее состояние
### 1.1. Публичная часть (aegisone.ru)
- **Технологии:** PHP 7.4, MySQL, inline CSS/JS
- **Хостинг:** Shared-хостинг (проблемы: HTTP 302-редирект, блокировка `/assets/`, отключённый `RewriteEngine`, PHP 7.4 тупик)
- **Страницы:** Главная, услуги, блог, контакты, форма обратной связи
- **SEO:** `robots.txt`, `sitemap.xml`, канонические URL
- **Решение:** **Не трогать.** Перенести на VPS как есть в Docker-контейнер.
### 1.2. Сервисная часть (service.aegisone.ru)
- **Технологии:** PHP 7.4, MySQL, inline CSS/JS
- **Функционал:** Админ-панель (управление пользователями, объектами, SLA, опросниками, блогом, документами), расчёты (Risk Score, Object Index, SLA price), паспорта объектов
- **Проблемы:** PHP 7.4 ограничивает развитие, нет автоматизации отчётов, нет интеграций
- **Решение:** **Полностью переписать на Python/FastAPI + Jinja2**
### 1.3. Инфраструктура
- **VPS:** Уже есть, на нём один проект (FastAPI + Uvicorn + Celery + Nginx + PostgreSQL + Redis + Alembic)
- **Хостинг:** Платный, планируется отказ
- **Git:** Нет централизованного сервера, работа на локальной машине
- **SSL:** От регистратора домена (статический, неудобно для мультидомена)
- **Домены:** `aegisone.ru` (публичная часть), планируется `service.aegisone.ru` (админка)
---
## 2. Целевая архитектура
```
┌─────────────────────────────────────────────────────────────────────┐
│ VPS │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Nginx (reverse proxy + SSL) │ │
│ │ порт 80/443, Let's Encrypt │ │
│ │ │ │
│ │ aegisone.ru ──────────────► php-fpm container (порт 9000) │ │
│ │ service.aegisone.ru ─────► fastapi container (порт 8000) │ │
│ │ other-project.ru ────────► project2 container (порт 8001) │ │
│ │ git.aegisone.ru ─────────► gitea container (порт 3000) │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ AegisOne PHP │ │ AegisOne Python │ │ Other Project │ │
│ │ (публичная) │ │ (админка) │ │ (FastAPI) │ │
│ │ │ │ │ │ │ │
│ │ • Главная │ │ • Аутентификация│ │ • ... │ │
│ │ • Услуги │ │ • Пользователи │ │ │ │
│ │ • Блог │ │ • Объекты │ │ │ │
│ │ • Контакты │ │ • Клиенты │ │ │ │
│ │ • FAQ │ │ • SLA │ │ │ │
│ │ • Карусель │ │ • Опросники │ │ │ │
│ │ • Форма │ │ • Расчёты │ │ │ │
│ │ │ │ • Отчёты (PDF) │ │ │ │
│ │ │ │ • Документы │ │ │ │
│ │ │ │ • Yandex Disk │ │ │ │
│ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └──────────┬──────────┘ │ │
│ │ │ │
│ ┌──────────▼──────────┐ ┌─────────▼────────┐ │
│ │ PostgreSQL │ │ PostgreSQL │ │
│ │ (AegisOne БД) │ │ (Project 2 БД) │ │
│ │ │ │ │ │
│ │ • users │ │ • ... │ │
│ │ • customers │ │ │ │
│ │ • objects │ │ │ │
│ │ • sla_contracts │ │ │ │
│ │ • questionnaire_* │ │ │ │
│ │ • blog_posts │ │ │ │
│ │ • cases │ │ │ │
│ │ • documents │ │ │ │
│ │ • photos │ │ │ │
│ │ • audit_log │ │ │ │
│ └─────────────────────┘ └──────────────────┘ │
│ │ │
│ ┌──────────▼──────────┐ │
│ │ Redis │ (кэш, Celery broker) │
│ └─────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Celery Workers (Python) │ │
│ │ │ │
│ │ • Генерация отчётов (PDF, Excel) │ │
│ │ • Загрузка фото на Yandex Disk │ │
│ │ • Интеграция с 1С (по мере необходимости) │ │
│ │ • Фоновые расчёты, уведомления │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Gitea │ │ Certbot │ │
│ │ (Git-сервер) │ │ (Let's Encrypt) │ │
│ │ │ │ │ │
│ │ • aegisone-php │ │ • aegisone.ru │ │
│ │ • aegisone-py │ │ • service.aeg.. │ │
│ │ • project2 │ │ • other.ru │ │
│ │ • CI/CD Actions │ │ • автообновление│ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Yandex Disk API (облачное хранилище) │ │
│ │ │ │
│ │ /AegisOne/ │ │
│ │ ├── objects/{object_id}/ │ │
│ │ │ ├── photos/{photo_id}.jpg │ │
│ │ │ └── documents/{doc_id}/ │ │
│ │ │ ├── {photo_id}.jpg │ │
│ │ │ └── report_{doc_id}.pdf │ │
│ │ └── ... │ │
│ │ │ │
│ │ В PostgreSQL хранятся: file_id, file_url, привязка к объекту│ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. Технологический стек
### 3.1. Публичная часть (без изменений)
| Компонент | Технология | Примечание |
|---|---|---|
| Язык | PHP 7.4 | Не обновлять, не трогать |
| БД | MySQL | Мигрировать на PostgreSQL позже (опционально) |
| Веб-сервер | Nginx + PHP-FPM | В Docker-контейнере |
| CSS/JS | Inline | Без изменений |
### 3.2. Сервисная часть (Python)
| Компонент | Технология | Примечание |
|---|---|---|
| Язык | Python 3.11+ | |
| Фреймворк | FastAPI | REST API + серверный рендеринг |
| Шаблоны | Jinja2 | Серверный рендеринг, как сейчас PHP |
| Веб-сервер | Uvicorn | ASGI-сервер |
| ORM | SQLAlchemy 2.0 + Alembic | Миграции БД |
| БД | PostgreSQL 15+ | Единая БД для всех проектов |
| Аутентификация | JWT (python-jose) | Токены для API и сессий |
| Фоновые задачи | Celery + Redis | Отчёты, загрузка файлов, интеграции |
| Генерация отчётов | WeasyPrint (PDF), openpyxl (Excel) | |
| Yandex Disk | yandex-disk SDK / REST API | OAuth 2.0 |
| Валидация | Pydantic | Схемы данных |
### 3.3. Инфраструктура
| Компонент | Технология | Примечание |
|---|---|---|
| Контейнеризация | Docker + Docker Compose | |
| Reverse proxy | Nginx | Маршрутизация по доменам |
| SSL | Let's Encrypt + Certbot | Автообновление |
| Git-сервер | Gitea | Лёгкий, встроенный CI/CD |
| CI/CD | Gitea Actions | Автоматический деплой |
| Мониторинг | (опционально) Uptime Kuma | |
### 3.4. Мобильные приложения (будущее)
| Компонент | Технология | Примечание |
|---|---|---|
| Фреймворк | Flutter | |
| API | FastAPI REST endpoints | Те же, что для веб-админки |
| Аутентификация | JWT | |
---
## 4. Почему Jinja2, а не SPA
### 4.1. Сравнение
| Критерий | Jinja2 (SSR) | SPA (React/Vue) |
|---|---|---|
| Серверная нагрузка | Рендерит HTML на сервере | Отдаёт статику + JSON API |
| Масштабирование | Горизонтальное: Nginx → N FastAPI инстансов | CDN для статики + Nginx → API |
| Сложность разработки | Один стек, один деплой | Два стека, два деплоя, CORS |
| Скорость разработки | Быстро | Медленнее |
| Команда | 1-2 Python-разработчика | Python + JS/TS разработчики |
| SEO | Не нужен (админка закрыта) | Не нужен |
| Мобильные приложения | API тот же — Flutter подключается | API тот же — Flutter подключается |
| Поддержка | Проще | Сложнее (два кодовых базы) |
### 4.2. Масштабирование Jinja2 по России
При росте нагрузки:
1. **Вертикальное:** Увеличить ресурсы VPS (CPU, RAM)
2. **Горизонтальное:** Несколько инстансов FastAPI за Nginx (load balancing)
3. **Кэширование:** Redis для кэширования тяжёлых запросов
4. **CDN:** Для статики (CSS, JS, изображения) — Cloudflare или аналог
Jinja2 **не является узким местом**. Узким местом будет БД или внешние API (Yandex Disk, 1С).
### 4.3. Вердикт
**Jinja2 — правильный выбор.** Для B2B-админки SPA — это оверинжиниринг. Jinja2 даёт:
- Быструю разработку
- Простую поддержку
- Легкое масштабирование
- Единую кодовую базу
- Готовность к мобильным приложениям (тот же API)
---
## 5. Этапы реализации
### Этап 1: Docker-фундамент на VPS (1-2 недели)
**Цель:** Подготовить VPS для мультипроектной работы с Docker.
#### 1.1. Установка Docker и Docker Compose
```bash
# На VPS (Ubuntu/Debian)
apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
#### 1.2. Базовая структура директорий на VPS
```
/opt/
├── nginx-proxy/ # Nginx reverse proxy + Certbot
│ ├── docker-compose.yml
│ ├── nginx.conf
│ └── certs/ # Let's Encrypt сертификаты
├── gitea/ # Git-сервер
│ ├── docker-compose.yml
│ └── data/ # Данные Gitea
├── aegisone-php/ # Публичная часть (PHP)
│ ├── docker-compose.yml
│ └── src/ # Исходный код (git clone)
├── aegisone-py/ # Сервисная часть (Python)
│ ├── docker-compose.yml
│ ├── app/ # FastAPI приложение
│ ├── migrations/ # Alembic миграции
│ └── requirements.txt
└── project2/ # Существующий проект
└── docker-compose.yml
```
#### 1.3. Nginx reverse proxy + Certbot
- Один Nginx-контейнер на портах 80/443
- Маршрутизация по `server_name`:
- `aegisone.ru``aegisone-php:80`
- `service.aegisone.ru``aegisone-py:8000`
- `git.aegisone.ru``gitea:3000`
- `other-project.ru``project2:8000`
- Certbot в отдельном контейнере или встроенный (nginx-proxy + acme-companion)
#### 1.4. Gitea (Git-сервер)
- Docker-образ `gitea/gitea:latest`
- Порт 3000 → `git.aegisone.ru`
- PostgreSQL для данных Gitea
- Встроенный CI/CD (Gitea Actions)
- Репозитории:
- `aegisone-php` (публичная часть, перенос с текущего хостинга)
- `aegisone-py` (новая сервисная часть)
- `project2` (существующий проект)
- `infra` (конфигурации Docker, Nginx, CI/CD)
#### 1.5. Обёртка существующего проекта в Docker
- Создать `docker-compose.yml` для project2
- Протестировать работоспособность
- Настроить домен `other-project.ru`
**Критерий завершения этапа:**
- [ ] Docker + Docker Compose установлены
- [ ] Nginx reverse proxy работает, маршрутизирует по доменам
- [ ] Certbot выдаёт SSL-сертификаты (Let's Encrypt)
- [ ] Gitea запущен на `git.aegisone.ru`
- [ ] Существующий проект работает в Docker
- [ ] Все домены доступны по HTTPS
---
### Этап 2: Перенос AegisOne на VPS (1 неделя)
**Цель:** Перенести публичную часть с хостинга на VPS, отключить хостинг.
#### 2.1. Docker-контейнер для PHP
```yaml
# /opt/aegisone-php/docker-compose.yml
services:
nginx:
image: nginx:alpine
ports:
- "9080:80" # Внутренний порт, внешний через reverse proxy
volumes:
- ./src:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
php:
image: php:7.4-fpm
volumes:
- ./src:/var/www/html
environment:
- DB_HOST=mysql
- DB_NAME=aegisone
- DB_USER=aegisone
- DB_PASS=<password>
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: <root_password>
MYSQL_DATABASE: aegisone
MYSQL_USER: aegisone
MYSQL_PASSWORD: <password>
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
```
#### 2.2. Перенос файлов
- Скачать все файлы с хостинга (FTP/SFTP)
- Загрузить в `/opt/aegisone-php/src/`
- Настроить `config.php` для нового окружения (DB_HOST=mysql)
#### 2.3. Миграция БД
- Экспорт MySQL с хостинга: `mysqldump -u user -p db_name > backup.sql`
- Импорт в Docker MySQL: `docker exec -i aegisone-php-mysql mysql -u aegisone -p aegisone < backup.sql`
- Проверить работоспособность
#### 2.4. Настройка домена
- DNS: `aegisone.ru` → IP VPS
- Nginx reverse proxy: `server_name aegisone.ru``aegisone-php:9080`
- SSL: Certbot для `aegisone.ru`
#### 2.5. Тестирование и отключение хостинга
- Проверить все страницы: главная, услуги, блог, контакты, форма
- Проверить карусель, FAQ, тему (светлая/тёмная)
- Проверить Яндекс.Карту с переключением темы
- После подтверждения — отключить хостинг
**Критерий завершения этапа:**
- [ ] Публичная часть работает на VPS
- [ ] Все страницы загружаются корректно
- [ ] Форма обратной связи работает
- [ ] Яндекс.Карта переключает тему
- [ ] Домен `aegisone.ru` указывает на VPS
- [ ] Хостинг отключён
---
### Этап 3: Python-админка (FastAPI + Jinja2) (3-5 недель)
**Цель:** Полностью переписать сервисную часть на Python.
#### 3.1. Структура проекта
```
aegisone-py/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── alembic.ini
├── migrations/ # Alembic миграции
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI приложение
│ ├── config.py # Настройки (env vars)
│ ├── database.py # SQLAlchemy engine, session
│ ├── models/ # SQLAlchemy модели
│ │ ├── __init__.py
│ │ ├── user.py
│ │ ├── customer.py
│ │ ├── object.py
│ │ ├── sla.py
│ │ ├── questionnaire.py
│ │ ├── blog.py
│ │ ├── case.py
│ │ ├── document.py
│ │ ├── photo.py
│ │ └── audit_log.py
│ ├── schemas/ # Pydantic схемы
│ │ ├── __init__.py
│ │ ├── user.py
│ │ ├── customer.py
│ │ └── ...
│ ├── api/ # API endpoints
│ │ ├── __init__.py
│ │ ├── auth.py # Логин, JWT
│ │ ├── users.py
│ │ ├── customers.py
│ │ ├── objects.py
│ │ ├── sla.py
│ │ ├── questionnaire.py
│ │ ├── blog.py
│ │ ├── cases.py
│ │ ├── documents.py
│ │ └── reports.py
│ ├── templates/ # Jinja2 шаблоны
│ │ ├── base.html # Базовый шаблон
│ │ ├── login.html
│ │ ├── dashboard.html
│ │ ├── users/
│ │ ├── customers/
│ │ ├── objects/
│ │ ├── sla/
│ │ ├── questionnaire/
│ │ ├── blog/
│ │ ├── documents/
│ │ └── reports/
│ ├── static/ # CSS, JS, изображения
│ │ ├── css/
│ │ │ ├── service.css # Стили админки
│ │ │ └── ...
│ │ ├── js/
│ │ │ ├── main.js
│ │ │ └── ...
│ │ └── img/
│ ├── services/ # Бизнес-логика
│ │ ├── __init__.py
│ │ ├── auth_service.py
│ │ ├── calc_service.py # Расчёты (Risk Score, Object Index, SLA)
│ │ ├── report_service.py # Генерация отчётов
│ │ ├── yandex_disk_service.py # Интеграция с Yandex Disk
│ │ └── ...
│ ├── tasks/ # Celery задачи
│ │ ├── __init__.py
│ │ ├── reports.py
│ │ ├── yandex_disk.py
│ │ └── ...
│ └── utils/ # Утилиты
│ ├── __init__.py
│ ├── password.py
│ └── ...
└── tests/ # Тесты (опционально)
```
#### 3.2. Миграция данных из MySQL в PostgreSQL
- Создать Alembic миграции для всех таблиц
- Написать скрипт миграции данных:
- `users``users`
- `customers``customers`
- `objects``objects`
- `sla_contracts``sla_contracts`
- `questionnaire_sessions`, `questionnaire_answers`, `questionnaire_items` → аналогично
- `blog_posts``blog_posts`
- `cases``cases`
- `audit_log``audit_log`
- Протестировать миграцию на копии БД
#### 3.3. Аутентификация
- JWT-токены (python-jose)
- Логин/пароль (bcrypt)
- Роли: `owner`, `engineer`, `technician`
- Сессии через cookies (для Jinja2) + JWT (для API)
- CSRF-защита для форм
#### 3.4. CRUD-модули (по порядку приоритета)
**3.4.1. Пользователи (`/service/users/`)**
- Список, создание, редактирование, удаление
- Роль `owner` нельзя удалить, нельзя изменить роль
- Блокировка/разблокировка
- Аудит действий
**3.4.2. Клиенты (`/service/customers/`)**
- Список, создание, редактирование, удаление
- ИНН, КПП, юридический адрес, контакты
- Связь с объектами и SLA
**3.4.3. Объекты (`/service/objects/`)**
- Список, создание, редактирование, удаление
- Привязка к клиенту
- Тип, адрес, площадь, сотрудники
- Risk Score, Complexity Index, Object Index (авторасчёт)
- SLA price (авторасчёт)
**3.4.4. SLA контракты (`/service/sla/`)**
- Список, создание, редактирование, удаление
- Привязка к клиенту и объекту
- Тарифы: Базовый, Оптимальный, Максимальный
- Время реакции, периодичность ТО
- Статус: active, expired, cancelled, negotiation
**3.4.5. Опросник (`/service/questionnaire/`)**
- Создание новой сессии
- 5 шагов: Коммерческий, Технический, Эксплуатация, Риски, Расчёт SLA
- Вопросы из БД (`questionnaire_items`)
- Сохранение ответов
- Авторасчёт: Risk Score, Complexity Index, Infrastructure Load, Service History, Object Index, SLA Price
- Формирование паспорта объекта
**3.4.6. Блог (`/service/blog/`)**
- Список, создание, редактирование, удаление
- Категории: audit, sla, incident, supervision, documentation, risk, cases
- HTML-редактор (toolbar)
- Автогенерация slug из заголовка
- Статус: draft, published
**3.4.7. Примеры из практики (`/service/cases/`)**
- Список, создание, редактирование, удаление
- Заголовок, текст, эффект
- Сортировка, активность
**3.4.8. Документы (`/service/documents/`)**
- Список документов (из `service/docs/*.md`)
- Ручная сортировка
- Переименование
- Гранулярные права: view, edit, cancel (по ролям)
- JSON-хранилище прав (`docs_permissions.json`)
#### 3.5. Расчёты (перенос из PHP)
- `calc_risk_score()` — Risk Score
- `calc_complexity()` — Complexity Index
- `calc_infrastructure_load()` — Infrastructure Load
- `calc_service_history()` — Service History
- `calc_object_index()` — Object Index
- `calc_sla_price()` — SLA Price
- `risk_multiplier()` — множитель риска
- `risk_label()` — текстовая метка риска
- `object_class()` — класс объекта
- `fmt_money()` — форматирование денег
Все функции переписать на Python, покрыть тестами.
#### 3.6. Дашборд (`/service/dashboard/`)
- Метрики: количество объектов, активных SLA, открытых задач
- Графики (Chart.js или аналог)
- Быстрые действия
- Последние активности (audit_log)
#### 3.7. Фронтенд (Jinja2)
- Базовый шаблон (`base.html`) с:
- Боковой панелью (sidebar) с навигацией
- Верхней панелью (header) с пользователем и переключателем темы
- Основным контентом
- Темы: system → dark → light (localStorage, как сейчас)
- Кастомные скроллбары
- Тултипы на кнопках
- Модальные окна (создание/редактирование)
- Таблицы с поиском и пагинацией
- Адаптивность (мобильная версия)
**Критерий завершения этапа:**
- [ ] Все CRUD-модули работают
- [ ] Расчёты корректны (сравнить с PHP-версией)
- [ ] Миграция данных завершена
- [ ] Фронтенд полностью функционален
- [ ] Темы переключаются
- [ ] Мобильная версия работает
- [ ] `service.aegisone.ru` доступен по HTTPS
---
### Этап 4: Интеграции (2-3 недели)
**Цель:** Добавить генерацию отчётов, интеграцию с Yandex Disk, фоновые задачи.
#### 4.1. Yandex Disk API
- Регистрация приложения в Yandex OAuth
- Получение OAuth-токена
- SDK: `yandex-disk` или REST API через `requests`
- Структура папок:
```
/AegisOne/
├── objects/{object_id}/
│ ├── photos/
│ │ └── {photo_id}.jpg
│ └── documents/{doc_id}/
│ ├── {photo_id}.jpg
│ └── report_{doc_id}.pdf
└── ...
```
- Эндпоинты:
- `POST /api/documents/{id}/upload-photo` — загрузка фото
- `GET /api/documents/{id}/photos` — список фото
- `DELETE /api/photos/{id}` — удаление фото
- В БД: таблица `photos` (id, document_id, object_id, yandex_file_id, yandex_file_url, uploaded_at, uploaded_by)
#### 4.2. Генерация отчётов
- **PDF:** WeasyPrint (HTML → PDF)
- Шаблон паспорта объекта
- Шаблон отчёта по аудиту
- Шаблон SLA-контракта
- **Excel:** openpyxl
- Экспорт списка объектов
- Экспорт SLA-контрактов
- Экспорт отчётов по KPI
- Фоновая генерация через Celery (для тяжёлых отчётов)
#### 4.3. Celery (фоновые задачи)
- Broker: Redis
- Задачи:
- Генерация PDF-отчётов
- Загрузка фото на Yandex Disk
- Отправка уведомлений (email, Telegram)
- Интеграция с 1С (по мере необходимости)
- Мониторинг: Flower (веб-интерфейс для Celery)
#### 4.4. Интеграция с 1С (опционально, по мере необходимости)
- REST API 1С или OData
- Синхронизация: клиенты, объекты, договоры
- Фоновая задача Celery
**Критерий завершения этапа:**
- [ ] Yandex Disk API интегрирован
- [ ] Фото загружаются и привязываются к документам
- [ ] PDF-отчёты генерируются
- [ ] Excel-экспорт работает
- [ ] Celery запущен, задачи выполняются
- [ ] (Опционально) Интеграция с 1С настроена
---
### Этап 5: CI/CD и автоматизация деплоя (1 неделя)
**Цель:** Настроить автоматический деплой при push в Git.
#### 5.1. Gitea Actions (CI/CD)
- Встроенный CI/CD в Gitea (совместим с GitHub Actions)
- Workflow для `aegisone-py`:
```yaml
name: Deploy AegisOne Python
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push Docker image
run: |
docker build -t registry.git.aegisone.ru/aegisone-py:latest .
docker push registry.git.aegisone.ru/aegisone-py:latest
- name: Deploy to VPS
run: |
ssh user@vps "cd /opt/aegisone-py && docker compose pull && docker compose up -d"
```
#### 5.2. Структура репозиториев в Gitea
```
git.aegisone.ru/
├── aegisone/aegisone-php # Публичная часть (PHP)
├── aegisone/aegisone-py # Сервисная часть (Python)
├── aegisone/infra # Docker, Nginx, CI/CD конфиги
└── aegisone/project2 # Существующий проект
```
#### 5.3. Автоматический деплой
- Push в `main` → Gitea Actions → сборка Docker-образа → деплой на VPS
- Rollback: `docker compose down && docker compose up -d` с предыдущим образом
- Миграции БД: Alembic `upgrade head` автоматически при деплое
#### 5.4. Локальная разработка
- `docker-compose.dev.yml` для локальной разработки
- Hot-reload для Python (uvicorn --reload)
- Локальная БД (PostgreSQL в Docker)
- Синхронизация с VPS: `git push` → автоматический деплой
**Критерий завершения этапа:**
- [ ] Gitea Actions настроены для всех проектов
- [ ] Push в `main` → автоматический деплой
- [ ] Rollback работает
- [ ] Миграции БД применяются автоматически
- [ ] Локальная разработка через Docker
---
## 6. Миграция данных: MySQL → PostgreSQL
### 6.1. Таблицы для миграции
| MySQL таблица | PostgreSQL таблица | Примечание |
|---|---|---|
| `users` | `users` | Без изменений |
| `login_attempts` | `login_attempts` | Без изменений |
| `audit_log` | `audit_log` | Без изменений |
| `objects` | `objects` | + `customer_id` FK |
| `object_assignments` | `object_assignments` | Без изменений |
| `tasks` | `tasks` | Без изменений |
| `task_comments` | `task_comments` | Без изменений |
| `customers` | `customers` | Новая таблица |
| `sla_contracts` | `sla_contracts` | + `customer_id` FK, `contract_number`, `description`, `response_time_hours` |
| `incidents` | `incidents` | Без изменений |
| `engineer_kpi` | `engineer_kpi` | Без изменений |
| `questionnaire_sessions` | `questionnaire_sessions` | Без изменений |
| `questionnaire_answers` | `questionnaire_answers` | Без изменений |
| `questionnaire_items` | `questionnaire_items` | Новая таблица |
| `object_passports` | `object_passports` | Без изменений |
| `blog_posts` | `blog_posts` | ENUM категории изменён |
| `cases` | `cases` | Без изменений |
### 6.2. Скрипт миграции
```python
# scripts/migrate_mysql_to_postgres.py
import mysql.connector
import psycopg2
from psycopg2.extras import execute_batch
# Подключение к MySQL
mysql_conn = mysql.connector.connect(host='...', user='...', password='...', database='...')
mysql_cursor = mysql_conn.cursor(dictionary=True)
# Подключение к PostgreSQL
pg_conn = psycopg2.connect(host='...', user='...', password='...', database='...')
pg_cursor = pg_conn.cursor()
# Миграция каждой таблицы
tables = ['users', 'customers', 'objects', 'sla_contracts', ...]
for table in tables:
mysql_cursor.execute(f"SELECT * FROM {table}")
rows = mysql_cursor.fetchall()
if rows:
columns = rows[0].keys()
placeholders = ', '.join(['%s'] * len(columns))
cols = ', '.join(columns)
execute_batch(
pg_cursor,
f"INSERT INTO {table} ({cols}) VALUES ({placeholders}) ON CONFLICT DO NOTHING",
[tuple(row[col] for col in columns) for row in rows]
)
pg_conn.commit()
```
### 6.3. Проверка миграции
- Сравнить количество записей в MySQL и PostgreSQL
- Проверить FK-связи
- Протестировать CRUD-операции на PostgreSQL
- Откат: сохранить бэкап MySQL до миграции
---
## 7. Безопасность
### 7.1. Аутентификация и авторизация
- JWT-токены с expiration (1 час)
- Refresh tokens (7 дней)
- Роли: `owner`, `engineer`, `technician`
- Гранулярные права для документов (view, edit, cancel)
- CSRF-защита для форм
### 7.2. Защита данных
- Пароли: bcrypt (cost factor 12)
- HTTPS для всех доменов (Let's Encrypt)
- Firewall: только порты 80, 443, 22 (SSH)
- Docker: изоляция контейнеров, нет root в контейнерах
- БД: нет внешнего доступа, только из Docker-сети
### 7.3. Бэкапы
- PostgreSQL: `pg_dump` ежедневно (cron)
- Yandex Disk: файлы уже в облаке
- Gitea: бэкап репозиториев (tar)
- Хранение бэкапов: отдельный диск или облако
### 7.4. Мониторинг
- (Опционально) Uptime Kuma для мониторинга доступности
- Логи: Docker logs + ротация
- Алерты: email/Telegram при ошибках
---
## 8. Риски и митигация
| Риск | Вероятность | Влияние | Митигация |
|---|---|---|---|
| Ошибка миграции данных | Средняя | Высокое | Тестирование на копии, бэкап MySQL |
| Простои при деплое | Низкая | Среднее | Zero-downtime деплой (docker compose up -d) |
| Проблемы с SSL | Низкая | Среднее | Certbot автообновление, мониторинг |
| Yandex Disk API лимиты | Низкая | Низкое | Кэширование, retry logic |
| Нехватка ресурсов VPS | Средняя | Высокое | Мониторинг CPU/RAM, масштабирование |
| Ошибки в расчётах | Средняя | Высокое | Тесты, сравнение с PHP-версией |
---
## 9. Оценки времени
| Этап | Описание | Оценка |
|---|---|---|
| Этап 1 | Docker-фундамент | 1-2 недели |
| Этап 2 | Перенос AegisOne на VPS | 1 неделя |
| Этап 3 | Python-админка | 3-5 недель |
| Этап 4 | Интеграции | 2-3 недели |
| Этап 5 | CI/CD | 1 неделя |
| **Итого** | | **8-12 недель** |
---
## 10. Контрольные точки
| Точка | Описание | Критерий успеха |
|---|---|---|
| КП1 | Docker-фундамент готов | Все сервисы запущены, домены работают по HTTPS |
| КП2 | Публичная часть на VPS | aegisone.ru работает, хостинг отключён |
| КП3 | Python-админка MVP | CRUD для пользователей, объектов, SLA работает |
| КП4 | Python-админка полная | Все модули, расчёты, миграция данных завершены |
| КП5 | Интеграции | Yandex Disk, отчёты, Celery работают |
| КП6 | CI/CD | Автоматический деплой при push |
---
## 11. Открытые вопросы (уточнить перед реализацией)
> **Важно:** Если при реализации возникнут вопросы — лучше уточнить, чем переделывать потом.
1. **Миграция данных:** Переносим все данные из MySQL в PostgreSQL или начинаем с чистой БД? (Рекомендация: мигрировать)
2. **Домен для админки:** `service.aegisone.ru` или `app.aegisone.ru`? (Рекомендация: `service.aegisone.ru`)
3. **Yandex Disk OAuth:** Использовать токен приложения или OAuth с авторизацией пользователя? (Рекомендация: токен приложения для простоты)
4. **Генерация отчётов:** Какие именно отчёты нужны в первую очередь? (Паспорт объекта, отчёт по аудиту, SLA-контракт?)
5. **Интеграция с 1С:** Какая версия 1С? Какой метод интеграции (REST API, OData, файловый обмен)?
6. **Мониторинг:** Нужен ли Uptime Kuma или другой мониторинг? (Рекомендация: да, для продакшена)
7. **Бэкапы:** Где хранить бэкапы PostgreSQL? (Отдельный диск на VPS, облако, другой сервер?)
8. **Тестирование:** Покрывать ли код тестами? (Рекомендация: да, хотя бы критические расчёты)
9. **Документация:** Вести ли документацию по API? (Рекомендация: да, через FastAPI автоматическую /docs)
10. **Логирование:** Какой уровень логирования? Куда писать логи? (Рекомендация: INFO в stdout, Docker logs)
---
## 12. Следующие шаги
1. **Утвердить план** — ответить на открытые вопросы (раздел 11)
2. **Начать Этап 1** — Docker-фундамент на VPS
3. **Параллельно** — создать репозитории в Gitea, настроить CI/CD skeleton
4. **После Этапа 1** — приступить к Этапу 2 (перенос PHP)
5. **После Этапа 2** — приступить к Этапу 3 (Python-админка)
---
**Документ создан:** 2026-05-17
**Версия:** 1.0
**Автор:** AI-ассистент + Владелец
**Статус:** Готов к реализации после утверждения