Initial commit: VoIdeaAI - voice-first AI idea assistant

This commit is contained in:
2026-05-13 12:51:42 +03:00
commit 688d043dad
421 changed files with 47915 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
# ADR-001: Выбор PostgreSQL как основной СУБД
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
Для проекта VoIdea требуется база данных с поддержкой:
- Сложных запросов (аналитика идей)
- JSONB для гибкости (метаданные, настройки)
- ACID транзакции (финансовые операции, подписки)
- Масштабируемость (тысячи пользователей)
- Хорошая работа с Python (asyncpg)
Рассматривались:
- **PostgreSQL** — реляционная, ACID, JSONB, mature
- **MongoDB** — документоориентированная, гибкость, шардинг
- **SQLite** — простая, не подходит для production
---
## Решение
**PostgreSQL** выбран как основная СУБД.
### Обоснование
| Критерий | PostgreSQL | MongoDB | SQLite |
|----------|------------|---------|--------|
| ACID | ✅ Полный | ❌ Eventual | ✅ Полный |
| JSONB | ✅ Отличный | ✅ Лучший | ❌ Limited |
| Масштабируемость | ✅ Хорошая | ✅ Отличная | ❌ Плохая |
| Python async | ✅ asyncpg | ✅ motor | ❌ |
| Сложные запросы | ✅ Отличные | ❌ Limited | ⚠️ Basic |
| Зрелость | ✅ 20+ лет | ⚠️ 15 лет | ✅ |
### Преимущества для VoIdea
1. **JSONB** — хранение зашифрованных данных, настроек агентов
2. **ACID** — безопасность транзакций (подписки, платежи)
3. **Индексы** — поиск по метаданным, пользователям
4. **PostGIS** — геолокация (future: автоопределение региона)
5. **Full-text search** — поиск в идеях
---
## Последствия
### Положительные
- Надёжная, проверенная база данных
- Отличная производительность
- Большое сообщество
- Хорошая документация
- Mature ORM (SQLAlchemy async)
### Отрицательные
- Требует установку и настройку (PostgreSQL server)
- Миграции Alembic для схемы
- Начальная настройка (создание пользователя, базы)
### Миграция
Для локальной разработки:
```bash
# Windows
# Скачать PostgreSQL с postgresql.org/download/windows
# или использовать Chocolatey:
choco install postgresql
# Ubuntu (VPS)
apt install postgresql postgresql-contrib
```
---
## Реализация
### Конфигурация в .env
```bash
DB_HOST=localhost
DB_PORT=5432
DB_NAME=voidea
DB_USER=voidea
DB_PASS=your_secure_password
```
### SQLAlchemy async setup
```python
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine(
f"postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}",
echo=True
)
```
---
## Ответственный
**Decision maker:** Owner
**Review date:** При масштабировании (> 10,000 пользователей)
---
*Создано: 2026-05-10*
*Обновлено при изменениях SpecAgent*
+397
View File
@@ -0,0 +1,397 @@
# ADR-002: Архитектура системных агентов
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
Проект VoIdea требует автоматизации через AI-агентов. Необходимо определить:
- Количество агентов
- Их обязанности
- Взаимодействие между агентами
- Стек реализации
Рассматривались:
- **Один суперагент** — всё в одном, сложно масштабировать
- **Ручное управление** — человек выполняет всё
- **11 отдельных агентов** — модульность, специализация
---
## Решение
**11 системных агентов**, каждый со своей ответственностью.
### Список агентов
| Агент | Ответственность | Триггеры |
|-------|-----------------|----------|
| DocAgent | Документация, комментарии | pre-commit, push, manual |
| AuditAgent | Соблюдение правил, прогресс | pre-commit, daily, manual |
| SecurityAgent | Безопасность, уязвимости | pre-commit, weekly, manual |
| SpecAgent | Спецификации, версионирование | tag creation, push |
| ObserverAgent | Наблюдение за пользователями | continuous, daily report |
| QATesterAgent | Функциональное тестирование | pre-commit, daily, manual |
| FixAgent | Исправление багов | QATesterAgent results |
| UITestAgent | Визуальное тестирование | weekly, manual |
| RolloutAgent | Постепенное развёртывание | after tests, manual |
| EvolutionAgent | Саморазвитие агентов | daily, learning |
| BacklogAgent | Управление задачами | continuous |
---
## Архитектура
### Структура файлов
```
app/agents/
├── __init__.py # Публичный API
├── base.py # Базовый класс Agent
├── doc_agent.py # DocAgent
├── audit_agent.py # AuditAgent
├── security_agent.py # SecurityAgent
├── spec_agent.py # SpecAgent
├── observer_agent.py # ObserverAgent
├── qa_tester_agent.py # QATesterAgent
├── fix_agent.py # FixAgent
├── ui_test_agent.py # UITestAgent
├── rollout_agent.py # RolloutAgent
├── evolution_agent.py # EvolutionAgent
└── backlog_agent.py # BacklogAgent
```
### Базовый класс
```python
from abc import ABC, abstractmethod
from typing import Any, Optional
class BaseAgent(ABC):
name: str
version: str
@abstractmethod
async def run(self, context: dict) -> AgentResult:
"""Основной метод выполнения"""
pass
@abstractmethod
async def health_check(self) -> bool:
"""Проверка работоспособности"""
pass
async def get_status(self) -> AgentStatus:
"""Текущий статус агента"""
pass
async def get_metrics(self) -> AgentMetrics:
"""Метрики работы агента"""
pass
```
---
## Меж-агентское взаимодействие
### Делегирование
```python
class AgentA:
async def process(self, task):
if task.requires_agent_b:
result = await delegate_to(
target=AgentB,
task=task,
timeout=30
)
# continue processing
```
### Event-driven
```python
class EventBus:
async def publish(self, event: AgentEvent):
await self._handlers[event.type].handle(event)
class AgentB:
@event_handler(AgentEventTypes.TASK_DELEGATED)
async def handle_delegated_task(self, event):
# process task
```
---
## Описание поведения каждого агента
### DocAgent
**Цель:** Поддержание документации в актуальном состоянии.
**Обязанности:**
- Создание README.md для новых модулей
- Обновление docs при изменении кода
- Генерация docstrings
- Ведение Runbook
**Триггеры:**
- Создание нового файла
- Изменение существующего > 50 строк
- Создание новой папки
- Push в main/develop
**Взаимодействие:**
- SpecAgent → обновление спецификаций
- AuditAgent → проверка актуальности docs
---
### AuditAgent
**Цель:** Контроль соблюдения правил проекта.
**Обязанности:**
- Проверка code style (ruff)
- Проверка типизации (mypy)
- Контроль прогресса по плану
- Фиксация отклонений
**Триггеры:**
- pre-commit hook
- Ежедневно 09:00
- По запросу администратора
**Взаимодействие:**
- SecurityAgent → проверка безопасности
- DocAgent → обновление отчётов
---
### SecurityAgent
**Цель:** Обеспечение безопасности проекта.
**Обязанности:**
- Сканирование уязвимостей
- Проверка input валидации
- Контроль зависимостей (safety)
- Соответствие 152-ФЗ
**Триггеры:**
- pre-commit hook
- Еженедельно (полное сканирование)
- При добавлении зависимости
**Взаимодействие:**
- FixAgent → исправление уязвимостей
- RolloutAgent → блокировка при критических уязвимостях
---
### SpecAgent
**Цель:** Управление спецификациями и версионированием.
**Обязанности:**
- Генерация CHANGELOG
- Обновление project.json
- Управление ADR
- Версионирование кода
**Триггеры:**
- Создание git tag
- Push в main
- Изменение спецификаций
**Взаимодействие:**
- DocAgent → обновление docs
- EvolutionAgent → фиксация изменений
---
### ObserverAgent
**Цель:** Сбор и анализ данных о пользователях.
**Обязанности:**
- Сбор метрик использования
- Генерация идей для развития
- Выявление паттернов поведения
- Отчёты для EvolutionAgent
**Триггеры:**
- Непрерывный сбор данных
- Ежедневный отчёт
- По запросу EvolutionAgent
**Метрики (MVP):**
- page_views
- session_duration
- feature_usage_frequency
- conversion_rate
**Взаимодействие:**
- EvolutionAgent → данные для анализа
- RolloutAgent → метрики для решения
---
### QATesterAgent
**Цель:** Функциональное тестирование.
**Обязанности:**
- Создание временных аккаунтов
- Выполнение тестов
- Очистка временных данных
- Генерация отчётов
**Триггеры:**
- pre-commit hook
- Ежедневно в 06:00
- Вручную через админ-панель
- После FixAgent исправления
**Взаимодействие:**
- FixAgent → исправление найденных багов
- UITestAgent → визуальное тестирование
- RolloutAgent → результаты для решения
---
### FixAgent
**Цель:** Автоматическое исправление багов.
**Обязанности:**
- Анализ багов из QATesterAgent
- Генерация исправлений
- Создание PR
- Валидация исправлений
**Триггеры:**
- Результаты QATesterAgent
- Критические ошибки в логах
- По запросу человека
**Взаимодействие:**
- QATesterAgent → повторное тестирование
- DocAgent → обновление документации
- Git → создание PR
---
### UITestAgent
**Цель:** Визуальное тестирование интерфейса.
**Обязанности:**
- Скриншот-тестирование
- Проверка layout
- Accessibility testing
- Кросс-браузерное тестирование
**Триггеры:**
- Еженедельно
- После изменений в UI
- Вручную через админ-панель
**Взаимодействие:**
- QATesterAgent → результаты
- FixAgent → исправление визуальных багов
---
### RolloutAgent
**Цель:** Управление развёртыванием.
**Обязанности:**
- Контроль этапов rollout (3→1%→5%→15%→100%)
- Мониторинг метрик
- Принятие решения о переходе
- Откат при проблемах
**Триггеры:**
- После успешных тестов
- Ежедневный мониторинг
- По решению человека
**Взаимодействие:**
- ObserverAgent → метрики
- FixAgent → исправление проблем
- BacklogAgent → создание задач
---
### EvolutionAgent
**Цель:** Саморазвитие агентов.
**Обязанности:**
- Анализ эффективности агентов
- Генерация предложений по улучшению
- Обновление capabilities
- Обучение на данных
**Триггеры:**
- Ежедневно
- При обнаружении новых паттернов
- По запросу BacklogAgent
**Взаимодействие:**
- ObserverAgent → данные о пользователях
- Все агенты → улучшение работы
---
### BacklogAgent
**Цель:** Управление отложенными задачами.
**Обязанности:**
- Создание задач из предложений
- Приоритизация
- Отслеживание статуса
- Напоминания
**Триггеры:**
- Непрерывный мониторинг
- По предложению других агентов
- Вручную через админ-панель
**Взаимодействие:**
- Все агенты → создание задач
- RolloutAgent → задачи для реализации
---
## Последствия
### Положительные
- Модульность — легко добавлять новых агентов
- Специализация — каждый делает своё
- Тестируемость — можно тестировать отдельно
- Масштабируемость — агенты работают параллельно
### Отрицательные
- Сложность координации
- Возможные конфликты агентов
- Overhead на коммуникацию
---
## Ответственный
**Decision maker:** Owner
**Review date:** При добавлении новых агентов
---
*Создано: 2026-05-10*
*Обновлено при изменениях EvolutionAgent*
+243
View File
@@ -0,0 +1,243 @@
# ADR-003: OAuth схема авторизации
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
Проект VoIdea поддерживает несколько способов авторизации:
- Email + пароль
- OAuth провайдеры (Яндекс, Google, Apple)
Необходимо определить правила привязки провайдеров к аккаунтам.
---
## Решение
**Один пользователь = один провайдер**
> Нельзя привязать Google к аккаунту, зарегистрированному через Яндекс.
---
## Правила
### Основные
1. **При регистрации через OAuth** — аккаунт привязан к этому провайдеру навсегда
2. **При регистрации через email** — можно использовать только email + пароль
3. **Нельзя добавить второй провайдер** — даже если email совпадает
### Примеры
| Действие | Результат |
|----------|-----------|
| Регистрация через Яндекс → Вход через Google | ❌ Ошибка: создай новый аккаунт |
| Регистрация через Google → Вход через Яндекс | ❌ Ошибка: создай новый аккаунт |
| Регистрация через email → Вход через Яндекс | ❌ Ошибка: это разные аккаунты |
| Регистрация через Яндекс → Повторный вход через Яндекс | ✅ Работает |
---
## Обоснование
### Почему один провайдер
1. **Безопасность**
- Меньше точек входа для атак
- Сложнее украсть аккаунт
- Чёткая атрибуция действий
2. **Простота реализации**
- Не нужно merge аккаунтов
- Не нужно решать конфликты данных
- Понятная модель данных
3. **Privacy**
- Данные не смешиваются между провайдерами
- Пользователь понимает что использует
4. **Яндекс vs Google**
- Разные экосистемы
- Разные данные пользователя
- Разная политика безопасности
---
## Структура данных
### Users table
```sql
CREATE TABLE users (
id UUID PRIMARY KEY,
-- Идентификация
email VARCHAR(255) UNIQUE, -- NULL если OAuth без email
password_hash VARCHAR(255), -- NULL если OAuth-only
-- OAuth (только один провайдер)
oauth_provider VARCHAR(20), -- yandex|google|apple|null
oauth_id VARCHAR(255), -- ID в системе провайдера
-- Метаданные
email_verified BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
-- Constraints
CONSTRAINT users_oauth_xor_email CHECK (
-- OAuth с email
(oauth_provider IS NOT NULL AND email IS NOT NULL) OR
-- Email-only
(oauth_provider IS NULL AND email IS NOT NULL AND password_hash IS NOT NULL)
)
);
CREATE UNIQUE INDEX uq_users_oauth
ON users(oauth_provider, oauth_id)
WHERE oauth_provider IS NOT NULL;
```
---
## OAuth Flow
### Пример: Яндекс OAuth
```python
async def yandex_oauth_callback(code: str, db: AsyncSession):
# 1. Получаем access_token
token_data = await yandex_api.get_token(code)
# 2. Получаем данные пользователя
user_data = await yandex_api.get_user_info(token_data.access_token)
# 3. Проверяем/создаём аккаунт
user = await db.execute(
select(User).where(
User.oauth_provider == 'yandex',
User.oauth_id == user_data.id
)
)
if not user:
# Новый пользователь
user = User(
email=user_data.email,
oauth_provider='yandex',
oauth_id=user_data.id
)
db.add(user)
await db.commit()
# 4. Создаём JWT session
return create_jwt_session(user.id)
```
---
## Google OAuth
Аналогично Яндексу, с заменой endpoint-ов.
### Различия
| Параметр | Яндекс | Google |
|----------|--------|--------|
| OAuth endpoint | oauth.yandex.ru | oauth2.googleapis.com |
| User info | login.yandex.ru | www.googleapis.com/oauth2/v2/userinfo |
| Scope | login:email, profile | email, profile |
---
## Apple OAuth (отложено)
Apple будет реализован ближе к коммерческой версии.
### Требования
- App Store Developer Account ($99/год)
- Private Key для подписи (в Keychain)
- Тот же принцип: один пользователь = один провайдер
---
## Защита от привязки чужого аккаунта
### Проблема
Злоумышленник может попытаться привязать Google к чужому email.
### Решение
1. **Email verification**
- OAuth возвращает verified email
- Привязка только verified email
2. **Separate tables**
- OAuth и email разделены логически
- Разные flows для входа
3. **Audit logging**
- Все попытки OAuth логируются
- Подозрительная активность → SecurityAgent
---
## Последствия
### Положительные
- Простая модель данных
- Безопасность выше
- Понятно для пользователя
- Легко реализовать
### Отрицательные
- Пользователь не может "добавить" Google к существующему аккаунту
- При потере доступа к провайдеру — сложнее восстановить
- Нельзя merge аккаунты
### Workaround для пользователя
При потере доступа к OAuth провайдеру:
1. Обращение в поддержку
2. Подтверждение личности
3. Смена email (если нужно)
4. Сброс пароля на email
---
## Конфигурация
```bash
# .env
OAUTH_YANDEX_ID=your_yandex_client_id
OAUTH_YANDEX_SECRET=your_yandex_secret
OAUTH_YANDEX_REDIRECT_URI=http://localhost:8020/auth/yandex/callback
OAUTH_GOOGLE_ID=your_google_client_id
OAUTH_GOOGLE_SECRET=your_google_secret
OAUTH_GOOGLE_REDIRECT_URI=http://localhost:8020/auth/google/callback
# Apple - зарезервировано для будущего
# OAUTH_APPLE_ID=
# OAUTH_APPLE_TEAM_ID=
```
---
## Ответственный
**Decision maker:** Owner
**Review date:** При добавлении Apple OAuth
---
*Создано: 2026-05-10*
*См. также: docs/backlog/oauth-schema-note.md*
+294
View File
@@ -0,0 +1,294 @@
# ADR-004: Постепенное развёртывание (Rollout)
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
При выпуске нового функционала требуется минимизировать риски и быстро реагировать на проблемы.
Рассматривались:
- **Big bang** — сразу на всех пользователей
- **Feature flags** — включение для избранных
- **Постепенное развёртывание** — процент от пользователей
---
## Решение
**Поэтапное развёртывание с мониторингом**
```
Stage 0: Development → Тестирование агентами
Stage 1: 3 users → Первые пользователи
Stage 2: 1% → Расширение выборки
Stage 3: 5% → Продолжение
Stage 4: 15% → Почти все
Stage 5: 100% → Production
```
---
## Этапы
### Stage 0: Development
**Кто:** Агенты (QATesterAgent, FixAgent, UITestAgent)
**Критерии перехода:**
- Все тесты пройдены
- Нет критических ошибок
- Документация обновлена
**Действия:**
```python
async def promote_to_stage_1():
# 1. Финальная проверка тестов
test_results = await QATesterAgent.run_full_suite()
# 2. Проверка документации
await AuditAgent.verify_docs_complete()
# 3. Решение о переходе
if test_results.success:
RolloutAgent.set_stage(1)
notify_admins("Готов к rollout: 3 пользователя")
```
---
### Stage 1: 3 users
**Кто:** 3 добровольца (beta testers)
**Критерии перехода в Stage 2:**
- 2 дня без критических ошибок
- Error rate < 1%
- User feedback положительный
- ObserverAgent не фиксирует аномалий
**Действия:**
```python
async def check_stage_1_health():
metrics = await ObserverAgent.get_metrics(days=2)
# Проверки
if metrics.error_rate < 0.01:
if metrics.user_satisfaction > 0.8:
if not metrics.anomalies_detected:
await promote_to_stage_2()
else:
await analyze_anomalies()
else:
await log_issue("Low satisfaction")
```
---
### Stage 2: 1% пользователей
**Кто:** ~10 пользователей (при 1000 MAU)
**Критерии перехода в Stage 3:**
- 2 дня стабильности
- Нет regresion
- Performance acceptable (< 500ms)
---
### Stage 3: 5% пользователей
**Кто:** ~50 пользователей
**При проблемах:** Откат до Stage 2
---
### Stage 4: 15% пользователей
**Кто:** ~150 пользователей
**При проблемах:** Откат до Stage 3
---
### Stage 5: 100% (Production)
**Кто:** Все пользователи
**Критерии:**
- Все предыдущие stages стабильны
- Мониторинг непрерывный
- Подготовлен changelog для магазинов
---
## Мониторинг
### ObserverAgent отслеживает
```python
class RolloutMetrics:
error_rate: float # Цель: < 1%
response_time_p95: float # Цель: < 500ms
user_satisfaction: float # Цель: > 0.8
feature_usage: float # Цель: рост
complaints_count: int # Цель: 0
rollback_requests: int # Цель: 0
```
### При аномалиях
1. **Alert** → RolloutAgent получает уведомление
2. **Analysis** → FixAgent анализирует логи
3. **Decision** → Человек + агент решают
4. **Action** → Откат или продолжение
---
## Откат (Rollback)
### Когда
- Error rate > 5%
- Критические баги в production
- Решение человека
### Процедура
```python
async def rollback_to(stage: int):
# 1. Приостановить rollout
RolloutAgent.pause()
# 2. Зафиксировать состояние
await AuditAgent.log_rollback(stage)
# 3. Откатить код
await git.revert_to_stable_version()
# 4. Уведомить
notify_admins(f"Откат до Stage {stage}")
# 5. Создать задачу
await BacklogAgent.create_task(
title=f"Rollback reason: ...",
priority="high"
)
# 6. После исправления → вернуться к Stage 0
```
---
## UI в админ-панели
### Dashboard
```
Rollout Status: Stage 2 (1%)
Progress:
[████████░░░░░░░░░░░░░░░░░░░] 1%
Metrics:
- Error rate: 0.5% ✓
- Response time: 234ms ✓
- Users: 10/1000
Actions:
[Приостановить] [Откат] [Форсировать]
```
### История
```
Stage 0 → Stage 1: 2026-05-10 (PASSED)
Stage 1 → Stage 2: 2026-05-12 (PASSED)
Stage 2 → Stage 3: 2026-05-14 (IN PROGRESS)
```
---
## Feature Flags
Для гибкости используем Feature Flags:
```sql
CREATE TABLE feature_flags (
id UUID PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
enabled BOOLEAN DEFAULT FALSE,
rollout_percentage INT DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
```
```python
async def is_feature_enabled(user_id: UUID, feature: str) -> bool:
flag = await db.get_feature_flag(feature)
if not flag.enabled:
return False
# Проверка процента
user_hash = hash(user_id)
return (user_hash % 100) < flag.rollout_percentage
```
---
## Последствия
### Положительные
- Минимизация рисков
- Быстрая реакция на проблемы
- Эволюция с обратной связью
- Прозрачность для команды
### Отрицательные
- Медленнее релиз
- Сложнее управление
- Требуется мониторинг
---
## Конфигурация
```yaml
rollout:
stages:
- name: development
users: 0
duration: unlimited
- name: "3 users"
users: 3
duration: 2 days
- name: "1%"
users_percentage: 1
duration: 2 days
- name: "5%"
users_percentage: 5
duration: 2 days
- name: "15%"
users_percentage: 15
duration: 3 days
- name: "100%"
users_percentage: 100
duration: unlimited
```
---
## Ответственный
**Decision maker:** Owner + RolloutAgent
**Review date:** После каждого успешного rollout
---
*Создано: 2026-05-10*
*Управляется RolloutAgent*
+330
View File
@@ -0,0 +1,330 @@
# ADR-005: Design Tokens как единый источник стилей
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
Проект VoIdea работает на нескольких платформах:
- Web (PWA)
- iOS (Swift/SwiftUI)
- Android (Kotlin)
Требуется унифицировать стили (цвета, шрифты, отступы) между всеми платформами.
Рассматривались:
- **Ручное копирование** — непоследовательно, сложно поддерживать
- **Shared library** — требует синхронизации
- **Design Tokens (JSON)** — единый источник, генераторы
---
## Решение
**Design Tokens в JSON + генераторы для каждой платформы**
```
docs/design-system/tokens.json (источник истины)
├── generators/css_generator.py → app/design-tokens/css/theme.css
├── generators/swift_generator.py → app/design-tokens/swift/Colors.swift
└── generators/kotlin_generator.py → app/design-tokens/kotlin/colors.xml
```
---
## Структура tokens.json
```json
{
"version": "1.0.0",
"project": "VoIdea",
"themes": ["system", "dark", "light"],
"colors": {
"primary": {
"500": "#6366F1",
"600": "#4F46E5",
"default": "#6366F1",
"hover": "#4F46E5"
},
"background": {
"system": "auto",
"dark": "#0F172A",
"light": "#FFFFFF"
},
"semantic": {
"error": "#EF4444",
"warning": "#F59E0B",
"success": "#22C55E",
"info": "#3B82F6"
}
},
"typography": {
"font_family": {
"primary": "Inter, system-ui, sans-serif"
},
"size": {
"xs": "0.75rem",
"sm": "0.875rem",
"base": "1rem"
}
},
"spacing": {
"xs": "0.25rem",
"sm": "0.5rem",
"md": "1rem",
"lg": "1.5rem"
},
"border_radius": {
"sm": "0.25rem",
"md": "0.5rem",
"lg": "0.75rem"
}
}
```
---
## Генераторы
### CSS Generator
```python
# docs/design-system/generators/css_generator.py
def generate(tokens: dict) -> str:
css = ":root {\n"
for category, values in tokens.items():
if category == "colors":
for name, value in flatten(values):
css += f" --color-{name}: {value};\n"
elif category == "typography":
for name, value in flatten(values):
css += f" --font-{name}: {value};\n"
elif category == "spacing":
for name, value in flatten(values):
css += f" --spacing-{name}: {value};\n"
css += "}\n"
return css
```
**Выход:** `app/design-tokens/css/theme.css`
```css
:root {
--color-primary: #6366F1;
--color-background-dark: #0F172A;
--font-family-primary: Inter, system-ui, sans-serif;
--spacing-md: 1rem;
}
```
---
### Swift Generator
```python
# docs/design-system/generators/swift_generator.py
def generate(tokens: dict) -> str:
swift = "import SwiftUI\n\n"
swift += "enum Colors {\n"
for name, value in flatten(tokens["colors"]):
snake_to_camel = to_camel_case(name)
swift += f' static let {snake_to_camel} = Color(hex: "{value}")\n'
swift += "}\n"
swift += "enum Typography {\n"
# ... font generation
return swift
```
**Выход:** `app/design-tokens/swift/Colors.swift`
```swift
import SwiftUI
enum Colors {
static let primary = Color(hex: "#6366F1")
static let backgroundDark = Color(hex: "#0F172A")
}
enum Typography {
static let fontFamilyPrimary = "Inter"
static let fontSizeBase: CGFloat = 16
}
```
---
### Kotlin Generator
```python
# docs/design-system/generators/kotlin_generator.py
def generate(tokens: dict) -> str:
xml = '<?xml version="1.0" encoding="utf-8"?>\n'
xml += '<resources>\n'
for name, value in flatten(tokens["colors"]):
safe_name = name.replace("_", "_")
xml += f' <color name="{safe_name}">{value}</color>\n'
xml += '</resources>\n'
return xml
```
**Выход:** `app/design-tokens/kotlin/colors.xml`
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primary">#6366F1</color>
<color name="background_dark">#0F172A</color>
</resources>
```
---
## Темы
### System (Auto)
```css
@media (prefers-color-scheme: dark) {
:root[data-theme="system"] {
--color-background: #0F172A;
--color-text: #F8FAFC;
}
}
@media (prefers-color-scheme: light) {
:root[data-theme="system"] {
--color-background: #FFFFFF;
--color-text: #0F172A;
}
}
```
### Dark / Light
```css
[data-theme="dark"] {
--color-background: #0F172A;
--color-text: #F8FAFC;
}
[data-theme="light"] {
--color-background: #FFFFFF;
--color-text: #0F172A;
}
```
---
## CI/CD Integration
```yaml
# .github/workflows/design-system.yml
on:
push:
paths:
- 'docs/design-system/tokens.json'
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate CSS
run: python -m generators css
- name: Generate Swift
run: python -m generators swift
- name: Generate Kotlin
run: python -m generators kotlin
- name: Commit
run: |
git add app/design-tokens/
git commit -m "style: regenerate design tokens"
git push
```
---
## Правила использования
1. **Никогда не редактировать сгенерированные файлы вручную**
2. **Все изменения только в tokens.json**
3. **После изменения tokens.json → запустить генераторы**
4. **DocAgent обновляет документацию**
---
## Maintenance
### Обновление tokens.json
1. Открыть `docs/design-system/tokens.json`
2. Внести изменения
3. Запустить `python -m generators all`
4. Проверить сгенерированные файлы
5. Зафиксировать в git
### Добавление новых token
```json
{
"new_token": {
"system": "auto",
"dark": "#value",
"light": "#value"
}
}
```
---
## Последствия
### Положительные
- Единый источник истины
- Согласованность между платформами
- Легко добавлять темы
- Автоматическая генерация
### Отрицательные
- Дополнительный слой абстракции
- Требует генерацию при изменениях
- Разные форматы вывода
---
## Ответственный
**Decision maker:** Frontend team
**Review date:** При добавлении новой платформы
---
*Создано: 2026-05-10*
*Обновляется DocAgent при изменениях*
+156
View File
@@ -0,0 +1,156 @@
# ADR-006: Версионирование агентов
**Статус:** принято
**Дата:** 2026-05-10
---
## Контекст
11 системных агентов VoIdea самообучаются — их код, промпты и capabilities изменяются
автоматически через EvolutionAgent или вручную. Без контроля версий невозможно:
- Отследить, когда и какой агент изменился
- Понять, какие изменения были внесены
- Откатить агента до предыдущей версии при проблемах
- Синхронизировать версии агентов между окружениями (local → VPS)
Рассматривались:
- **Единая версия для всех** — не отражает индивидуальных изменений
- **Только git** — не покрывает runtime-эволюцию (изменение промптов без коммита)
- **A.B.C для каждого агента** — точный контроль, авто-детект изменений
---
## Решение
**A.B.C (SemVer) для каждого агента**, changelog в `CHANGELOG/agents/<name>.md`.
### Правила бампа
| Компонент | Когда меняется | Кто меняет |
|-----------|---------------|------------|
| **A (major)** | Breaking change: сигнатура `run()` или публичные методы | EvolutionAgent (анализ кода) |
| **B (minor)** | Новая capability: новый метод, новый prompt, новая роль | EvolutionAgent (добавление capability) |
| **C (patch)** | Внутренние правки: багфикс, оптимизация, уточнение промпта | Сам агент (авто-сравнение checksum) |
### Механика
```
Каждый Agent.run()
→ compute_checksum() — SHA256 от __file__ агента
→ сравнивает с AgentConfig.checksum в БД
→ не совпал → bump_version("patch") → запись в changelog → обновление БД
→ совпал → ничего
EvolutionAgent
→ добавляет capability → bump_version("minor") → запись в changelog
→ обнаружил breaking change → bump_version("major") → запись в changelog
```
### Хранение
```
CHANGELOG/agents/
├── doc_agent.md
├── audit_agent.md
├── security_agent.md
├── spec_agent.md
├── observer_agent.md
├── qa_tester_agent.md
├── fix_agent.md
├── ui_test_agent.md
├── rollout_agent.md
├── evolution_agent.md
└── backlog_agent.md
```
Формат changelog агента:
```markdown
# audit_agent Changelog
## 1.0.2 (2026-05-10)
- Fixed: ruff output parsing for Windows paths
## 1.0.1 (2026-05-09)
- Fixed: missing error handling in health_check
## 1.0.0 (2026-05-08)
- Initial version
```
### Разделение ответственности
| Аспект | Владелец | Где хранится |
|--------|----------|--------------|
| Версия проекта | SpecAgent | `project.json`, `CHANGELOG/v*.md` |
| Версия агента | EvolutionAgent | `AgentConfig.version` (БД) |
| Changelog проекта | SpecAgent | `CHANGELOG/v*.md` |
| Changelog агента | EvolutionAgent | `CHANGELOG/agents/<name>.md` |
---
## Архитектура
### Изменения в моделях БД
```python
class AgentConfig(SQLBase, UUIDMixin, TimestampMixin):
__tablename__ = "agent_configs"
agent_name: str # unique
is_enabled: bool
version: str # "1.0.0" — новое поле
checksum: str # SHA256 — новое поле
config: str | None # JSON
last_run_at: datetime # DateTime вместо String
```
### Изменения в BaseAgent
```python
class BaseAgent(ABC):
name: str
version: str = "1.0.0"
CHANGELOG_DIR = "CHANGELOG/agents/"
def compute_checksum(self) -> str:
"""SHA256 от __file__ агента"""
...
def bump_version(self, version_type: str = "patch") -> str:
"""Увеличить A/B/C, обновить self.version"""
...
def write_changelog(self, version: str, entries: list[str]) -> None:
"""Дописать запись в CHANGELOG/agents/<name>.md"""
...
```
---
## Последствия
### Положительные
- Полная traceability изменений каждого агента
- Автоматическое версионирование без участия человека
- Совместимо с git (checksum детектит и runtime-изменения)
- Единый формат changelog для всех агентов
### Отрицательные
- Дополнительная нагрузка на БД (чтение/запись checksum при каждом run)
- SHA256 файла не детектит изменения в импортируемых зависимостях
- Patch-версия может расти быстро при частых правках
---
## Ответственный
**Decision maker:** Owner
**Review date:** При изменении архитектуры агентов
---
*Создано: 2026-05-10*