317 lines
13 KiB
Markdown
317 lines
13 KiB
Markdown
# Полная спецификация проекта для ИИ-ассистента
|
||
|
||
Этот файл — единственный источник истины для ИИ, работающего с проектом.
|
||
Прочитай его полностью перед началом любой работы. Если какой-то аспект не описан — спроси.
|
||
|
||
---
|
||
|
||
## 1. РОЛИ
|
||
|
||
- **Ты — ИИ-ассистент.** Твоя задача: писать код, соответствующий правилам проекта.
|
||
- **Пользователь — владелец проекта.** Он принимает все стратегические решения.
|
||
- **Агенты — автоматические участники.** Они следят за качеством, версиями и эволюцией.
|
||
|
||
---
|
||
|
||
## 2. СТРУКТУРА ПРОЕКТА (MUST FOLLOW)
|
||
|
||
```
|
||
project/
|
||
├── app/ # Backend (Python FastAPI)
|
||
│ ├── __init__.py
|
||
│ ├── main.py # FastAPI app, lifespan, middleware
|
||
│ ├── api/
|
||
│ │ └── v1/ # Версионированные роуты
|
||
│ │ ├── __init__.py # api_v1_router = APIRouter(prefix="/api/v1")
|
||
│ │ ├── auth.py # POST /login, /register, /refresh, /oauth
|
||
│ │ ├── users.py # GET/PATCH /me
|
||
│ │ ├── ideas.py # CRUD /ideas + POST /analyze
|
||
│ │ ├── agents.py # GET /agents + POST /run
|
||
│ │ ├── sync.py # POST /sync/pull, /sync/push
|
||
│ │ └── admin.py # GET /users, /health, /logs
|
||
│ ├── core/
|
||
│ │ ├── __init__.py
|
||
│ │ ├── config.py # Pydantic Settings из .env
|
||
│ │ ├── base.py # SQLBase, CoreModel, UUIDMixin, TimestampMixin
|
||
│ │ ├── database.py # Engine + async_session_maker + get_db
|
||
│ │ ├── security.py # JWT create/decode, password hash
|
||
│ │ ├── exceptions.py # HTTPException подклассы
|
||
│ │ ├── dependencies.py # get_db, get_current_user, require_admin
|
||
│ │ └── metrics.py # Middleware для сбора метрик
|
||
│ ├── models/ # SQLAlchemy модели
|
||
│ ├── schemas/ # Pydantic схемы (Request/Response)
|
||
│ ├── services/ # Бизнес-логика
|
||
│ ├── integrations/ # AI провайдеры, внешние API
|
||
│ ├── tasks/ # Celery задачи (или прямой вызов)
|
||
│ └── agents/ # Системные агенты
|
||
├── webui/ # Frontend (React + Vite + Tailwind)
|
||
│ ├── src/
|
||
│ │ ├── main.tsx
|
||
│ │ ├── App.tsx # BrowserRouter + Routes
|
||
│ │ ├── index.css # Tailwind directives
|
||
│ │ ├── api/ # HTTP-клиент, типы запросов
|
||
│ │ ├── auth/ # AuthContext, login/register
|
||
│ │ ├── components/ # Layout, ProtectedRoute
|
||
│ │ └── pages/ # Dashboard, IdeaView, Admin
|
||
│ └── vite.config.ts # Vite + React + PWA proxy
|
||
├── tests/ # pytest тесты
|
||
├── docs/ # Документация
|
||
├── CHANGELOG/ # Версионирование
|
||
├── migrations/ # Alembic миграции
|
||
├── .env.example
|
||
└── project.yaml
|
||
```
|
||
|
||
## 3. ПРАВИЛА КОДИРОВАНИЯ (MUST FOLLOW)
|
||
|
||
### 3.1 Python
|
||
|
||
- **Версия:** Python 3.12+
|
||
- **Типизация:** `from __future__ import annotations` во всех файлах, `X | None` вместо `Optional[X]`
|
||
- **Строки:** двойные кавычки `"` для строковых литералов, одинарные `'` для docstrings
|
||
- **Длина строки:** 88 символов (ruff format)
|
||
- **Импорты:** абсолютные, порядок: stdlib → third-party → local (алфавитный внутри групп)
|
||
- **Docstrings:** Google-style для всех публичных классов/функций/методов
|
||
- **Именование:** классы PascalCase, функции/переменные snake_case, константы UPPER_SNAKE
|
||
- **Линтер:** ruff (E, F, W, I, N, UP)
|
||
- **Форматтер:** ruff format
|
||
|
||
### 3.2 SQL
|
||
|
||
- **Ключевые слова:** UPPERCASE (SELECT, FROM, WHERE)
|
||
- **Таблицы/поля:** snake_case
|
||
- **Индексы:** `ix_tablename_column`
|
||
- **Уникальность:** `uq_tablename_column`
|
||
|
||
### 3.3 TypeScript/React
|
||
|
||
- **Форматтер:** Prettier (100 символов)
|
||
- **Типы:** strict TypeScript, `any` запрещён
|
||
- **Импорты:** абсолютные через `@/` alias
|
||
- **Стили:** Tailwind CSS, никаких CSS-in-JS
|
||
- **Асинхронность:** async/await, `.then()` запрещён
|
||
- **Состояние:** zustand или React Context
|
||
|
||
## 4. АРХИТЕКТУРА (MUST FOLLOW)
|
||
|
||
### 4.1 Слои (зависимости только внутрь)
|
||
|
||
```
|
||
API → Services → Integrations → Data → Core
|
||
```
|
||
|
||
- **API** не знает про БД. Не создаёт сессий. Только Depends(get_db).
|
||
- **Services** не знают про HTTP. Не импортируют FastAPI/fastapi. Работают с БД через сессию.
|
||
- **Integrations** не знают про бизнес-логику. Оборачивают внешние API.
|
||
- **Data** (models) — SQLAlchemy модели и репозитории.
|
||
- **Core** — конфиг, базовые классы, утилиты, безопасность.
|
||
|
||
### 4.2 Сервисы
|
||
|
||
Сервис — это класс, который принимает `db: AsyncSession` в конструкторе:
|
||
|
||
```python
|
||
class IdeaService:
|
||
def __init__(self, db: AsyncSession):
|
||
self.db = db
|
||
|
||
async def get_by_id(self, idea_id: str) -> Idea | None:
|
||
result = await self.db.execute(select(Idea).where(Idea.id == idea_id))
|
||
return result.scalar_one_or_none()
|
||
```
|
||
|
||
### 4.3 API
|
||
|
||
API-роуты — это функции, которые:
|
||
1. Принимают `Depends(get_db)` и `Depends(get_current_user)`
|
||
2. Создают сервис с сессией
|
||
3. Вызывают метод сервиса
|
||
4. Возвращают Pydantic response
|
||
|
||
```python
|
||
@router.get("/{idea_id}", response_model=IdeaResponse)
|
||
async def get_idea(
|
||
idea_id: str,
|
||
user: Annotated[User, Depends(get_current_user)],
|
||
db: AsyncSession = Depends(get_db),
|
||
):
|
||
service = IdeaService(db)
|
||
idea = await service.get_by_id(idea_id)
|
||
if not idea or str(idea.user_id) != str(user.id):
|
||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||
return _to_response(idea)
|
||
```
|
||
|
||
### 4.4 Зависимости (dependencies.py)
|
||
|
||
- `get_db()` — yield async_session_maker(), commit/rollback/close
|
||
- `get_current_user(credentials, db)` — decode JWT → find user in DB
|
||
- `require_admin(user)` — check is_superuser
|
||
|
||
ВАЖНО: `get_current_user` принимает `db = Depends(get_db)`, а не создаёт свою сессию.
|
||
|
||
### 4.5 Config
|
||
|
||
```python
|
||
class Settings(BaseSettings):
|
||
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
|
||
|
||
server_host: str = "0.0.0.0"
|
||
server_port: int = 8020
|
||
database_url: str = "sqlite+aiosqlite:///./app.db"
|
||
jwt_secret_key: str = ""
|
||
log_level: str = "INFO"
|
||
|
||
@property
|
||
def is_sqlite(self) -> bool:
|
||
return "sqlite" in self.database_url
|
||
```
|
||
|
||
## 5. БАЗА ДАННЫХ
|
||
|
||
### 5.1 Поддержка SQLite и PostgreSQL
|
||
|
||
Для портабельности между SQLite (dev) и PostgreSQL (prod) используем:
|
||
|
||
- **UUID поля:** `String(36)` во всех моделях (храним UUID как строку)
|
||
- **JSON/Array:** `JSON` вместо `JSONB` и `ARRAY`
|
||
- **Автовыбор:** через `settings.database_url` и `settings.is_sqlite`
|
||
|
||
### 5.2 Модели
|
||
|
||
```python
|
||
class UUIDMixin:
|
||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||
|
||
class TimestampMixin:
|
||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||
```
|
||
|
||
## 6. AI-ИНТЕГРАЦИЯ
|
||
|
||
### 6.1 Паттерн FallbackChain
|
||
|
||
```python
|
||
class AIProvider(ABC):
|
||
async def analyze(self, prompt: str, **kwargs) -> AIResult: ...
|
||
|
||
class FallbackChain:
|
||
def __init__(self, providers: list[AIProvider], max_retries: int = 2):
|
||
...
|
||
async def analyze(self, prompt: str, **kwargs) -> AIResult:
|
||
# Try each provider in order, max_retries per provider
|
||
# 1st retry after 2s, 2nd after 5s
|
||
# All fail → AIResult(success=False, error="All providers failed")
|
||
```
|
||
|
||
### 6.2 Где хранить промпты
|
||
|
||
- **YAML-файл** (`docs/agent_prompts.yaml`) для настроек (system_prompt, temperature, max_tokens, provider)
|
||
- **MD-файлы** (`docs/specs/agents/`) для детальных спецификаций
|
||
- Загрузка через `PromptLoader` (пытается YAML → falls back к MD)
|
||
|
||
## 7. АГЕНТЫ (IF APPLICABLE)
|
||
|
||
### 7.1 Ядро (4 агента, с первого коммита)
|
||
|
||
1. **DocAgent** — пишет документацию
|
||
2. **AuditAgent** — проверяет правила
|
||
3. **EvolutionAgent** — версионирует агентов
|
||
4. **SupervisorAgent** — следит за всеми агентами
|
||
|
||
### 7.2 Архитектура агента
|
||
|
||
```python
|
||
class BaseAgent(ABC):
|
||
name: str
|
||
version: str = "1.0.0"
|
||
description: str = ""
|
||
triggers: list[AgentTrigger]
|
||
|
||
async def run(self, context: dict | None = None) -> AgentResult: ...
|
||
async def health_check(self) -> bool: ...
|
||
def compute_checksum(self) -> str: ... # SHA256 от __file__
|
||
def bump_version(self, version_type: str = "patch") -> str: ...
|
||
```
|
||
|
||
### 7.3 Agent Versioning
|
||
|
||
- Каждый агент: независимое A.B.C
|
||
- SHA256 checksum файла агента сравнивается с хранимым
|
||
- Не совпал → авто-бамп patch + запись в `CHANGELOG/agents/<name>.md`
|
||
- EvolutionAgent бампает minor (новая capability) и major (breaking change)
|
||
- Формат changelog:
|
||
|
||
```markdown
|
||
# agent_name Changelog
|
||
<!-- checksum: sha256hash -->
|
||
|
||
## 1.0.1 (2026-05-10)
|
||
- Fixed: описание
|
||
|
||
## 1.0.0 (2026-05-09)
|
||
- Initial version
|
||
```
|
||
|
||
## 8. ФОНОВЫЕ ЗАДАЧИ
|
||
|
||
### 8.1 Celery (production) / Прямой вызов (dev)
|
||
|
||
```python
|
||
# tasks/analysis.py
|
||
@celery_app.task(bind=True, max_retries=2, name="analyze_idea")
|
||
def analyze_idea(self, idea_id: str, role: str) -> dict:
|
||
return asyncio.run(_analyze_idea_async(idea_id, role))
|
||
|
||
# services/analysis_service.py
|
||
class AnalysisService:
|
||
async def start_analysis(self, idea_id: str) -> dict:
|
||
if settings.celery_broker_url:
|
||
task = analyze_idea.delay(idea_id, role)
|
||
else:
|
||
task = await _analyze_local(idea_id, role)
|
||
...
|
||
```
|
||
|
||
## 9. ТЕСТИРОВАНИЕ
|
||
|
||
- **Фреймворк:** pytest с asyncio_mode=auto
|
||
- **Unit-тесты:** `tests/unit/` — изолированные, mocked зависимости
|
||
- **Integration-тесты:** `tests/integration/` — с БД, реальные запросы
|
||
- **Smoke-тесты:** `tests/smoke/` — минимум 1 на endpoint
|
||
- **Покрытие:** > 80% (критический код: auth, security, payments — 100%)
|
||
|
||
## 10. БЕЗОПАСНОСТЬ
|
||
|
||
- JWT: HS256, access_token 60min, refresh_token 30d
|
||
- Пароли: bcrypt (passlib)
|
||
- .env в .gitignore — всегда
|
||
- Pydantic валидация на всех входах
|
||
- RBAC: user, admin (is_superuser)
|
||
|
||
## 11. РЕШЕНИЯ (SHOULD ASK)
|
||
|
||
Перед каждым из этих выборов — остановись и спроси пользователя:
|
||
|
||
| Решение | Опции по умолчанию |
|
||
|---------|-------------------|
|
||
| База данных | SQLite (dev) → PostgreSQL (prod) |
|
||
| Фоновые задачи | Прямой вызов (dev) → Celery (prod) |
|
||
| AI провайдеры | FallbackChain с 2 провайдерами |
|
||
| Аутентификация | Email+password + JWT |
|
||
| Агенты | 4 ядерных + остальные по необходимости |
|
||
| Фронтенд | React + Vite + Tailwind + PWA |
|
||
| CI/CD | GitHub Actions |
|
||
|
||
## 12. ЧТО ДЕЛАТЬ ЕСЛИ НЕ ЗНАЕШЬ
|
||
|
||
1. Поищи в `docs/` — там описано 90% ситуаций
|
||
2. Если не нашёл — открой `notes/encountered-issues.md` — может это уже было
|
||
3. Если и там нет — посмотри на `notes/improvements.md` — может это запланированное улучшение
|
||
4. Если ничего не помогло — **спроси пользователя с рекомендацией**
|
||
|
||
---
|
||
|
||
*Этот файл сгенерирован на основе реального опыта. Обновляется при изменении проекта.*
|