Тема
Чеклисты
Копируемые списки для типовых операций. Проходить сверху вниз — не полагаться на память.
Новый проект
- [ ]
laravel new(L12 стабильный или L13 для нового) → см. структура L12/13 - [ ] Свой starter применён (или собран): Breeze + Filament + Spatie-набор
- [ ]
docker-composeстудии: app/nginx/postgres(mysql)/redis/queue/scheduler - [ ]
.envзаполнен,.env.exampleв git, секреты не в git - [ ]
phpunit.xml:DB_DATABASE={project}_test— защита рабочей БД - [ ] Тестовая БД создана + extensions (PostGIS и т.п.)
- [ ] Pint + Larastan (level 6+) + Pest настроены
- [ ]
.claudeignore(vendor, node_modules, storage/logs) - [ ]
.mcp.jsonсгенерирован (setup.ps1), boost установлен, проект активирован в~/.claude.json - [ ] trustProxies +
URL::forceSchemeпод Caddy (если публичный) - [ ] Кастомные stubs под
declare(strict_types=1)+$casts
Новая модель
- [ ]
make:model X -mf(+--requestsесли есть форма) - [ ] Миграция: FK
constrained()+index(), JSONnullable(), enum-столбцы,down() - [ ]
declare(strict_types=1) - [ ]
$fillable(whitelist) — не$guarded = []при пользовательском вводе - [ ]
$castsна КАЖДЫЙ json/date/bool/enum/decimal столбец - [ ] Обе стороны связей (
hasMany↔belongsTo) - [ ] Scope для WHERE, используемых 2+ раз
- [ ] Фабрика заполнена
- [ ] Нет
$withв модели, нет бизнес-логики в модели - [ ] Индексы на WHERE/ORDER BY столбцы
Новый роут / контроллер
- [ ] Роут именован через
->name() - [ ] Route model binding: slug (публичные) / id (admin)
- [ ] Контроллер тонкий (≤10 строк логики) — остальное в Service
- [ ] Валидация в FormRequest, не в контроллере
- [ ]
->with()явно (нет N+1) - [ ] Ссылки в коде —
route('name'), не хардкод URL - [ ] Feature-тест: GET 200, несуществующий slug 404, наличие h1/title
- [ ] Если форма: POST валидные → success, невалидные → 422/errors
- [ ] Если менялся URL: 301 redirect со старого + тест на него
Новый Filament-ресурс
- [ ]
make:filament-resource X --generate - [ ] Русские
$modelLabel/$pluralModelLabel/ лейблы полей - [ ] Navigation group на русском +
$navigationSort - [ ] Поля сгруппированы в
Section(доп. —collapsible()) - [ ] Slug:
unique(ignoreRecord: true) - [ ] FK:
Select::relationship(); медиа:SpatieMediaLibraryFileUpload; bool:Toggle - [ ] Таблица:
searchable/sortableгде нужно, FK какrelation.name, датаd.m.Y H:i - [ ]
afterSave()→Cache::tags([...])->flush()(гранулярно, не весь кеш) - [ ] Бизнес-логика — в Service, не в Resource
Новая форма (публичная)
- [ ] FormRequest с правилами (
max:255на строки,email:rfc,dns,existsдля FK) - [ ]
authorize()осознанно,messages()на русском - [ ] spatie/laravel-honeypot против спама
- [ ]
throttleна POST-endpoint - [ ]
для вывода (не{!! !!}с пользовательским вводом) - [ ] Уведомление о заявке (mail/Telegram) через Job (не синхронно)
- [ ] Тест валидации + сохранения
Новая миграция большой таблицы (>1M строк)
- [ ]
CREATE INDEX CONCURRENTLY+$withinTransaction = false - [ ] Functional index для
lower()при ILIKE с кириллицей - [ ] GIN на tsvector для полнотекста (STORED generated column)
- [ ] После массового импорта —
ANALYZE table - [ ]
down()сDROP INDEX CONCURRENTLY
Перед коммитом (стандарт студии)
- [ ] Нет
dd(),dump(),console.log, закомментированного кода - [ ] Строки UI через
__(), числа/статусы в config/Enum/Constants - [ ] Новый роут →
->name()+ тест; новая модель →$casts+ relations + factory - [ ] Новая миграция →
down(), FKconstrained()+index() - [ ] Новая форма → FormRequest; изменён URL → 301 redirect
- [ ] Filament →
afterSave+Cache::tags()->flush() - [ ] Pint + тесты зелёные (проверено, а не «должно»), нет секретов в diff
Безопасность (быстрая проверка периметра)
- [ ] SQL — только Eloquent/bindings, нет
DB::raw()с конкатенацией - [ ] XSS —
,{!! !!}только для доверенного HTML из админки - [ ] CSRF — на всех POST-формах (Laravel по умолчанию, не отключать)
- [ ] Права — Policy/Gate на защищённые действия
- [ ] Секреты —
.env→config(), никогдаenv()в коде - [ ] ID в публичных URL — UUID/хеш/slug, не автоинкремент
- [ ] Rate limiting на API POST/PUT/DELETE