230 lines
15 KiB
Markdown
230 lines
15 KiB
Markdown
# AGENTS.md — Окнардия: Оконный Агрегатор
|
||
|
||
**Версия**: 0.2.0 | **Язык**: Python 3.12+ + Django 6.0+ | **БД**: MariaDB/MySQL
|
||
|
||
Этот документ обеспечивает AI-агентов (Copilot, Claude, Cursor и т.д.) контекстом для эффективной работы с проектом.
|
||
|
||
## Архитектура и назначение
|
||
|
||
**Окнардия** — это агрегатор для сравнения цен на установку оконных конструкций в зданиях типового (серийного) строительства в России. Пользователи вводят адрес дома → система распознаёт серию строения → выдаёт типовые размеры оконных проемов → показывает предложения от поставщиков на установку (замену) окон.
|
||
|
||
Архитектура двухуровневая:
|
||
- **Основной проект**: `oknardia/` (Django settings, URL routing, models, templates)
|
||
- **Приложение логики**: `web/` (views, вспомогательные функции, кеширование схем окон)
|
||
|
||
## Критические компоненты и модели данных
|
||
|
||
### Основные модели (oknardia/models.py)
|
||
|
||
**Иерархия зданий:**
|
||
- `Seria_Info` — серия типового строения (P-44, 5-этажка и т.п.), поддерживает self-referential FK для древовидной структуры
|
||
- `Building_Info` — конкретный адрес с ссылкой на серию; содержит ~30 полей метаданных (площадь, износ, материалы)
|
||
- `Apartment_Type` — типовой план квартиры в серии; содержит связь M2M с `Win_MountDim`
|
||
- `MountDim2Apartment` — через-таблица между проёмами и квартирами
|
||
|
||
**Каталог и цены:**
|
||
- `PVCprofiles` — PVC-профили (окна), содержат рейтинг (0…+5) и tech-specs
|
||
- `Glazing` — стеклопакеты с изоляционными параметрами и рейтингом
|
||
- `SetKit` — готовый "набор" (профиль + стеклопакет + фурнитура + монтаж), связывает компоненты и хранит бизнес-условия
|
||
- `PriceOffer` — финальная цена для конкретного проёма и набора от конкретного пользователя
|
||
|
||
**Дополнительные сущности:**
|
||
- `OurUser` — собственная система пользователей (расширение Django User)
|
||
- `MerchantBrand` / `MerchantOffice` — организационная иерархия поставщиков
|
||
- `BlogPosts` — универсальная таблица для блога и каталога (одна таблица, флаги `bCatalog`, `bPublished`)
|
||
- Несколько LOG-таблиц: `LogMeasure`, `LogDemand`, `LogVisitPriceReport`
|
||
|
||
**Именование полей** (обязательное соглашение):
|
||
- `s*` = String/Char
|
||
- `i*` = Integer
|
||
- `f*` = Float/Decimal
|
||
- `b*` = Boolean
|
||
- `d*` = DateTime/Date
|
||
- `k*` = Foreign Key (связь)
|
||
- `p*` = Path/Media
|
||
- Например: `sSetName` — название набора, `fSetRating` — рейтинг набора
|
||
|
||
### Кеширование и специфика
|
||
|
||
1. **Картинки схем окон** генерируются автоматически в:
|
||
- `public/static/img/_flap.cfg` — большие картинки схем открывания
|
||
- `public/static/img/_miniflap.cfg` — миниатюры для таблиц
|
||
- **Важно**: не удалять просто так, они переиспользуются; если схема архивируется, картинка остаётся без явного удаления
|
||
|
||
2. **Pre-render HTML-шаблоны** для серий в `oknardia/templates/seria_info/prepared/`
|
||
- Создаются при первом обращении к странице серии
|
||
- **Требуют ручной очистки** при изменении цен/спецификаций или настройки cronjob на удаление
|
||
|
||
3. **Кольцевой буфер логирования** (настройка `MAX_LEN_RING_LOG_BUFFER=250` в settings)
|
||
|
||
## Workflow и точки входа
|
||
|
||
### Основной сценарий пользователя:
|
||
1. **Главная** (`/`) → `views.main_init()` — отслеживание кук посещений
|
||
2. **Автокомплит адреса** (`/autocomplete_addr`) → `autocomplete_addr.autocomplete_addr()` — подсказки при вводе
|
||
3. **Поиск по адресу** (`/get_address`) → `views.get_address()` — распознание серии здания
|
||
4. **Ценовая выдача** (`/{build_id}/{apart_id}/*`) → `prices.report_price()` — основной отчёт с фильтрацией и пагинацией по фреймам
|
||
|
||
### Каталоги и отчёты:
|
||
- `catalog.py` — каталог профилей, производителей, серий (с методом `catalog_seria_info()`)
|
||
- `report1.py` — сравнение наборов (`compare_offers()`) с расчётом рейтинговых компонент
|
||
- `report2.py` — рейтинги и ранжирование (фильтрация по звёздочкам и весам)
|
||
- `diagrams.py` — статистика и аналитика
|
||
|
||
### Система пользователей:
|
||
- `user_manager.py` — регистрация, логин/logout, восстановление пароля, верификация email
|
||
- Использует собственные таблицы `OurUser` + стандартный Django `User`
|
||
|
||
## Специфические технологии и паттерны
|
||
|
||
### Конфигурация через settings.py:
|
||
- **Двойной хост** (DEV и PROD) по `socket.gethostname()` — разные БД, media-пути, сценарии отладки
|
||
- Настройки ранжирования через веса (более 20 констант типа `RANK_STEP_*`, `RARING_*`)
|
||
- Google Captcha и Yandex Maps API ключи из `my_secret.py`
|
||
|
||
### Импорт конфиденциальных данных:
|
||
```python
|
||
from oknardia.my_secret import * # в settings.py и models.py
|
||
```
|
||
**⚠️ Важно**: `my_secret.py` содержит пароли БД, SECRET_KEY и должен быть в `.gitignore`
|
||
|
||
### Использование JSON в моделях:
|
||
- Поле `sProfileDescription` (Profiles), `sGlazingDescription`, `sSetDescription` — JSON или HTML в TextField
|
||
- Нет явной валидации структуры JSON при сохранении
|
||
|
||
### Система рейтинга и ранжирования:
|
||
- Каждый компонент (профиль, стеклопакет, набор) имеет рейтинг
|
||
- Веса рейтинга задают важность каждого атрибута (теплопередача, звукоизоляция и т.п.)
|
||
- `report1.show_rating_components()` раскрывает формулу расчёта рейтинга
|
||
|
||
### Интернационализация:
|
||
- `LANGUAGE_CODE = 'ru-RU'`, `TIME_ZONE = 'Europe/Moscow'`
|
||
- `USE_I18N = True`, `FIRST_DAY_OF_WEEK = 1` (понедельник)
|
||
- Все названия моделей и help_text на русском языке
|
||
|
||
## Конвенции кодирования
|
||
|
||
Из `.github/copilot-instructions.md`:
|
||
|
||
✅ **Обязательные правила:**
|
||
- **Язык**: отвечай на русском, комментарии кода на русском
|
||
- **Стиль**: PEP 8 для Python, используй современные возможности (Python 3.12+, Django 6.0+)
|
||
- **Управление зависимостями**: `poetry` (вместо pip/requirements.txt)
|
||
- **Переменные окружения**: секреты в `.env`, не в коде
|
||
- **Git коммиты**:
|
||
- `add: <описание>` — новая функция/файл
|
||
- `fix: <описание>` — баг
|
||
- `mod: <описание>` — переработка кода
|
||
- `minor: <описание>` — форматирование, опечатки, мелкие комменты
|
||
- **Удаление старого кода**: помечать меткой `# Удалить:`, не стирать просто
|
||
- **Тон**: неформальный, профессиональный, образность допускается (как с коллегой)
|
||
|
||
⚠️ **Исключения**:
|
||
- Не удаляй старый код без явного указания
|
||
- Всегда уточняй перед `git commit` / `git push`
|
||
- Если модель требует миграций, опиши шаги для `python manage.py makemigrations/migrate`
|
||
|
||
## Типичные рабочие циклы
|
||
|
||
### Добавление нового фильтра в ценовую выдачу:
|
||
1. Добавить поле в модель (например, `SetKit`) → создать миграцию
|
||
2. Обновить фильтрацию в `prices.report_price()` → использовать Q-объекты
|
||
3. Обновить template для выбора фильтра (`templates/price/*.html`)
|
||
4. Проверить влияние на рейтинг в `report1.py` если нужно
|
||
|
||
### Обновление рейтинга и ранжирования:
|
||
1. Модифицировать вес в settings.py (RANK_STEP_*, RARING_*)
|
||
2. Пересчитать рейтинг в моделях через функцию `save()` или создать management-command
|
||
3. Проверить результаты в `report2.ratings()` и `report2.profiles_rating()`
|
||
|
||
### Кеширование и производительность:
|
||
- Картинки схем кешируются автоматически; при добавлении новой схемы нужно явно вызвать функцию генерации
|
||
- Pre-render HTML нужно чистить при обновлении ценовых данных (см. управление файлами в `seria_info/prepared/`)
|
||
- БД индексирована на часто используемых полях (`db_index=True`)
|
||
|
||
### Разработка на macOS:
|
||
- При установке `mysqlclient` может потребоваться `brew install mariadb-connector-c`
|
||
- Подробнее см. README.md, раздел "Некоторые заметки относительно разработки"
|
||
|
||
## Структура папок
|
||
|
||
```
|
||
oknardia/
|
||
├── manage.py
|
||
├── oknardia/
|
||
│ ├── models.py # ВСЕ модели (1900+ строк)
|
||
│ ├── settings.py # конфиг, импорт my_secret.py
|
||
│ ├── urls.py # маршруты (113 строк)
|
||
│ ├── admin.py
|
||
│ ├── views.py # главная, контакты, тариф
|
||
│ └── my_secret.py # CONFIDENTIAL: пароли, ключи
|
||
├── web/
|
||
│ ├── views.py # основная логика
|
||
│ ├── add_func.py # утилиты (геокод, расстояния)
|
||
│ ├── prices.py # отчёты ценовой выдачи
|
||
│ ├── report1.py # сравнение наборов
|
||
│ ├── report2.py # рейтинги и ранжирование
|
||
│ ├── catalog.py # каталоги
|
||
│ ├── diagrams.py # статистика
|
||
│ ├── blog.py # список и посты блога
|
||
│ ├── autocomplete_addr.py # автокомплит адресов
|
||
│ ├── user_manager.py # логин, регистрация
|
||
│ └── service.py # служебные функции (sitemap, очистка)
|
||
├── templates/ # Django шаблоны (Jinja2-like)
|
||
│ ├── base.html
|
||
│ ├── index.html # главная
|
||
│ ├── seria_info/prepared/ # пре-рендер кеш
|
||
│ ├── price/
|
||
│ ├── catalog/
|
||
│ └── ...
|
||
└── public/
|
||
├── static/
|
||
│ ├── img/_flap.cfg/ # схемы окон (большие)
|
||
│ ├── img/_miniflap.cfg/ # схемы окон (мини)
|
||
│ ├── css/
|
||
│ ├── js/
|
||
│ └── ...
|
||
└── media/ # загружаемые файлы
|
||
```
|
||
|
||
## Отладка и команды
|
||
|
||
```bash
|
||
# Разработка
|
||
python manage.py runserver # локальный сервер
|
||
python manage.py makemigrations # подготовить миграцию
|
||
python manage.py migrate # применить миграцию
|
||
|
||
# Администрирование
|
||
python manage.py shell # интерпретатор с контекстом Django
|
||
python manage.py createsuperuser # создать админа
|
||
python manage.py collectstatic # собрать статику для продакшена
|
||
|
||
# Служебные (см. service.py)
|
||
# Находятся в urls.py: /service/make_sitemaps, /service/make_rating
|
||
```
|
||
|
||
## Типичные ошибки и подводные камни
|
||
|
||
1. **Забывчивость миграций**: при добавлении полей в модель сразу создавай миграцию
|
||
2. **Нарушение именования полей**: новые поля должны начинаться с префикса (s, i, f, b, d, k, p)
|
||
3. **Незакешированные картинки**: если добавляешь новую схему открывания, вызови функцию генерации явно
|
||
4. **Неочищенные pre-render шаблоны**: могут вызвать устаревание данных на страницах серий
|
||
5. **Foreign Key ON_DELETE**: используется в основном `DO_NOTHING` и `SET_NULL`, будь осторожен при удалении
|
||
6. **Двойной хост**: убедись, что используешь правильные переменные из `my_secret.py` для текущей машины
|
||
7. **Индексирование БД**: большинство полей для поиска уже имеют `db_index=True`, но проверь при добавлении фильтров
|
||
|
||
## Реферальные ссылки (для более глубокого изучения)
|
||
|
||
- **Django 6.0+ docs**: https://docs.djangoproject.com/en/stable/
|
||
- **MariaDB/MySQL**: Конфиг БД в settings.py, ENGINE = "django.db.backends.mysql"
|
||
- **Система рейтинга**: см. functions в report1.py и constants в settings.py (RANK_*, RARING_*)
|
||
- **Фронтенд**: Bootstrap 3.3.7 (в static/bootstrap-3.3.7-dist.zip), jQuery, Yandex Maps API
|
||
|
||
---
|
||
|
||
**Автор инструкций**: проанализировано 16.04.2026
|
||
**Версия документа**: 1.0
|
||
**Последнее обновление**: инструкции в `.github/copilot-instructions.md`
|
||
|