---
name: laravel-backend-patterns
description: Backend-конвенции Лидерры (Laravel 13) — как писать controller→service→job, RLS-aware Eloquent, деньги через bcmath/LedgerService, идемпотентные джобы, partition-aware запросы. Используй при «как писать backend в Лидерре», «паттерн контроллера/сервиса/джоба», scaffolding новой backend-фичи. НЕ для generic-паттернов (architecture-patterns #38), аудита денег (billing-audit #62), РСБУ/налогов (ru-tax-accounting), security-аудита (D3).
---

# Laravel Backend Patterns — конвенции backend-кода Лидерры

Проектный скил, который описывает **как здесь пишут backend**, а не как рекомендует generic-Laravel.
При scaffolding новой фичи или ревью кода — сверяться с пятью конвенциями ниже.
Детальные примеры с образцами кода и антипаттернами — в `references/conventions.md`.

## 1. Слоистость: Controller → FormRequest → Service → Job

Контроллер тонкий: принимает FormRequest, делегирует Service, возвращает JSON-ответ.
Бизнес-логика — в Service; асинхронная работа — в Job.
Слои зафиксированы в `app/deptrac.yaml` (13 слоёв, pre-commit gate job 10).

Подробнее: `references/conventions.md` §1.

## 2. RLS-aware Eloquent и middleware `tenant`

Middleware `SetTenantContext` оборачивает HTTP-запрос в транзакцию и выполняет
`SET LOCAL app.current_tenant_id = X`, обеспечивая RLS-изоляцию между tenant'ами.
**КРИТИЧНО**: очередные джобы выполняются под ролью `crm_supplier_worker` (BYPASSRLS),
поэтому RLS не фильтрует. Каждый запрос в джобе **обязан** содержать явный
`where('tenant_id', $tenantId)` или устанавливать `SET LOCAL` вручную внутри транзакции.

Подробнее: `references/conventions.md` §2.

## 3. Деньги — только через bcmath и LedgerService

Все денежные операции — `bcadd` / `bcsub` / `bcmul` / `bcdiv` / `bccomp` со строковыми операндами
и фиксированным `scale`. Никаких операторов `+` / `-` / `*` / `/` над деньгами, никакого `float`.
Точка входа для биллингового списания — `LedgerService::chargeForDelivery()`.
Аудит денежных инвариантов кода — скил `billing-audit` (#62); здесь — только конвенция написания.

Подробнее: `references/conventions.md` §3.

## 4. Идемпотентные джобы через advisory lock

Повторный запуск джоба не должен дублировать результат.
Паттерн: `pg_advisory_xact_lock(composite_bigint)` внутри транзакции — сериализует
конкурентные обработки одного (tenant_id, source_crm_id). Дополнительно: `lockForUpdate`
на строку Tenant защищает баланс от TOCTOU при конкурентных списаниях.

Подробнее: `references/conventions.md` §4.

## 5. Partition-aware запросы для `deals` и `supplier_lead_costs`

Таблицы `deals` и `supplier_lead_costs` секционированы по `RANGE (received_at)`.
Запросы к этим таблицам должны включать условие по `received_at` (или `created_at`
для `supplier_lead_costs`) — это включает pruning и предотвращает full-scan всех партиций.

Подробнее: `references/conventions.md` §5.

## Связано

- `billing-audit` #62 — аудит денежной корректности (I1–I5 инварианты).
- `architecture-patterns` #38 — общие паттерны архитектуры (не Лидерра-специфика).
- Boost #10 — Eloquent introspection, документация Laravel 13.
- Larastan #12 — статанализ PHP (ловит float-арифметику на деньгах).
- ADR-005 — deptrac architecture-fitness gate.
