# MAX Bot Fixes — Implementation Plan v2 ## Phase 1: py_service (no rebuild, restart only) ### 1a. Fix ctx() mojibake **File:** `py_service/app/routers/service_pages.py:48` ```python # Add to ctx() dict: "page_name": kw.get("active_page", "") ``` ### 1b. Add broadcast page route **File:** `py_service/app/routers/service_pages.py` — after line 1396: ```python @router.get("/service/bot-settings/broadcasts") async def bot_broadcasts_page(request, db, user): return templates.TemplateResponse("pages/bot_broadcasts.html", ctx(request, user=user, active_page="bot-broadcasts", title="Рассылки")) ``` Plus proxy endpoints for broadcast data. ### 1c. Add sidebar link **File:** `py_service/app/templates/_sidebar.html` — after bot-storage line: ```html {% if role_permissions.get('bot_broadcasts', True) != False %}Рассылки{% endif %} ``` ### 1d. Create bot_broadcasts.html template **File:** `py_service/app/templates/pages/bot_broadcasts.html` Basically the broadcast section extracted from bot_analytics.html into its own page. ### 1e. Add try/except to all proxy endpoints **File:** `py_service/app/routers/service_pages.py` Create helper: ```python async def _proxy(method, path, json_body=None): try: async with aiohttp.ClientSession() as session: async with session.request(method, f"{MAX_BOT_URL}{path}", json=json_body) as resp: return JSONResponse(await resp.json()) except Exception as e: return JSONResponse({"error": f"Bot service unavailable: {e}", "ok": False}, status_code=503) ``` ### 1f. Update permission_config.py Add ALL missing routes (bot broadcasts, notifications, handoffs, risk-questions, storage, tickets) ## Phase 2: max_bot (rebuild required) ### 2a. Fix feature_key auto_notifications → notifications **File:** `max_bot/sql/bot_schema.sql:156` — change `'auto_notifications'` to `'notifications'` ### 2b. Fix commercial_offer → commercial (or vice versa) **File:** `max_bot/sql/bot_schema.sql:153` — change `'commercial_offer'` to `'commercial'` **File:** `max_bot/app/keyboards/inline.py:20` — ensure payload matches ### 2c. Fix test-run: add role:'bot' to test messages **File:** `max_bot/app/max_api.py:71` — add `msg["role"] = "bot"` **File:** `max_bot/app/main.py:407` — add `role: 'bot'` when copying greeting ### 2d. Fix flush→commit everywhere **Files:** `max_bot/app/main.py` - Lines 596, 620, 632, 644 → `db.commit()` - Lines 722, 725 → `db.commit()` - Lines 740, 755 → `db.commit()` - Lines 801, 814 → `db.commit()` - Line 852 → `db.commit()` **File:** `max_bot/app/database.py:15-17` — add session.commit(): ```python async def get_db(): async with async_session() as session: try: yield session await session.commit() except Exception: await session.rollback() raise ``` ### 2e. SQL migration: add recipient_ids to bot_broadcasts **File:** `max_bot/sql/migrations/v1.6.0_fixes.sql` ```sql ALTER TABLE bot_broadcasts ADD COLUMN IF NOT EXISTS recipient_ids JSONB DEFAULT '[]'::jsonb; ``` ### 2f. FSM persistence (optional) Create `bot_fsm_states` table + async save/load in FSM class. ### 2g. RMP permissions for engineer (optional) Add INSERT for engineer with bot_* menu keys. ## Phase 3: Replace categories ### 3a. SQL migration: ```sql DELETE FROM bot_categories; INSERT INTO bot_categories (name, description, icon_emoji, keywords, sort_order) VALUES ('Аудит безопасности', 'Независимая оценка систем видеонаблюдения, СКУД, ОПС', '🔍', '["аудит","безопасность","оценка","видеонаблюдение","скуд","опс"]', 1), ('Сервисное обслуживание / SLA', 'Абонентское обслуживание по SLA-контракту', '🛡️', '["сервис","sla","абонентский","обслуживание","контракт"]', 2), ('Реагирование на инциденты', 'Срочное реагирование при нештатных ситуациях', '🚨', '["инцидент","реагирование","срочный","нештатный","авария"]', 3), ('Технический надзор', 'Контроль качества при монтаже и пусконаладке', '📐', '["надзор","технический","контроль","качество","монтаж","пусконаладка"]', 4), ('Проектная документация', 'Разработка и согласование проектной документации', '📄', '["проект","документация","разработка","согласование"]', 5), ('Риск-инжиниринг', 'Оценка рисков, BCP, DRP, стратегия безопасности', '⚡', '["риск","инжиниринг","bcp","drp","стратегия","безопасность"]', 6), ('Общий вопрос', 'Консультация или вопрос вне указанных категорий', '💬', '["консультация","вопрос","общий","другое"]', 7); ``` ## Phase 4: Deploy scripts ### 4a. Fix max_bot_deploy.sh rsync **File:** `max_bot/max_bot_deploy.sh:32` — change `max_bot/` to `.` ### 4b. Add max_bot hook to main deploy.sh **File:** `py_service/deploy.sh` — after docker compose up -d: ```bash echo "Deploying max_bot..." bash max_bot/max_bot_deploy.sh ``` ## Phase 5: Changelog Create `CHANGELOG.md` with all fixes. ## Deploy Order 1. SQL migrations on DB 2. scp + docker exec tee for py_service files 3. docker compose restart aegisone-app 4. scp + docker compose build for max_bot 5. docker compose up -d aegisone-max-bot 6. Verify health checks