🧙 Садовник: уточнил шаги, добавил проверки и обоснования. Примите, если полезно.
#1Внутри app/ создай пять прикладных слоёв и общее ядро. Пока в них не будет прикладного кода.
Команда использует Python и одинаково работает в PowerShell, macOS и Linux при установленном uv.
- –Внутри app созданы ровно шесть целевых папок
- –Названия папок совпадают со схемой
- –В папках пока нет прикладного кода
Создай пустой __init__.py в самой папке app/ и во всех шести вложенных папках. Это делает их обычными Python-пакетами и обеспечивает предсказуемое обнаружение модулей инструментами сборки и анализа.
- –В каждой целевой папке есть __init__.py
- –Файл app/__init__.py тоже существует
- –Команда uv run python -c "import app" завершается без ошибки
Здесь находятся классы SQLAlchemy: описание таблиц, колонок, связей, индексов и ограничений.
Здесь не должно быть кодов HTTP-ответа, проверок прав, вызовов внешних сервисов и отправки писем.
- –Можешь объяснить, почему модель не должна знать про HTTP
- –Можешь отличить модель SQLAlchemy от схемы Pydantic
- –Проверил, что модели не импортируют routers и services
Здесь находятся классы Pydantic, описывающие контракты входных и выходных данных. Для создания и ответа используй отдельные схемы.
В CategoryCreate нет id и slug, потому что их назначает сервер. Здесь не должно быть запросов к базе и бизнес-правил.
- –Можешь объяснить, зачем нужны разные классы на вход и выход
- –Понимаешь, почему id и slug отсутствуют в схеме создания
- –Проверил, что схемы не обращаются к базе данных
Здесь находится всё, что напрямую обращается к базе: запросы, выборки, вставки, обновления и удаления.
Репозиторий возвращает None, если запись не найдена. Решать, является ли это ошибкой, должен сервис. Здесь не должно быть правил вроде «нельзя удалять категорию с товарами».
- –Можешь объяснить, почему репозиторий возвращает None
- –Проверил, что репозиторий не создаёт HTTPException
- –Проверил, что SQL не размещён в routers или services
Здесь находятся правила предметной области. Например: slug генерируется из названия, категорию с потомками нельзя удалить, а имя должно быть уникально внутри родителя.
Сервис вызывает репозиторий и выбрасывает собственные исключения, а не HTTPException. Здесь не должно быть кодов ответа, объекта HTTP-запроса и прямых SQL-запросов.
- –Можешь назвать три правила, относящиеся к сервису
- –Понимаешь, почему сервис не выбрасывает HTTPException
- –Проверил, что сервис обращается к базе только через repository
Здесь находятся маршруты, HTTP-коды и модели ответа. Роутер должен быть тонким: принять данные, вызвать сервис и вернуть результат.
Условие в роутере — повод проверить, не является ли оно бизнес-правилом. Здесь не должно быть SQL, предметных правил и локальных try/except, если ошибки уже преобразуются централизованными обработчиками.
- –Можешь объяснить, почему if в роутере требует проверки
- –Проверил, что роутер не обращается к базе напрямую
- –Проверил, что роутер вызывает сервис, а не repository
Здесь находятся действительно общие механизмы: настройки, базовые исключения и их обработчики, общие зависимости, безопасность и логирование.
В будущем структура может выглядеть так:
Не создавай эти подпапки заранее без необходимости. Если содержимое core нужно только одному слою, перенеси его в этот слой.
- –Можешь назвать критерий попадания кода в core
- –Проверил, что core не импортирует routers или services
- –Не создавал вложенные папки без реальной необходимости
Разреши зависимостям идти только от внешних деталей к внутренним: routers → services → repository → models. Схемы используются на границе данных, а core предоставляет общие механизмы и не должен зависеть от прикладных слоёв.
Обратный путь результата не означает обратного импорта: repository возвращает данные сервису, а сервис — роутеру, но нижние слои по-прежнему ничего не знают о верхних.
- –models не импортирует repository, services или routers
- –repository не импортирует services или routers
- –services не импортирует routers
- –core не импортирует прикладные слои
Без подглядывания нарисуй цепочку для запроса «создать категорию»: какие слои вызываются, какие данные передаются вперёд и что возвращается обратно. Отдельно отметь направление импортов, чтобы не смешивать его с обратным движением результата.
- –Цепочка запроса нарисована по памяти
- –Вызовы идут от routers к services и repository
- –Направление импортов не нарушает правило зависимостей
- –Результат возвращается обратно без обратных импортов
Добавь раздел «Структура проекта» и опиши каждую папку одной строкой своими словами. Отдельно запиши правило допустимого направления зависимостей.
- –В README есть раздел «Структура проекта»
- –Все шесть папок описаны одной строкой
- –Указана цепочка routers → services → repository → models
- –Формулировки не скопированы дословно