first commit
Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 0s
CI/CD Pipeline / Code Quality Checks (push) Failing after 1m43s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped

This commit is contained in:
2026-01-21 12:07:35 +01:00
commit e9d7f24aaa
102 changed files with 13890 additions and 0 deletions

422
.qoder/rules/main.md Normal file
View File

@@ -0,0 +1,422 @@
---
trigger: always_on
---
## 0) Язык и стиль общения (СТРОГО)
- ИИ-агент **ВСЕГДА отвечает на русском языке**
- Английский допускается ТОЛЬКО для:
- имён библиотек
- имён классов, функций, переменных
- CLI-команд
- Тон: инженерный, практичный, без воды и маркетинга
---
## 1) Базовые принципы (НЕ ОБСУЖДАЮТСЯ)
Проект разрабатывается строго по принципам:
- **SOLID**
- **KISS**
- **DRY**
Правила приоритета:
- красиво vs просто → **простота**
- умно vs поддерживаемо → **поддерживаемость**
- магия vs явность → **явность**
---
## 2) Контекст проекта
- ОС: **Astra Linux 1.8**
- Python: **3.11.2**
- Django: **3.x (указано 3.14)**
- Django REST Framework (DRF)
- Celery
- PostgreSQL **15.10**
- Apache **2.4.57**
- mod_wsgi **4.9.4**
### Инструменты разработки
- **uv**
- **виртуальная среда**
- **pre-commit**
- **Gitea Actions (CI)**
- Тесты: `django test`
- Линтинг: `ruff`
- **ЗАПРЕЩЕНО** создавать тестовые скрипты для демонстрации, все должно быть исправлено в рамках проекта
---
## 3) Окружение и команды (СТРОГО)
Все команды:
- выполняются **только внутри виртуальной среды**
- используют **uv**
- считаются выполняемыми из корня проекта
### ❌ Запрещено
- `pip`, `python -m pip`
- `poetry`, `pipenv`, `pipx`
- системные команды вне venv
### ✅ Разрешено
- `uv venv`
- `source .venv/bin/activate`
- `uv add / uv remove / uv sync`
- `uv run <command>`
Пример:
```bash
uv run python manage.py test
```
---
## 4) Архитектура и слои ответственности (КРИТИЧНО)
### 4.1 View (DRF)
View отвечает ТОЛЬКО за:
- приём HTTP-запроса
- проверку прав доступа
- работу с serializer
- вызов сервисного слоя
❌ Запрещено:
- бизнес-логика
- сложные условия
- транзакции
- сложная работа с ORM
---
### 4.2 Serializer
Serializer отвечает за:
- валидацию данных
- преобразование вход/выход
Допускается:
- field-level validation
- object-level validation
❌ Запрещено:
- бизнес-правила
- side-effects
- сложная логика в `save()`
---
### 4.3 Сервисный слой (Business Logic)
- **ВСЯ бизнес-логика живёт здесь**
- Сервисы:
- не зависят от HTTP
- легко тестируются
- управляют транзакциями
- Сервис определяет *что* делать, а не *как* отдать ответ
Рекомендуемый паттерн:
```python
class EntityService:
@classmethod
def do_something(cls, *, data):
...
```
---
### 4.4 Модели (ORM)
Модели должны быть:
- простыми
- декларативными
Допускается:
- `__str__`
- простые computed properties
- минимальные helper-методы
❌ Запрещено:
- бизнес-логика
- workflow
- сигналы как логика
- условия, зависящие от сценариев
👉 **Любые исключения — ТОЛЬКО после обсуждения в чате.**
---
## 5) Celery
- Task = **thin wrapper**
- Task вызывает сервис, а не содержит логику
- Таски:
- идемпотентны
- логируют начало и завершение
- Ретраи:
- только для временных ошибок
- с backoff
---
## 6) База данных и миграции
- Любое изменение моделей → миграции обязательны
- Миграции:
- детерминированные
- без ручной магии без причины
Проверка перед коммитом:
```bash
uv run python manage.py makemigrations --check --dry-run
```
PostgreSQL:
- транзакции использовать осознанно
- `select_for_update()` при гонках
- Raw SQL — только с объяснением
---
## 7) Тестирование
- Любая бизнес-логика → тесты
- В первую очередь тестируется сервисный слой
- API — happy path + edge cases
Запуск:
```bash
uv run python manage.py test
```
---
## 8) pre-commit (обязателен)
- Любой код обязан проходить pre-commit
- Агент обязан учитывать проверки форматирования и линтинга
```bash
pre-commit run --all-files
```
---
## 9) CI (Gitea Actions)
- Используется **Gitea Actions**
- ❌ GitHub Actions запрещены
- Любые изменения:
- не должны ломать CI
- Если меняются:
- зависимости
- команды тестов
- миграции
→ агент обязан указать необходимость правок workflow
---
## 10) Apache + mod_wsgi
- Используется **ТОЛЬКО WSGI**
- ASGI запрещён без отдельного обсуждения
- Любые изменения в `wsgi.py`, путях, статике:
- сопровождаются пояснением
- требуют перезапуска Apache
```bash
systemctl restart apache2
```
Учитывать ограничения и права Astra Linux.
---
## 11) Работа с репозиторием
- Минимальный diff — приоритет
-Не коммитить:
- `.venv`
- артефакты
- дампы БД
- Массовый рефакторинг — только по явному запросу
---
## 12) Anti-patterns (ЗАПРЕЩЕНО)
- Fat Models
- God Views
- Бизнес-логика в Serializers
- Сигналы как workflow
- Магия в `save()`
- Прямые импорты моделей между apps
- Сложная логика в queryset как бизнес-правило
---
## 13) Формат ответа ИИ-агента (ОБЯЗАТЕЛЬНЫЙ)
Каждый ответ должен содержать:
1. **Что меняем**
2. **Файлы / патч**
3. **Команды (через uv)**
4. **Проверки (tests / pre-commit / CI)**
5. **Риски / замечания**
---
## 14) Исключения
- ИИ-агент **НЕ внедряет исключения сам**
- Агент:
- описывает стандартное решение
- объясняет, почему оно не подходит
- запрашивает разрешение в чате
## 15) Структура проекта и миксины (ОБЯЗАТЕЛЬНО)
### 15.0 Правило Core-First (КРИТИЧНО)
**ПЕРЕД созданием любого нового компонента** агент ОБЯЗАН проверить модуль `apps.core`:
```
src/apps/core/
├── mixins.py # Model mixins (TimestampMixin, SoftDeleteMixin, etc.)
├── services.py # BaseService, BackgroundJobService
├── views.py # Health checks, BackgroundJob API
├── viewsets.py # BaseViewSet, ReadOnlyViewSet
├── exceptions.py # APIError, NotFoundError, ValidationError
├── permissions.py # IsOwner, IsAdminOrReadOnly, etc.
├── pagination.py # CursorPagination
├── filters.py # BaseFilterSet
├── cache.py # cache_result, invalidate_cache
├── tasks.py # BaseTask для Celery
├── logging.py # StructuredLogger
├── middleware.py # RequestIDMiddleware
├── signals.py # SignalDispatcher
├── responses.py # APIResponse wrapper
├── openapi.py # api_docs decorator
└── management/commands/base.py # BaseAppCommand
```
**Порядок действий:**
1. Проверить `apps.core` на наличие нужного базового класса/миксина
2. Наследоваться от существующего, а не создавать с нуля
3. Если нужного нет — обсудить добавление в core
**ЗАПРЕЩЕНО:** создавать дублирующую функциональность в app-модулях
---
### 15.1 Model Mixins
При создании моделей **ОБЯЗАТЕЛЬНО** использовать миксины из `apps.core.mixins`:
| Миксин | Когда использовать | Поля |
|--------|-------------------|------|
| `TimestampMixin` | **ВСЕГДА** для любой модели | `created_at`, `updated_at` |
| `UUIDPrimaryKeyMixin` | Когда нужен UUID вместо int ID | `id` (UUID) |
| `SoftDeleteMixin` | Когда нельзя физически удалять | `is_deleted`, `deleted_at` |
| `AuditMixin` | Когда нужно знать кто создал/изменил | `created_by`, `updated_by` |
| `OrderableMixin` | Для сортируемых списков | `order` |
| `StatusMixin` | Для моделей со статусами | `status` |
| `SlugMixin` | Для URL-friendly идентификаторов | `slug` |
**Пример правильного использования:**
```python
from apps.core.mixins import TimestampMixin, SoftDeleteMixin, AuditMixin
class Document(TimestampMixin, SoftDeleteMixin, AuditMixin, models.Model):
"""Документ с историей и мягким удалением."""
title = models.CharField(max_length=200)
class Meta:
ordering = ['-created_at']
```
**Порядок наследования миксинов:**
1. `UUIDPrimaryKeyMixin` (если нужен)
2. `TimestampMixin`
3. `SoftDeleteMixin` (если нужен)
4. `AuditMixin` (если нужен)
5. `OrderableMixin` / `StatusMixin` / `SlugMixin`
6. `models.Model` (последним)
---
### 15.2 Management Commands
Все management commands наследуются от `BaseAppCommand`:
```python
from apps.core.management.commands.base import BaseAppCommand
class Command(BaseAppCommand):
help = 'Описание команды'
use_transaction = True # Обернуть в транзакцию
def add_arguments(self, parser):
super().add_arguments(parser) # Добавляет --dry-run, --silent
parser.add_argument('--my-arg', type=str)
def execute_command(self, *args, **options):
items = MyModel.objects.all()
for item in self.progress_iter(items, desc="Обработка"):
if not self.dry_run:
self.process(item)
return "Обработано успешно"
```
**Возможности BaseAppCommand:**
- `--dry-run` — тестовый запуск без изменений
- `--silent` — минимальный вывод
- `self.progress_iter()` — прогресс-бар
- `self.timed_operation()` — измерение времени
- `self.confirm()` — подтверждение
- `self.log_info/success/warning/error()` — логирование
---
### 15.3 Background Jobs (Celery)
Для отслеживания статуса фоновых задач использовать `BackgroundJob`:
```python
# В сервисе при запуске задачи
from apps.core.services import BackgroundJobService
job = BackgroundJobService.create_job(
task_id=task.id,
task_name="apps.myapp.tasks.process_data",
user_id=request.user.id,
)
# В Celery таске
from apps.core.models import BackgroundJob
@shared_task(bind=True)
def my_task(self, data):
job = BackgroundJob.objects.get(task_id=self.request.id)
job.mark_started()
for i, item in enumerate(items):
process(item)
job.update_progress(i * 100 // len(items), "Обработка...")
job.complete(result={"processed": len(items)})
```
**API эндпоинты:**
- `GET /api/v1/jobs/` — список задач пользователя
- `GET /api/v1/jobs/{task_id}/` — статус конкретной задачи
---
### 15.4 Factories (тестирование)
Все фабрики используют `factory_boy` + `faker`:
```python
import factory
from faker import Faker
fake = Faker("ru_RU")
class MyModelFactory(factory.django.DjangoModelFactory):
class Meta:
model = MyModel
name = factory.LazyAttribute(lambda _: fake.word())
email = factory.LazyAttribute(lambda _: fake.unique.email())
```
**Правила:**
- Никакого хардкода в тестах (`"test@example.com"``fake.email()`)
- Использовать `fake.unique.*` для уникальных полей
- Локаль: `Faker("ru_RU")` для русских данных