837 lines
43 KiB
Markdown
837 lines
43 KiB
Markdown
# 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-ассистент + Владелец
|
||
**Статус:** Готов к реализации после утверждения
|