v1.7.0: refactor max_bot to flat structure, add VCF+UserModel+NLP history context, portal pages and proxy fixes
- Refactored max_bot from nested packages to flat module structure - Q2: Extended BotUser model (patronymic, email, org, address, vcf_raw, contact_hash, phone_verified, email_verified, last_interaction, total_conversations, total_tickets) - Q2: VCF parser (FN, N, TEL, EMAIL, ORG, ADR), upsert on re-contact, NLP history context (_get_user_history_context -> YandexGPT) - Q1: Broadcast preview modal with 10s confirmation timer - Q3: CSS var(--white)->var(--bg-card), var(--text)->var(--text-primary) - Q4: bot_settings showNotification(), editable max_bot_id - Q5: Webhook secret passthrough via X-Max-Bot-Api-Secret - Masking sensitive keys, dialog_cleared handler, migrate via _add_column_if_not_exists() - Rate limit (asyncio.sleep 0.5 per 10), dead code removed, conv.intent context in contact.py - Portal pages: bot_consent, bot_kb (edit), bot_settings, bot_test, bot_tickets, portal_settings - Tests: 21/21 passing, added test_yandex_gpt.py, test_email_sender.py - Deploy: deploy_full.sh, schema.sql, seed_knowledge_base.sql
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# aegisone.ru / www.aegisone.ru -> PHP frontend
|
||||
server {
|
||||
listen 80;
|
||||
server_name aegisone.ru www.aegisone.ru;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name aegisone.ru www.aegisone.ru;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/live/aegisone.ru.selfsigned/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/live/aegisone.ru.selfsigned/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# git.aegisone.ru -> Gitea
|
||||
server {
|
||||
listen 80;
|
||||
server_name git.aegisone.ru;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name git.aegisone.ru;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/live/aegisone.ru.selfsigned/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/live/aegisone.ru.selfsigned/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name max.aegisone.ru;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/live/max.aegisone.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/live/max.aegisone.ru/privkey.pem;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location /webhook {
|
||||
proxy_pass http://127.0.0.1:8002/webhook;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8002/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:8002/health;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name max.aegisone.ru;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# service.aegisone.ru -> FastAPI (aegisone-py)
|
||||
server {
|
||||
listen 80;
|
||||
server_name service.aegisone.ru;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
location /service-style.php {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
location /logo.php {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
location /assets/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name service.aegisone.ru;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/live/aegisone.ru.selfsigned/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/live/aegisone.ru.selfsigned/privkey.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
location /service-style.php {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
location /logo.php {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
location /assets/ {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: nginx-proxy
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./certs:/etc/nginx/certs:ro
|
||||
- ./conf.d:/etc/nginx/conf.d:ro
|
||||
- ./html:/usr/share/nginx/html:ro
|
||||
restart: unless-stopped
|
||||
|
||||
certbot:
|
||||
image: certbot/certbot:latest
|
||||
container_name: certbot
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./certs:/etc/letsencrypt
|
||||
- ./html:/var/www/certbot
|
||||
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,124 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo " AegisOne Nginx Fix Script"
|
||||
echo "=========================================="
|
||||
|
||||
NGINX_DIR="/opt/projects/nginx-proxy"
|
||||
|
||||
# 1. Остановить текущий nginx, если запущен
|
||||
echo ""
|
||||
echo "[1/7] Остановка текущего nginx..."
|
||||
cd "$NGINX_DIR"
|
||||
docker compose down 2>/dev/null || true
|
||||
|
||||
# 2. Сохранить старые конфиги
|
||||
echo ""
|
||||
echo "[2/7] Резервное копирование старых конфигов..."
|
||||
BACKUP_DIR="/root/nginx-backup-$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
if [ -f "$NGINX_DIR/nginx.conf" ]; then
|
||||
cp "$NGINX_DIR/nginx.conf" "$BACKUP_DIR/"
|
||||
fi
|
||||
if [ -d "$NGINX_DIR/conf.d" ]; then
|
||||
cp -r "$NGINX_DIR/conf.d" "$BACKUP_DIR/"
|
||||
fi
|
||||
echo " ✅ Бэкап: $BACKUP_DIR"
|
||||
|
||||
# 3. Создать структуру директорий
|
||||
echo ""
|
||||
echo "[3/7] Создание структуры..."
|
||||
mkdir -p "$NGINX_DIR/certs/live/aegisone.ru"
|
||||
mkdir -p "$NGINX_DIR/conf.d"
|
||||
mkdir -p "$NGINX_DIR/html"
|
||||
mkdir -p "$NGINX_DIR/certs"
|
||||
|
||||
# 4. Сгенерировать самоподписанный сертификат (временный, пока Let's Encrypt не выдаст настоящий)
|
||||
echo ""
|
||||
echo "[4/7] Генерация временного самоподписанного сертификата..."
|
||||
if [ ! -f "$NGINX_DIR/certs/live/aegisone.ru/fullchain.pem" ]; then
|
||||
openssl req -x509 -nodes -days 30 -newkey rsa:2048 \
|
||||
-keyout "$NGINX_DIR/certs/live/aegisone.ru/privkey.pem" \
|
||||
-out "$NGINX_DIR/certs/live/aegisone.ru/fullchain.pem" \
|
||||
-subj "/CN=aegisone.ru" \
|
||||
2>/dev/null || {
|
||||
echo " ⚠️ OpenSSL не найден, генерируем через Docker..."
|
||||
docker run --rm -v "$NGINX_DIR/certs:/certs" alpine:latest sh -c "
|
||||
apk add openssl >/dev/null 2>&1
|
||||
mkdir -p /certs/live/aegisone.ru
|
||||
openssl req -x509 -nodes -days 30 -newkey rsa:2048 \
|
||||
-keyout /certs/live/aegisone.ru/privkey.pem \
|
||||
-out /certs/live/aegisone.ru/fullchain.pem \
|
||||
-subj '/CN=aegisone.ru'
|
||||
"
|
||||
}
|
||||
echo " ✅ Самоподписанный сертификат создан"
|
||||
else
|
||||
echo " ℹ️ Сертификат уже существует"
|
||||
fi
|
||||
|
||||
# 5. Копирование конфигов
|
||||
echo ""
|
||||
echo "[5/7] Установка новых конфигов..."
|
||||
cp nginx.conf "$NGINX_DIR/nginx.conf"
|
||||
cp -r conf.d/* "$NGINX_DIR/conf.d/"
|
||||
echo " ✅ Конфиги скопированы"
|
||||
|
||||
# 6. Создать html/index.html для webroot (нужен certbot)
|
||||
echo ""
|
||||
echo "[6/7] Подготовка webroot..."
|
||||
mkdir -p "$NGINX_DIR/html/.well-known/acme-challenge"
|
||||
cat > "$NGINX_DIR/html/index.html" << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>AegisOne</title></head>
|
||||
<body><h1>AegisOne Engineering</h1></body>
|
||||
</html>
|
||||
EOF
|
||||
echo " ✅ Webroot готов"
|
||||
|
||||
# 7. Запуск nginx
|
||||
echo ""
|
||||
echo "[7/7] Запуск nginx..."
|
||||
cd "$NGINX_DIR"
|
||||
docker compose up -d
|
||||
sleep 3
|
||||
|
||||
# Проверка
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " Проверка..."
|
||||
echo "=========================================="
|
||||
|
||||
if docker compose exec nginx nginx -t 2>/dev/null; then
|
||||
echo " ✅ nginx: конфиг валидный"
|
||||
else
|
||||
echo " ❌ nginx: ошибка в конфиге"
|
||||
docker compose logs --tail=20 nginx
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверить отвечает ли nginx
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/ 2>/dev/null || echo "FAIL")
|
||||
echo " HTTP localhost: $HTTP_CODE"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo " Далее: получить Let's Encrypt сертификаты"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Запустите:"
|
||||
echo " cd $NGINX_DIR"
|
||||
echo " docker compose run --rm certbot certonly --webroot \\"
|
||||
echo " --webroot-path=/var/www/certbot \\"
|
||||
echo " -d aegisone.ru -d www.aegisone.ru \\"
|
||||
echo " -d service.aegisone.ru \\"
|
||||
echo " -d git.aegisone.ru \\"
|
||||
echo " --email admin@aegisone.ru \\"
|
||||
echo " --agree-tos --non-interactive"
|
||||
echo ""
|
||||
echo "После получения сертификатов перезапустите nginx:"
|
||||
echo " docker compose exec nginx nginx -s reload"
|
||||
echo ""
|
||||
echo "Готово!"
|
||||
@@ -0,0 +1,35 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 50M;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off valid=10s;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
Reference in New Issue
Block a user