Initial commit
This commit is contained in:
@@ -0,0 +1,836 @@
|
||||
# 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-ассистент + Владелец
|
||||
**Статус:** Готов к реализации после утверждения
|
||||
Reference in New Issue
Block a user