Дата: 2025-11-10
Статус: Архитектурное решение
Версия: 1.0.0
| Инструмент | Что это | Где работает | Зачем нужен |
|---|---|---|---|
| Git | Программа для версионирования | Командная строка | Хранит историю файлов |
| GitPython | Библиотека Python | Внутри Python кода | Управление Git из кода |
| GitHub | Облачный сервис | Интернет (github.com) | Хранение + веб-интерфейс |
| Gitea | Самостоятельный сервер Git | Ваш сервер | Свой GitHub на своём сервере |
Что это:
- Веб-интерфейс для Git (как GitHub, но на вашем сервере)
- Написан на Go (быстрый, легковесный)
- Open Source
Что умеет:
- ✅ Веб-интерфейс для репозиториев
- ✅ Pull requests, issues, wiki
- ✅ Code review
- ✅ Webhooks (автоматизация)
- ✅ Пользователи и права доступа
- ✅ API для интеграций
Установка:
# Один бинарник - и готово
wget https://dl.gitea.io/gitea/1.21/gitea-1.21-linux-amd64
chmod +x gitea-1.21-linux-amd64
./gitea-1.21-linux-amd64 web
Аналоги:
- GitLab (тяжелее, больше функций)
- Gogs (предшественник Gitea, проще)
Вы → Браузер → Gitea (http://91.218.142.168:3000)
↓
Смотрите коммиты, файлы, историю
Плюсы:
- ✅ Удобно просматривать код в браузере
- ✅ Не нужен VS Code для просмотра
- ✅ История коммитов наглядно
Минусы:
- ❌ Ещё один сервис (порт 3000)
- ❌ Нужно обслуживать
Git commit → Gitea → Webhook → FastAPI → Запустить тесты
Плюсы:
- ✅ Автоматизация при коммитах
- ✅ CI/CD из коробки
Минусы:
- ❌ Можно сделать проще (Git hooks)
Вы → VS Code (Remote-SSH) → Работаете с файлами
↓
Git в командной строке
Плюсы:
- ✅ Проще (меньше компонентов)
- ✅ VS Code и так показывает Git
- ✅ Не нужен отдельный порт
Пока НЕ ставим Gitea, оставляем обычный Git.
Что должен уметь:
API для агентов
- Получить задачу от пользователя
- Отправить запрос к агенту
- Получить результат
Управление проектами
- CRUD для проектов
- Чтение/запись документов
- Git операции
Интеграция с Claude API
- Отправка промптов в Claude
- Получение ответов
- Стриминг (опционально)
Real-time обновления
- WebSocket для чата
- Статусы агентов
Простота разработки
- Быстрый старт
- Понятный код
- Хорошая документация
from fastapi import FastAPI
app = FastAPI()
@app.post("/api/chat")
async def chat(message: str):
return {"response": "Hello"}
Тип: Асинхронный микрофреймворк
Язык: Python 3.7+
Скорость: ⚡⚡⚡ Очень быстрый
Сложность: 🟢 Простой
Современный и быстрый
- Асинхронный (async/await)
- Один из самых быстрых Python фреймворков
- Comparable с Go и Node.js
Автоматическая документация
http://localhost:8000/docs ← Swagger UI из коробки
http://localhost:8000/redoc ← ReDoc из коробки
Type hints и валидация
```python
from pydantic import BaseModel
class ChatRequest(BaseModel):
message: str
project: str | None = None
@app.post("/api/chat")
async def chat(request: ChatRequest): # ← Автовалидация!
return {"response": "OK"}
```
WebSocket из коробки
python
@app.websocket("/ws/chat")
async def websocket_chat(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Response: {data}")
Минимальный код
- Нет лишних абстракций
- Только то, что нужно
- Легко понять и модифицировать
Dependency Injection
```python
async def get_db():
db = Database()
yield db
db.close()
@app.get("/projects")
async def list_projects(db: Database = Depends(get_db)):
return db.query_all()
```
Нет встроенной ORM
- Нужно подключать SQLAlchemy отдельно
- Или использовать чистый SQL
Нет встроенной админки
- Django Admin из коробки, FastAPI - нет
- Нужно делать самому или ставить сторонние
Молодой фреймворк
- Появился в 2018 году
- Меньше готовых решений чем для Django
Не подходит для сложных веб-приложений
- Нет шаблонизатора (Jinja2 нужно отдельно)
- Нет форм, сессий из коробки
- Но нам это и не нужно!
✅ Идеально для:
- API-first приложений
- Микросервисов
- Интеграций с ML/AI
- Real-time приложений (WebSocket)
- Когда фронтенд отдельно (React/Vue/Streamlit)
❌ Не подходит для:
- Классических веб-сайтов с SSR
- Монолитных приложений с админкой
- Если нужна готовая CMS
from fastapi import FastAPI, WebSocket
from pydantic import BaseModel
from typing import Optional
import anthropic
app = FastAPI(title="Платформа ЦИФРА")
# Models
class ChatRequest(BaseModel):
message: str
project: Optional[str] = None
class ProjectCreate(BaseModel):
name: str
template: str
# Endpoints
@app.post("/api/chat")
async def chat(request: ChatRequest):
"""Отправить сообщение агентам"""
central = CentralAgent(workspace="/opt/claude-workspace")
response = await central.process(request.message)
return {
"response": response["text"],
"actions": response["actions"],
"status": "completed"
}
@app.get("/api/projects")
async def list_projects():
"""Список всех проектов"""
projects_dir = Path("/opt/claude-workspace/projects")
projects = []
for p in projects_dir.iterdir():
if p.is_dir() and (p / "PROJECT.md").exists():
metadata = parse_frontmatter(p / "PROJECT.md")
projects.append({
"name": p.name,
"status": metadata.get("status"),
"version": metadata.get("version")
})
return projects
@app.get("/api/documents/{project}/{path:path}")
async def get_document(project: str, path: str):
"""Получить содержимое документа"""
file_path = Path(f"/opt/claude-workspace/projects/{project}/{path}")
if not file_path.exists():
raise HTTPException(404, "File not found")
content = file_path.read_text()
metadata = parse_frontmatter_if_exists(content)
return {
"content": content,
"metadata": metadata,
"path": str(file_path)
}
@app.websocket("/ws/chat")
async def websocket_chat(websocket: WebSocket):
"""Real-time чат с агентами"""
await websocket.accept()
try:
while True:
message = await websocket.receive_text()
# Обработка агентами
response = await process_message(message)
# Отправка ответа
await websocket.send_json({
"type": "response",
"data": response
})
except WebSocketDisconnect:
print("Client disconnected")
# Запуск
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Размер: ~150 строк
Время разработки: 1 день
Зависимости: fastapi, uvicorn, pydantic
from django.http import JsonResponse
def chat(request):
message = request.POST.get('message')
return JsonResponse({"response": "Hello"})
Тип: Полнофункциональный фреймворк (batteries included)
Язык: Python 2/3
Скорость: ⚡ Средняя
Сложность: 🟡 Средняя/Высокая
Всё из коробки
- ORM (база данных)
- Админка (Django Admin)
- Аутентификация/авторизация
- Формы, валидация
- Шаблонизатор
- Сессии, куки
- Миграции БД
Django Admin
http://localhost:8000/admin ← Готовая админка!
- CRUD для всех моделей
- Поиск, фильтры
- Редактирование в браузере
Огромная экосистема
- 15+ лет развития
- Тысячи готовых пакетов
- Решение для любой задачи
Django REST Framework
- Мощный API framework
- Сериализация, валидация
- Browsable API (документация)
- Throttling, permissions
Безопасность из коробки
- Защита от CSRF, XSS, SQL injection
- Проверенный временем
Для больших команд
- Четкая структура проекта
- Конвенции и best practices
- Масштабируемость
Тяжеловесный
- Много кода для простых задач
- Долгий старт проекта
- Больше файлов, больше конфигурации
Медленнее FastAPI
- Синхронный (до Django 4.0)
- Асинхронность частичная (4.0+)
- Больше overhead
ORM обязательна
- Всё завязано на Django ORM
- Сложно использовать чистый SQL
- Нам база данных пока не нужна!
Избыточен для API
- Много лишнего для API-only приложения
- Шаблоны, формы - не нужны если фронтенд отдельно
Сложнее для новичков
- Больше концепций (apps, models, views, urls, templates)
- Дольше разбираться
✅ Идеально для:
- Монолитных веб-приложений
- Когда нужна админка из коробки
- CMS, блоги, интернет-магазины
- Большие проекты с командой
- Когда нужна ORM и миграции
❌ Избыточен для:
- Простых API
- Микросервисов
- Когда база данных не нужна
- Когда важна скорость разработки
# models.py
from django.db import models
class Project(models.Model):
name = models.CharField(max_length=100)
template = models.CharField(max_length=50)
status = models.CharField(max_length=20)
created_at = models.DateTimeField(auto_now_add=True)
class Agent(models.Model):
name = models.CharField(max_length=50)
status = models.CharField(max_length=20)
config = models.JSONField()
# serializers.py
from rest_framework import serializers
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
# views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['POST'])
def chat(request):
message = request.data.get('message')
# Обработка
central = CentralAgent()
response = central.process(message)
return Response({
"response": response["text"],
"status": "completed"
})
# urls.py
from django.urls import path
urlpatterns = [
path('api/chat/', chat),
path('api/projects/', ProjectListView.as_view()),
path('admin/', admin.site.urls),
]
Размер: ~300-400 строк (+ настройка)
Время разработки: 2-3 дня
Зависимости: django, djangorestframework
from flask import Flask, request
app = Flask(__name__)
@app.route('/api/chat', methods=['POST'])
def chat():
message = request.json.get('message')
return {"response": "Hello"}
Тип: Микрофреймворк
Язык: Python 2/3
Скорость: ⚡⚡ Хорошая
Сложность: 🟢 Простая
Простой и гибкий
- Минимализм
- Подключаешь только что нужно
- Нет жестких правил
Огромная экосистема
- 13+ лет существования
- Тысячи расширений
- Много готовых решений
Легкий старт
- Файл в 10 строк - уже работает
- Понятный для новичков
Flask-SocketIO
- WebSocket поддержка через расширение
- Простая интеграция
Синхронный
- Нет async/await
- Медленнее FastAPI
Нет автодокументации
- Swagger нужно настраивать вручную
- Нет валидации из коробки
Устаревает
- FastAPI забирает популярность
- Меньше новых фич
Ручная валидация
- Нет Pydantic
- Проверки вручную или через marshmallow
✅ Хорошо для:
- Простых API
- Прототипов
- Маленьких проектов
- Когда знаешь Flask
❌ Хуже чем FastAPI для:
- Современных API
- Когда важна скорость
- Когда нужна автодокументация
FastAPI лучше - современнее, быстрее, удобнее для API.
from sanic import Sanic, response
app = Sanic("MyApp")
@app.post("/api/chat")
async def chat(request):
return response.json({"response": "Hello"})
FastAPI лучше - больше документации, Pydantic, автодокументация.
from aiohttp import web
async def chat(request):
data = await request.json()
return web.json_response({"response": "Hello"})
app = web.Application()
app.add_routes([web.post('/api/chat', chat)])
FastAPI лучше - выше уровень абстракции, автодокументация.
| Критерий | FastAPI | Django | Flask | Sanic | aiohttp |
|---|---|---|---|---|---|
| Скорость | ⚡⚡⚡ | ⚡ | ⚡⚡ | ⚡⚡⚡ | ⚡⚡⚡ |
| Простота | 🟢 Простой | 🟡 Средний | 🟢 Простой | 🟢 Простой | 🔴 Сложный |
| Async | ✅ Да | 🟡 Частично | ❌ Нет | ✅ Да | ✅ Да |
| Автодокументация | ✅ Swagger | ❌ Нет | ❌ Нет | ❌ Нет | ❌ Нет |
| Валидация | ✅ Pydantic | ✅ Forms/ORM | 🟡 marshmallow | ❌ Ручная | ❌ Ручная |
| ORM | ❌ Нужна SQLAlchemy | ✅ Django ORM | ❌ Нужна | ❌ Нужна | ❌ Нужна |
| Админка | ❌ Нет | ✅ Есть | ❌ Нет | ❌ Нет | ❌ Нет |
| WebSocket | ✅ Из коробки | 🟡 Channels | 🟡 SocketIO | ✅ Да | ✅ Да |
| Размер кода | Малый | Большой | Малый | Малый | Средний |
| Популярность | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| Для API | ✅ Идеально | 🟡 Избыточен | ✅ Хорошо | ✅ Хорошо | 🟡 Сложно |
| Для монолита | ❌ Не подходит | ✅ Идеально | 🟡 Можно | ❌ Нет | ❌ Нет |
Что нужно ПЛАТФОРМЕ ЦИФРА:
Главные причины:
API-first подход
- Мы делаем API для агентов
- Django избыточен (ORM, админка, формы - не нужны)
- FastAPI создан именно для API
Скорость
- Один из самых быстрых Python фреймворков
- Асинхронный (async/await)
- Важно для real-time с Claude API
Автодокументация
http://localhost:8000/docs ← Swagger UI бесплатно!
- Видим все endpoints
- Можно тестировать прямо в браузере
- Документация всегда актуальна
Минимум кода
- 150 строк vs 400 строк (Django)
- Быстрее разрабатывать
- Легче поддерживать
Современный
- Type hints
- Pydantic валидация
- Async из коробки
- WebSocket из коробки
Простая интеграция
- С anthropic SDK (async)
- С Streamlit (фронтенд)
- С Git через GitPython
❌ Django - избыточен (ORM, админка не нужны)
❌ Flask - устаревает, синхронный, нет автодокументации
❌ Sanic - меньше документации, FastAPI лучше
❌ aiohttp - низкоуровневый, много ручной работы
❌ Gitea - пока не нужен, VS Code достаточно
/opt/claude-workspace/
├── platform/
│ ├── backend/ # ← FastAPI приложение
│ │ ├── main.py # Точка входа
│ │ ├── api/
│ │ │ ├── chat.py # /api/chat
│ │ │ ├── projects.py # /api/projects
│ │ │ ├── documents.py # /api/documents
│ │ │ ├── agents.py # /api/agents
│ │ │ └── git.py # /api/git
│ │ ├── core/
│ │ │ ├── agents/ # Агенты
│ │ │ │ ├── base.py # BaseAgent
│ │ │ │ ├── document.py # DocumentAgent
│ │ │ │ ├── code.py # CodeAgent
│ │ │ │ └── git.py # GitAgent
│ │ │ ├── claude.py # Интеграция с Claude API
│ │ │ └── workspace.py # Работа с workspace
│ │ ├── models/
│ │ │ ├── requests.py # Pydantic модели запросов
│ │ │ └── responses.py # Pydantic модели ответов
│ │ ├── config.py # Конфигурация
│ │ └── requirements.txt
│ │
│ └── core/ # ← Ядро (агенты standalone)
│ ├── agents/
│ ├── templates/
│ └── config/
│
├── projects/ # Проекты пользователя
├── templates/ # Шаблоны
└── .claude/ # Контекст между сессиями
┌─────────────────────────────────────────────────────────┐
│ FRONTEND (Browser) │
│ Streamlit / React │
└────────────────────┬────────────────────────────────────┘
│ HTTP / WebSocket
↓
┌─────────────────────────────────────────────────────────┐
│ FASTAPI BACKEND │
│ ┌──────────────────────────────────────────────────┐ │
│ │ API Endpoints (Port 8000) │ │
│ │ /api/chat - Диалог с агентами │ │
│ │ /api/projects - Управление проектами │ │
│ │ /api/documents - Чтение/запись документов │ │
│ │ /api/agents - Статус и управление │ │
│ │ /api/git - Git операции │ │
│ │ /ws/chat - WebSocket real-time │ │
│ └──────────────┬───────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Agent Orchestration │ │
│ │ CentralAgent - маршрутизация задач │ │
│ │ TaskQueue - очередь задач │ │
│ └──────────────┬───────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Core Agents │ │
│ │ DocumentAgent - работа с документами │ │
│ │ CodeAgent - генерация кода │ │
│ │ GitAgent - Git операции │ │
│ └──────────────┬───────────────────────────────────┘ │
└─────────────────┼────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ INFRASTRUCTURE │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Claude API (anthropic SDK) │ │
│ │ - claude-sonnet-4-5-20250929 │ │
│ │ - Async client │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Git Repository (/opt/claude-workspace) │ │
│ │ - Markdown documents │ │
│ │ - YAML frontmatter │ │
│ │ - GitPython для операций │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Назначение: Отправить сообщение агентам
Request:
{
"message": "Создай новый проект analytics",
"project": "analytics",
"context": {
"current_file": "PROJECT.md"
}
}
Response:
{
"response": "Создал проект analytics используя шаблон streamlit-mvp-v1",
"actions": [
{
"type": "project_created",
"project": "analytics",
"path": "/opt/claude-workspace/projects/analytics"
}
],
"agent": "DocumentAgent",
"status": "completed",
"tokens": 1250
}
Код:
@app.post("/api/chat")
async def chat(request: ChatRequest) -> ChatResponse:
central = CentralAgent(workspace="/opt/claude-workspace")
# Обработка через агентов
result = await central.process_message(
message=request.message,
context=request.context
)
return ChatResponse(
response=result["text"],
actions=result["actions"],
agent=result["agent"],
status="completed"
)
Назначение: Список всех проектов
Response:
{
"projects": [
{
"name": "marketplace",
"status": "active",
"version": "0.2.0",
"created": "2025-11-09",
"path": "/opt/claude-workspace/projects/marketplace",
"has_design": true,
"has_solution": true
},
{
"name": "analytics",
"status": "planning",
"version": "0.1.0",
"created": "2025-11-10",
"path": "/opt/claude-workspace/projects/analytics",
"has_design": true,
"has_solution": false
}
],
"total": 2
}
Код:
@app.get("/api/projects")
async def list_projects() -> ProjectListResponse:
workspace = Path("/opt/claude-workspace/projects")
projects = []
for project_dir in workspace.iterdir():
if not project_dir.is_dir():
continue
project_file = project_dir / "PROJECT.md"
if not project_file.exists():
continue
# Парсинг frontmatter
metadata = parse_frontmatter(project_file)
projects.append({
"name": project_dir.name,
"status": metadata.get("status", "unknown"),
"version": metadata.get("version", "0.0.0"),
"created": metadata.get("created", ""),
"path": str(project_dir),
"has_design": (project_dir / "design").exists(),
"has_solution": (project_dir / "solution").exists()
})
return ProjectListResponse(projects=projects, total=len(projects))
Назначение: Создать новый проект
Request:
{
"name": "analytics",
"template": "streamlit-mvp-v1",
"description": "Дашборд аналитики продаж"
}
Response:
{
"project": {
"name": "analytics",
"status": "created",
"version": "0.1.0",
"path": "/opt/claude-workspace/projects/analytics"
},
"files_created": [
"PROJECT.md",
"design/ROADMAP.md",
"design/ARCHITECTURE.md",
"management/README.md",
"solution/mvp/.gitkeep"
]
}
Назначение: Получить документ
Example: /api/documents/marketplace/design/ROADMAP.md
Response:
{
"content": "# Roadmap\n\n## Phase 1...",
"metadata": {
"version": "1.2.0",
"status": "active",
"updated": "2025-11-10"
},
"path": "/opt/claude-workspace/projects/marketplace/design/ROADMAP.md",
"size": 2450,
"modified": "2025-11-10T15:30:00"
}
Назначение: Обновить документ
Request:
{
"content": "# Updated Roadmap\n\n...",
"metadata": {
"version": "1.3.0",
"updated": "2025-11-10"
},
"commit_message": "update: roadmap phase 2 details"
}
Response:
{
"status": "updated",
"commit": "a3f5b21",
"path": "/opt/claude-workspace/projects/marketplace/design/ROADMAP.md"
}
Назначение: Статус всех агентов
Response:
{
"agents": [
{
"name": "DocumentAgent",
"status": "idle",
"version": "1.0.0",
"capabilities": ["create", "read", "update", "search"]
},
{
"name": "CodeAgent",
"status": "busy",
"version": "1.0.0",
"current_task": "Generating component code",
"progress": 75
},
{
"name": "GitAgent",
"status": "idle",
"version": "1.0.0"
}
]
}
Назначение: Real-time диалог
Client → Server:
{
"type": "message",
"data": {
"message": "Создай проект analytics",
"project": null
}
}
Server → Client (stream):
// 1. Acknowledgment
{
"type": "ack",
"message_id": "msg_123"
}
// 2. Agent started
{
"type": "agent_started",
"agent": "DocumentAgent",
"task": "create_project"
}
// 3. Progress updates
{
"type": "progress",
"step": "Creating project structure",
"progress": 50
}
// 4. Final response
{
"type": "response",
"data": {
"response": "Проект analytics создан",
"actions": [...]
}
}
// 5. Completion
{
"type": "completed",
"status": "success"
}
Назначение: Git commit
Request:
{
"message": "feat: добавлен модуль аналитики",
"files": [
"projects/analytics/solution/mvp/app.py",
"projects/analytics/design/ARCHITECTURE.md"
]
}
Response:
{
"commit": "b4c2a91",
"message": "feat: добавлен модуль аналитики",
"files_changed": 2,
"insertions": 150,
"deletions": 5
}
# requirements.txt
# FastAPI + ASGI сервер
fastapi==0.104.1
uvicorn[standard]==0.24.0
# Pydantic для валидации
pydantic==2.5.0
pydantic-settings==2.1.0
# Anthropic SDK
anthropic==0.7.0
# Git интеграция
GitPython==3.1.40
# Markdown + YAML
python-frontmatter==1.0.1
PyYAML==6.0.1
# WebSocket
websockets==12.0
# Опционально (Phase 1+)
# SQLAlchemy==2.0.23 # Если нужна БД
# Jinja2==3.1.2 # Если нужны шаблоны
# pytest==7.4.3 # Тесты
# config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# Claude API
claude_api_key: str
claude_model: str = "claude-sonnet-4-5-20250929"
claude_max_tokens: int = 4096
# Workspace
workspace_path: str = "/opt/claude-workspace"
# Server
backend_host: str = "0.0.0.0"
backend_port: int = 8000
# CORS
cors_origins: list[str] = ["http://localhost:3000"]
class Config:
env_file = ".env"
settings = Settings()
# Development
uvicorn main:app --reload --host 0.0.0.0 --port 8000
# Production
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
# /etc/systemd/system/cifra-backend.service
[Unit]
Description=CIFRA Platform Backend
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/claude-workspace/platform/backend
Environment="CLAUDE_API_KEY=sk-ant-..."
ExecStart=/usr/bin/uvicorn main:app --host 0.0.0.0 --port 8000
Restart=always
[Install]
WantedBy=multi-user.target
systemctl enable cifra-backend
systemctl start cifra-backend
systemctl status cifra-backend
# core/agents/base.py
from abc import ABC, abstractmethod
from anthropic import Anthropic
class BaseAgent(ABC):
def __init__(self, workspace: str, config: dict):
self.workspace = Path(workspace)
self.config = config
self.claude = Anthropic(api_key=config['claude_api_key'])
@abstractmethod
async def execute(self, task: dict) -> dict:
"""Выполнить задачу"""
pass
async def call_claude(self, prompt: str, system: str = None) -> str:
"""Вызвать Claude API"""
response = await self.claude.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=4096,
system=system,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text
# core/agents/central.py
class CentralAgent:
def __init__(self, workspace: str):
self.workspace = workspace
self.agents = {
'document': DocumentAgent(workspace, config),
'code': CodeAgent(workspace, config),
'git': GitAgent(workspace, config)
}
async def process_message(self, message: str, context: dict = None) -> dict:
"""Обработать сообщение пользователя"""
# 1. Определить тип задачи
task_type = await self._classify_task(message)
# 2. Выбрать агента
agent = self._select_agent(task_type)
# 3. Выполнить задачу
result = await agent.execute({
'message': message,
'context': context
})
# 4. Вернуть результат
return {
'text': result['response'],
'actions': result['actions'],
'agent': agent.__class__.__name__,
'status': 'completed'
}
async def _classify_task(self, message: str) -> str:
"""Определить тип задачи через Claude"""
prompt = f"""
Определи тип задачи:
- document: работа с документами (создание, чтение, поиск)
- code: генерация кода
- git: Git операции
Сообщение: {message}
Ответь одним словом: document/code/git
"""
response = await self.claude.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=10,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text.strip().lower()
def _select_agent(self, task_type: str):
return self.agents.get(task_type, self.agents['document'])
91.218.142.168
├─ /opt/claude-workspace/
│ ├── platform/
│ │ └── backend/ ← FastAPI код
│ │ ├── main.py
│ │ ├── api/
│ │ ├── core/
│ │ └── requirements.txt
│ │
│ ├── projects/ ← Проекты пользователя
│ ├── templates/ ← Шаблоны
│ └── .claude/ ← Контекст
│
├─ systemd services
│ ├── cifra-backend.service (Port 8000)
│ └── cifra-frontend.service (Port 3000)
│
└─ nginx
├── 80 → 3000 (frontend)
└── /api → 8000 (backend)
# /etc/nginx/sites-available/cifra
upstream backend {
server 127.0.0.1:8000;
}
upstream frontend {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name 91.218.142.168;
# Frontend
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Backend API
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
}
# WebSocket
location /ws/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Docs
location /docs {
proxy_pass http://backend;
}
}
# main.py
import logging
from logging.handlers import RotatingFileHandler
# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
RotatingFileHandler(
'/opt/claude-workspace/.claude/logs/backend.log',
maxBytes=10*1024*1024, # 10MB
backupCount=5
),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
@app.post("/api/chat")
async def chat(request: ChatRequest):
logger.info(f"Chat request: {request.message[:50]}...")
try:
result = await central.process_message(request.message)
logger.info(f"Response: {result['text'][:50]}...")
return result
except Exception as e:
logger.error(f"Error: {e}", exc_info=True)
raise HTTPException(500, str(e))
# Простые метрики
metrics = {
'requests_total': 0,
'requests_by_endpoint': {},
'errors_total': 0,
'tokens_used': 0
}
@app.middleware("http")
async def track_metrics(request: Request, call_next):
metrics['requests_total'] += 1
endpoint = request.url.path
metrics['requests_by_endpoint'][endpoint] = \
metrics['requests_by_endpoint'].get(endpoint, 0) + 1
response = await call_next(request)
return response
@app.get("/api/metrics")
async def get_metrics():
return metrics
# .env (НЕ коммитим в Git!)
CLAUDE_API_KEY=sk-ant-api03-xxx...
# config.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
claude_api_key: str
class Config:
env_file = ".env"
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], # Frontend
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
@app.post("/api/chat")
@limiter.limit("10/minute")
async def chat(request: Request, data: ChatRequest):
...
# tests/test_api.py
import pytest
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_chat_endpoint():
response = client.post("/api/chat", json={
"message": "Привет",
"project": None
})
assert response.status_code == 200
data = response.json()
assert "response" in data
assert "agent" in data
def test_list_projects():
response = client.get("/api/projects")
assert response.status_code == 200
data = response.json()
assert "projects" in data
assert isinstance(data["projects"], list)
pytest tests/ -v
FastAPI (порт 8000)
- REST API endpoints
- WebSocket для real-time
- Автодокументация Swagger
Core Agents
- DocumentAgent
- CodeAgent
- GitAgent
- CentralAgent (координатор)
Интеграции
- Anthropic SDK (Claude API)
- GitPython (Git операции)
- python-frontmatter (Markdown metadata)
Инфраструктура
- Systemd сервис
- Nginx прокси
- Логирование
platform/backend/
├── main.py # Точка входа FastAPI
├── config.py # Конфигурация
├── requirements.txt # Зависимости
├── api/
│ ├── chat.py
│ ├── projects.py
│ ├── documents.py
│ ├── agents.py
│ └── git.py
├── core/
│ ├── agents/
│ │ ├── base.py
│ │ ├── central.py
│ │ ├── document.py
│ │ ├── code.py
│ │ └── git.py
│ ├── claude.py
│ └── workspace.py
├── models/
│ ├── requests.py
│ └── responses.py
└── tests/
├── test_api.py
└── test_agents.py
После утверждения этой архитектуры:
/opt/claude-workspace/platform/backend//api/chat)Версия: 1.0.0
Статус: Готово к обсуждению
Следующий шаг: Утверждение архитектуры и начало разработки