# Laravel/PHP-стек и инфраструктура для multi-tenant API-first SaaS лояльности (состояние на сентябрь 2026)

> Метод: официальная документация Laravel 13.x, php.net, PostgreSQL; метаданные Packagist и GitHub API, снятые 25.09.2026 (версии, даты релизов, требования к PHP/Laravel, звёзды, загрузки в месяц); официальные страницы облачных и платёжных провайдеров; независимые бенчмарки. Лимит веб-поиска сессии исчерпался в ходе работы, поэтому часть вопросов (российские high-load кейсы на Laravel, цены части провайдеров) закрыта не полностью. Это отмечено в разделах Gaps.

## 1. Состояние Laravel и PHP на сентябрь 2026; какую версию PHP брать

### Takeaway
Текущая ветка — Laravel 13: релиз 17.03.2026, последняя версия 13.33.0 от 22.09.2026, требует PHP ≥ 8.3. Bug fixes выходят до Q3 2027, security-фиксы до 17.03.2028. Новый проект стоит начинать на PHP 8.5 (как минимум 8.4). Часть ключевых пакетов уже требует PHP ≥ 8.4: Pest 5, spatie/laravel-activitylog 5, spatie/laravel-model-states 2.14, spatie/laravel-prometheus 1.7. PHP 8.3 с 01.01.2026 получает только security-фиксы. Локальный Laragon на Windows с PHP 8.3 не подходит как среда исполнения для Horizon и Octane.

### Cited Findings
- Laravel 13 вышел 17.03.2026. Минимальный PHP — 8.3, поддерживаются 8.3–8.5. Bug fixes до Q3 2027, security fixes до 17.03.2028 — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)
- Политика поддержки одна для всех мажорных версий: 18 месяцев bug fixes и 2 года security fixes. Мажорные релизы выходят раз в год (~Q1), minor/patch — вплоть до еженедельных и без breaking changes — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)
- Laravel 12 (24.02.2025, PHP 8.2–8.5): bug fixes закончились 13.08.2026, security до 24.02.2027. Laravel 11: security закончился 12.03.2026 — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)
- Последний тег laravel/framework — v13.33.0 от 22.09.2026 (`php: ^8.3`, `symfony/http-kernel: ^7.4 || ^8.0`); ~15,2 млн загрузок в месяц, 34,9k звёзд — [Packagist: laravel/framework](https://packagist.org/packages/laravel/framework)
- Что нового в Laravel 13: first-party Laravel AI SDK; first-party JSON:API resources (sparse fieldsets, include связей, links, заголовки); middleware `PreventRequestForgery` с origin-aware проверкой; `Queue::route(...)` для централизованной маршрутизации jobs; атрибуты `#[Middleware]`, `#[Authorize]`, `#[Tries]`, `#[Backoff]`, `#[Timeout]`, `#[FailOnTimeout]`; `Cache::touch()`; семантический и векторный поиск на PostgreSQL + pgvector (`whereVectorSimilarTo`). Основной фокус цикла — минимум breaking changes — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases); [Laravel News](https://laravel-news.com/laravel-13-released)
- Поддержка PHP: 8.2 — только security до 31.12.2026. 8.3 (23.11.2023) — active support до 31.12.2025, security до 31.12.2027. 8.4 (21.11.2024) — active до 31.12.2026, security до 31.12.2028. 8.5 (20.11.2025) — active до 31.12.2027, security до 31.12.2029 — [php.net: Supported Versions](https://www.php.net/supported-versions.php)
- PHP 8.4: property hooks, asymmetric visibility, `#[\Deprecated]`, lazy objects, объектный API `BcMath\Number` с перегрузкой операторов (произвольная точность), `array_find/array_any/array_all`, драйвер-специфичные подклассы PDO (`Pdo\Pgsql`), новый JIT на базе IR, enum `RoundingMode` — [PHP 8.4 Release](https://www.php.net/releases/8.4/en.php)
- PHP 8.5: расширение URI (RFC 3986/WHATWG), pipe-оператор `|>`, clone with, `#[\NoDiscard]`, closures и first-class callables в константных выражениях, persistent cURL share handles (`curl_share_init_persistent()`), `array_first()`/`array_last()`, backtrace для фатальных ошибок, ключ `partitioned` в `setcookie()`. Среди deprecations — backtick-оператор, неканонические касты, soft-deprecate `__sleep/__wakeup` — [PHP 8.5 Release](https://www.php.net/releases/8.5/en.php)
- Производительность PHP 8.5. По Phoronix Test Suite 8.5 примерно на 14% быстрее 8.1 — [GameGPU со ссылкой на Phoronix](https://en.gamegpu.com/news/zhelezo/php-8-5-bystree-php-8-1-na-14-chem-hp-8-4-16-uzhe-dostupen). В CPU-синтетике (fibonacci, 4 vCPU, OPcache on, JIT off; это не Laravel) PHP 8.5.2 выдал 1,78 req/s против 1,63 у 8.3.30 (≈+9%) и 1,53 у 8.4.17 — [PHPBenchLab](https://phpbenchlab.com/php-8-3-vs-8-4-vs-8-5-real-world-performance-benchmark-2026/)
- Пакеты, которые уже требуют PHP ≥ 8.4:
  - pestphp/pest v5 (5.0.0 от 24.07.2026, текущий 5.2.1) — [Packagist](https://packagist.org/packages/pestphp/pest)
  - pestphp/pest-plugin-arch v5 — [Packagist](https://packagist.org/packages/pestphp/pest-plugin-arch)
  - spatie/laravel-activitylog 5.x (5.0.0 от 25.03.2026) — [Packagist](https://packagist.org/packages/spatie/laravel-activitylog)
  - spatie/laravel-model-states 2.14.2 — [Packagist](https://packagist.org/packages/spatie/laravel-model-states)
  - spatie/laravel-prometheus 1.7.0 — [Packagist](https://packagist.org/packages/spatie/laravel-prometheus)

  Pest v4 (20.08.2025) работает на PHP ^8.3 — [Packagist](https://packagist.org/packages/pestphp/pest)
- Ограничения Windows:
  - PCNTL «will not function on non-Unix platforms (Windows)» — [PHP Manual: PCNTL](https://www.php.net/manual/en/pcntl.installation.php)
  - laravel/horizon требует `ext-pcntl` и `ext-posix` — [Packagist: laravel/horizon](https://packagist.org/packages/laravel/horizon)
  - Официальные Docker-образы FrankenPHP позволяют запускать его на платформах без нативной поддержки, «such as Windows» — [Laravel Octane docs](https://laravel.com/docs/13.x/octane)

### Inferences
- Рекомендация для нового проекта — Laravel 13 + PHP 8.5, запасной вариант PHP 8.4. PHP 8.3 из текущего Laragon (8.3.30) не даёт поставить Pest 5, activitylog 5 и model-states 2.14.x, и у него уже только security-поддержка.
- Laragon на Windows оставить как IDE-окружение. Код с Octane (FrankenPHP/Swoole), Horizon и всё, что требует pcntl, запускать в Docker/WSL2 на тех же образах, что и в prod (Docker Compose локально).
- Laravel 14 по политике ожидается в ~Q1 2027. Судя по заявленному фокусу на минимуме breaking changes, апгрейд можно планировать как рутину.
- `BcMath\Number` (8.4) можно использовать как нативную альтернативу decimal-библиотекам. Persistent cURL share handles (8.5) полезны для исходящих вызовов (webhooks, платёжные API) в long-running воркерах.

### Gaps
- Не найдено надёжных Laravel-специфичных бенчмарков PHP 8.5 против 8.4. Доступные данные — синтетика или вторичные пересказы.
- Поддержка Swoole на Windows не проверена по первоисточнику.

## 2. Производительность: Octane (FrankenPHP / RoadRunner / Swoole), сравнение с Go/Node/Java, реальные кейсы

### Takeaway
По двум независимым замерам 2026 года на 4 vCPU и эндпоинтах с 3–5 запросами к БД Octane даёт в 2,5–5 раз больше пропускной способности и в 3–5 раз меньшую латентность, чем PHP-FPM: ~2–3 тыс. RPS и p95 ~40–90 мс против ~0,3–0,85 тыс. RPS. Цена — строгая дисциплина с состоянием: singletons, static, открытые транзакции, рецикл воркеров. Потолок на ядро у PHP/Laravel на порядок ниже Go/Java/.NET: в TechEmpower R23 Fortunes у Laravel ~16,8 тыс. RPS, у Go Fiber ~338 тыс. Тем не менее Laravel-SaaS выдерживают сотни миллионов API-запросов в неделю, и узким местом обычно становится БД, а не PHP.

### Cited Findings
**Octane (официальная документация и пакеты)**
- Octane загружает приложение один раз и держит его в памяти. Поддерживаются FrankenPHP, Open Swoole, Swoole и RoadRunner — [Octane docs](https://laravel.com/docs/13.x/octane)
- Поведение по умолчанию: один воркер на ядро CPU; воркер перезапускается после 500 запросов (`--max-requests`); `max_execution_time` 30 с; после деплоя выполняется `octane:reload` — [Octane docs](https://laravel.com/docs/13.x/octane)
- Подводные камни. `register`/`boot` провайдеров выполняются один раз на воркер. Нельзя инжектить контейнер, request или config repository в конструкторы singletons (объект получит устаревший request/config). Накопление данных в static-массивах — утечка памяти — [Octane docs](https://laravel.com/docs/13.x/octane)
- Только в Swoole: concurrent tasks (не больше 1024 задач), ticks/intervals, Octane cache («up to 2 million operations per second»), Swoole tables — [Octane docs](https://laravel.com/docs/13.x/octane)
- laravel/octane v2.20.0 (23.08.2026), совместим с Laravel 10–13; ~2,4 млн загрузок в месяц — [Packagist](https://packagist.org/packages/laravel/octane)
- FrankenPHP — сервер на Go (на базе Caddy). Octane скачивает его бинарник автоматически. Официальные Docker-образы рекомендуются, в том числе ради дополнительных расширений — [Octane docs](https://laravel.com/docs/13.x/octane). Репозиторий сейчас находится в GitHub-организации `php` (github.com/php/frankenphp, ~11,4k звёзд, последний push 24.09.2026) — [GitHub: php/frankenphp](https://github.com/php/frankenphp)
- В worker mode FrankenPHP между запросами сохраняются static-переменные, static-свойства классов, глобальные переменные и in-memory кеши. Есть `MAX_REQUESTS` и `max_consecutive_failures` — [FrankenPHP worker docs](https://frankenphp.dev/docs/worker/)
- Альтернативный мост RoadRunner: spiral/roadrunner-laravel 6.6.0 (19.08.2026) — [Packagist](https://packagist.org/packages/spiral/roadrunner-laravel)

**Замеры throughput/latency**
- Deploynix, 05.04.2026. Hetzner CX32 (4 vCPU / 8 GB), PHP 8.4, MySQL 8.4, Valkey 8, wrk (100 соединений, 30 с). Приложение: auth, 3–5 Eloquent-запросов, cache, Blade.

  | Сервер | RPS | p50 / p95 / p99, мс | Память на воркер |
  |---|---|---|---|
  | PHP-FPM (10 воркеров) | 850 | 45 / 120 / 250 | 30–50 MB |
  | FrankenPHP (4 воркера) | 2 100 | 18 / 48 / 95 | 55–100 MB (все Octane) |
  | RoadRunner (4 воркера) | 2 350 | 16 / 42 / 88 | 55–100 MB (все Octane) |
  | Swoole (4 воркера) | 2 600 | 14 / 38 / 78 | 55–100 MB (все Octane) |

  По оценке автора, при нагрузке меньше ~500 запросов в минуту разница незаметна — [DEV / Deploynix](https://dev.to/deploynix/php-fpm-vs-laravel-octane-on-deploynix-real-world-performance-comparison-53gp)
- EdgeServers, 13.05.2026. 4 vCPU / 8 GB, Laravel 11, PHP 8.3 + OPcache.

  | Сервер | RPS | median, мс | p95, мс |
  |---|---|---|---|
  | FPM | 280–420 | 65–95 | 180–280 |
  | RoadRunner | 1 400–2 100 | 12–22 | 45–90 |
  | Swoole | 1 800–3 200 | 8–15 | 30–65 |
  | FrankenPHP | 1 600–2 800 | 10–18 | 35–70 |

  Стоимость бутстрапа в FPM — 15–30 мс на запрос. Память RoadRunner растёт на 30–60 MB за 100k запросов. Стартовые значения `max_requests`: 500 для RoadRunner и 250 для Swoole — [EdgeServers](https://www.edgeservers.com.au/en/articles/laravel-octane-roadrunner-swoole)
- Проблемы из продакшена по тому же источнику:
  - singleton создаётся на воркер, а не на запрос, и данные протекают между запросами;
  - незакрытый `DB::beginTransaction()` после падения запроса «достаётся» следующему запросу;
  - RoadRunner может молча ронять воркеры.

  [EdgeServers](https://www.edgeservers.com.au/en/articles/laravel-octane-roadrunner-swoole)
- Есть открытый CI-бенчмарк Swoole/OpenSwoole/RoadRunner/FrankenPHP/FPM (p50–p99, RPS, RSS, CPU, разные уровни конкуренции), который пересобирается при обновлениях Laravel. Числа в текстовом виде извлечь не удалось — [terrylinooo/laravel-octane-benchmark](https://terrylinooo.github.io/laravel-octane-benchmark/)

**Сравнение с другими стеками**
- TechEmpower Round 23 (24.02.2025), тест Fortunes (ORM, БД, шаблоны), RPS: ASP.NET 609 966; Go Fiber 338 096; Rust Actix 320 144; Java Spring 243 639; Node Express 78 136; Rails 42 546; Django 32 651; Laravel 16 800. Это вторичная сводка: для части фреймворков автор оговаривает поправки («logical deduction») — [DEV: сводка R23](https://dev.to/tuananhpham/popular-backend-frameworks-performance-benchmark-1bkh); первоисточник — [TechEmpower](https://www.techempower.com/benchmarks/)
- TechEmpower объявил о прекращении Framework Benchmarks (issue #10932, обсуждение на HN около марта 2026). Комментаторы указывают на «подгонку» реализаций под бенчмарк и слабую связь с реальными нагрузками — [Hacker News](https://news.ycombinator.com/item?id=47497763)

**Реальные кейсы**
- Sportmonks (Нидерланды, B2B API спортивных данных, на Laravel с основания):
  - 600 млн API-запросов в неделю;
  - пик 24 000 запросов к БД в секунду (PlanetScale, 450 GB) и 4 млн прочитанных строк в секунду;
  - больше 1 000 jobs в секунду, 3 млрд cache-событий (ElastiCache);
  - раньше Horizon со 150–200 именованными очередями, сейчас Laravel Private Cloud с managed queues;
  - дорогие offset-запросы заменили cursor-пагинацией.

  [Laravel Customer Story](https://laravel.com/cloud/customer-stories/how-sportmonks-handles-600m-api-requests-a-week-on-laravel-cloud)
- SaaS SMS-рассылок на Laravel + Horizon + Redis + MySQL без K8s и микросервисов:
  - пик 30 000 запросов в минуту;
  - больше 100 млн jobs за 12 часов, больше 1 млрд записей;
  - уроки: индексы в MySQL, импорт чанками по 10 000, передача в jobs ID, а не моделей.

  [Mateus Guimarães](https://mateusguimaraes.com/posts/scaling-laravel)
- Fathom Analytics (2022):
  - Laravel Vapor на AWS Lambda, burst 60 000 RPS;
  - «your database is going to be the bottleneck»: база мигрировала до SingleStore;
  - Octane с постоянными соединениями снизил нагрузку на CPU базы;
  - EU-прокси написан на Go.

  [Fathom](https://usefathom.com/blog/does-laravel-scale)
- Русскоязычный материал: статья OTUS на Хабре о production-архитектуре Traefik + FrankenPHP + Docker Compose. Это руководство, а не кейс нагрузки — [Хабр](https://habr.com/ru/companies/otus/articles/1001078/)

### Inferences
- Для checkout API с целевым p95 в десятки миллисекунд Octane практически обязателен. Разумный дефолт — FrankenPHP: официальная интеграция и Docker-образы, один бинарник с HTTP-сервером, активный репозиторий. RoadRunner — равноценная альтернатива. Swoole имеет смысл, только если нужны его фичи (tasks, tables, Octane cache).
- Грубая оценка ёмкости: 2–3 тыс. RPS на узел 4 vCPU для умеренно сложных эндпоинтов. Значит, 10 тыс. RPS на checkout — это порядка 4–6 таких узлов плюс ресурсы БД и PgBouncer. Судя по кейсам Fathom и Sportmonks, упираться будет в первую очередь БД.
- Для multi-tenant под Octane критично сбрасывать tenant context на каждом запросе. Tenant, сохранённый в singleton или static, — прямой путь к утечке данных между арендаторами.
- Обязательные guardrails:
  - scoped bindings вместо singletons для request-зависимых сервисов;
  - middleware, откатывающий незакрытые транзакции;
  - `max-requests`;
  - мониторинг RSS воркеров;
  - нагрузочные тесты до прода.
- Symfony работает на тех же рантаймах (FrankenPHP/RoadRunner) и, вероятно, находится в том же классе производительности. Прямых данных нет, см. Gaps.

### Gaps
- Не найдены проверяемые кейсы российских компаний с high-load Laravel: веб-поиск исчерпан, найденные материалы на Хабре — туториалы.
- Цифры Symfony в TechEmpower R23 не получены. Данные R23 взяты из вторичной сводки с оговорками автора.

## 3. Multi-tenancy: stancl/tenancy vs spatie, single DB vs multi-DB, PostgreSQL RLS, тестирование изоляции

### Takeaway
Для SaaS лояльности с тысячами мелких мерчантов и горячим транзакционным API прагматичный дефолт такой:
- одна БД PostgreSQL и `tenant_id` во всех таблицах;
- скоупинг на уровне приложения (global scopes или репозитории);
- PostgreSQL RLS как вторая линия обороны.

Отдельные БД стоит выделять только крупным enterprise-арендаторам. stancl/tenancy v3 стабилен (v3.10.1, есть Laravel 13). v4 с RLS пока не выпущен тегом: документация помечена как WIP, часть функций распространяется через спонсорский портал. spatie/laravel-multitenancy v4 намеренно минималистичен и запросы сам не скоупит.

### Cited Findings
- stancl/tenancy: последний тег v3.10.1 (05.08.2026), `illuminate/support ^10–^13`; 4,4k звёзд, ~886k загрузок в месяц — [Packagist: stancl/tenancy](https://packagist.org/packages/stancl/tenancy)
- В GitHub-релизах последние версии v3.10.1 и v3.10.0 (18.03.2026), тегов v4 нет. Среди веток есть `configurable-force-rls-2`. README ссылается на документацию v4.tenancyforlaravel.com — [GitHub Releases](https://github.com/archtechx/tenancy/releases); [GitHub: archtechx/tenancy](https://github.com/archtechx/tenancy)
- Документация v4 помечена «WIP». Заявленные функции:
  - PostgreSQL RLS для single-database как «best of both worlds»;
  - переработка resource syncing;
  - параллельные миграции (пример: 5 минут → ~20 секунд);
  - SQL Server;
  - `tenant:tinker`, early identification;
  - bootstrappers для Scout, mail и логов.

  Премиальные функции доступны через спонсорский портал — [Tenancy v4 docs](https://v4.tenancyforlaravel.com/version-4/)
- spatie/laravel-multitenancy 4.2.1 (22.09.2026): Laravel 11–13, PHP ^8.2, 1,4k звёзд — [Packagist](https://packagist.org/packages/spatie/laravel-multitenancy). Философия — «only provide the bare essentials». Поддерживает single и multi DB, tenant finder, задачи переключения (БД, префикс кеша), tenant-aware очереди. Автоматического скоупинга запросов в single-DB режиме нет — [Spatie docs](https://spatie.be/docs/laravel-multitenancy/v4/introduction)
- В Filament tenancy автоматически скоупятся только resources. Не скоупятся модели без resource, запросы до идентификации tenant и запросы с `withoutGlobalScopes`. Для `unique`/`exists` нужны `scopedUnique()`/`scopedExists()`. Предупреждения документации: «If implemented partially or incorrectly, data belonging to one tenant may be exposed to another tenant» и «Filament does not provide any guarantees about the security of your application» — [Filament 5.x Tenancy](https://filamentphp.com/docs/5.x/users/tenancy)
- Global scopes снимаются через `withoutGlobalScope(s)` и `withoutGlobalScopesExcept` — это легальный путь обхода изоляции — [Eloquent docs](https://laravel.com/docs/13.x/eloquent)
- Поведение PostgreSQL RLS:
  - «Superusers and roles with the BYPASSRLS attribute always bypass the row security system»;
  - владелец таблицы обходит RLS, если не включён `FORCE ROW LEVEL SECURITY`;
  - при включённом RLS и отсутствии политик действует default-deny;
  - проверки unique, PK и FK всегда обходят RLS, отсюда риск «covert channel».

  [PostgreSQL docs: Row Security Policies](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
- RLS в Laravel: `app.current_tenant_id` выставляется middleware в начале запроса, политика сравнивает `tenant_id` с `current_setting(...)`. Защищает даже от «сырых» `DB::select` — [DEV](https://dev.to/iprajapatiparesh/stop-leaking-tenant-data-postgresql-row-level-security-in-laravel-2pkl). Готовых Laravel-библиотек под этот подход мало — [Laracasts](https://laracasts.com/discuss/channels/eloquent/taking-advantage-of-postgresql-row-level-security)
- В Laravel 13.x документирована работа с pooled PostgreSQL (PgBouncer в transaction mode). Для pooled-соединения включаются emulated prepares, а миграции и `db:*` идут через отдельное `direct`-соединение — [Laravel DB docs](https://laravel.com/docs/13.x/database)
- Связка Filament 5 + stancl: tomatophp/filament-tenancy v5.0.0 поддерживает Filament 5 / Livewire 4, Laravel 12–13 и stancl/tenancy 3.9+ — [GitHub Release](https://github.com/tomatophp/filament-tenancy/releases/tag/v5.0.0)

### Inferences
- RLS вместе с PgBouncer в transaction mode требует задавать контекст через `SET LOCAL` или `set_config('app.tenant_id', ..., true)` внутри транзакции запроса или job. Session-level `SET` в transaction pooling «протечёт» к другому клиенту. Роль приложения должна быть без BYPASSRLS и не владельцем таблиц (миграции — под отдельной owner-ролью), плюс `FORCE ROW LEVEL SECURITY`.
- Каждая queued job должна явно нести `tenant_id` и восстанавливать контекст в job middleware. Под Octane tenant context сбрасывается на каждом запросе.
- Все unique-индексы должны начинаться с `tenant_id` — это закрывает covert channel через constraint violations и соответствует бизнес-смыслу.
- Тестирование изоляции:
  - Pest dataset «два арендатора», который прогоняет каждый эндпоинт с чужими ID и ждёт 404/403;
  - arch-тест, запрещающий `withoutGlobalScope(s)` вне allowlist;
  - DB-тест: роль приложения без выставленного tenant видит 0 строк (default-deny);
  - периодический аудит запросов без `tenant_id` по логам.
- Отдельная БД на tenant при тысячах арендаторов усложняет миграции, пулы соединений и кросс-тенантную аналитику. Гибрид «shared DB по умолчанию + выделенная БД или кластер для enterprise» решается на уровне роутинга соединений.
- Выбор пакета:
  - stancl/tenancy v3 оправдан, если нужны готовые bootstrappers (cache, filesystem, queue, Redis);
  - для single-DB + RLS достаточно тонкого собственного слоя или spatie/laravel-multitenancy и своих scopes;
  - на stancl v4 разумно переходить только после стабильного тега.

### Gaps
- Не выяснены дата релиза stancl/tenancy v4 и то, входит ли RLS в бесплатную часть.
- Не найдены опубликованные production-отчёты «Laravel + PostgreSQL RLS» на высокой нагрузке.

## 4. Доменные пакеты и паттерны: деньги и баллы, event sourcing, state machines, идемпотентность, outbox, webhooks, аудит, feature flags, DTO

### Takeaway
Все профильные пакеты живы и совместимы с Laravel 13 на сентябрь 2026. Рекомендуемый набор:
- **баллы:** целые числа (bigint) в append-only ledger;
- **денежные суммы:** brick/money (пока 0.x) или moneyphp/money 4.x;
- **статусы:** spatie/laravel-model-states (требует PHP 8.4+);
- **идемпотентность:** Idempotency-Key по семантике IETF-драфта с хранением в БД;
- **интеграционные события:** транзакционный outbox;
- **webhooks:** spatie webhook-server и webhook-client;
- **аудит:** owen-it/laravel-auditing или spatie/laravel-activitylog v5;
- **feature flags и DTO:** Pennant и spatie/laravel-data.

Полноценный event-sourcing фреймворк нужен точечно. Verbs всё ещё 0.x.

### Cited Findings
Сводка по пакетам (Packagist на 25.09.2026):

| Пакет | Версия (дата) | Совместимость | Популярность | Источник |
|---|---|---|---|---|
| brick/money | 0.15.1 (14.09.2026) | PHP ^8.2 | 1,9k★, ~1,7 млн/мес | [Packagist](https://packagist.org/packages/brick/money) |
| brick/math | 1.0.0 (12.09.2026), первый 1.0 | PHP ^8.2 | ~19 млн/мес | [Packagist](https://packagist.org/packages/brick/math) |
| moneyphp/money | v4.9.0 (04.05.2026) | PHP 8.1–8.5 | 4,9k★, ~4,2 млн/мес | [Packagist](https://packagist.org/packages/moneyphp/money) |
| spatie/laravel-event-sourcing | 7.15.1 (10.08.2026) | Laravel 10–13 | 916★, ~250k/мес | [Packagist](https://packagist.org/packages/spatie/laravel-event-sourcing) |
| eventsauce/eventsauce | 3.9.1 (03.05.2026) | PHP ^8.0, framework-agnostic | 870★ | [Packagist](https://packagist.org/packages/eventsauce/eventsauce) |
| hirethunk/verbs | v0.9.0 (17.07.2026), pre-1.0 | PHP ≥8.3, Laravel 11–13 | 518★, ~23k/мес | [Packagist](https://packagist.org/packages/hirethunk/verbs) |
| spatie/laravel-model-states | 2.14.2 (22.07.2026) | PHP ^8.4, Laravel 12–13 | 1,3k★, ~479k/мес | [Packagist](https://packagist.org/packages/spatie/laravel-model-states) |
| spatie/laravel-webhook-server | 3.11.0 (23.08.2026) | Laravel 8.50–13 | ~545k/мес | [Packagist](https://packagist.org/packages/spatie/laravel-webhook-server) |
| spatie/laravel-webhook-client | 3.7.0 (28.07.2026) | Laravel 9–13 | ~677k/мес | [Packagist](https://packagist.org/packages/spatie/laravel-webhook-client) |
| owen-it/laravel-auditing | v14.0.6 (20.06.2026) | PHP ^8.2, Laravel 11–13 | 3,5k★, ~1,75 млн/мес | [Packagist](https://packagist.org/packages/owen-it/laravel-auditing) |
| spatie/laravel-activitylog | 5.1.1 (08.09.2026) | PHP ^8.4, Laravel 12–13 | 5,9k★, ~3,9 млн/мес | [Packagist](https://packagist.org/packages/spatie/laravel-activitylog) |
| laravel/pennant | v1.26.0 (13.08.2026) | Laravel 10–13 | ~1,8 млн/мес | [Packagist](https://packagist.org/packages/laravel/pennant) |
| spatie/laravel-data | 4.23.0 (08.05.2026) | Laravel 10–13 | 1,8k★, ~3,1 млн/мес | [Packagist](https://packagist.org/packages/spatie/laravel-data) |
| square1/laravel-idempotency | 13.0.0 (18.03.2026) | Laravel 12–13 | 119★, ~18k/мес | [Packagist](https://packagist.org/packages/square1/laravel-idempotency) |
| infinitypaul/idempotency-laravel | 2.0.0 (25.05.2026) | Laravel 9–13 | ~3,5k/мес | [Packagist](https://packagist.org/packages/infinitypaul/idempotency-laravel) |
| lorisleiva/laravel-actions | v2.12.0 (25.08.2026) | Laravel 11–13 | 2,9k★ | [Packagist](https://packagist.org/packages/lorisleiva/laravel-actions) |
| spatie/laravel-permission | 8.3.0 (03.07.2026) | PHP ^8.3, Laravel 12–13 | 13k★ | [Packagist](https://packagist.org/packages/spatie/laravel-permission) |
| spatie/laravel-query-builder | 7.3.5 (03.09.2026) | PHP ^8.3, Laravel 12–13 | 4,5k★ | [Packagist](https://packagist.org/packages/spatie/laravel-query-builder) |

- В PHP 8.4 есть нативный объектный `BcMath\Number` для арифметики произвольной точности — [PHP 8.4 Release](https://www.php.net/releases/8.4/en.php)
- IETF draft-ietf-httpapi-idempotency-key-header-07 (истёк 15.10.2025) предназначен для «fault-tolerant» POST/PATCH — [IETF Datatracker](https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/). Семантика:
  - повтор с тем же ключом и телом возвращает результат исходной операции;
  - тот же ключ с другим телом → `422`;
  - повтор, пока первый запрос ещё обрабатывается → `409 Conflict`;
  - отсутствие обязательного ключа → `400`;
  - политику истечения ключей нужно документировать, fingerprint тела опционален.

  [IETF draft-07 (HTML)](https://www.ietf.org/archive/id/draft-ietf-httpapi-idempotency-key-header-07.html)
- square1/laravel-idempotency:
  - заголовок `Idempotency-Key`, хранение в Laravel cache (по умолчанию 1 день);
  - ключи уникальны на пользователя (или IP);
  - от одновременных дублей защищают cache locks;
  - по умолчанию покрывает POST/PUT/PATCH/DELETE.

  [GitHub: square1-io/laravel-idempotency](https://github.com/square1-io/laravel-idempotency)
- Transactional outbox: сообщение пишется в outbox-таблицу в той же транзакции, что и бизнес-данные, а relay публикует его polling-ом или tailing-ом лога. Гарантия: «Messages are guaranteed to be sent if and only if the database transaction commits». Доставка at-least-once, поэтому «A message consumer must be idempotent» — [microservices.io](https://microservices.io/patterns/data/transactional-outbox.html)
- В Laravel с `after_commit => true` или `->afterCommit()` job отправляется в очередь только после commit, а при rollback отбрасывается — [Laravel Queues docs](https://laravel.com/docs/13.x/queues)

### Inferences
- Ledger. Append-only таблица операций (`accrual`, `redeem`, `expire`, `reverse`, `adjust`) с суммами в целых баллах (bigint) и ссылками на `checkout_id` и `idempotency_key`. Проекция баланса обновляется в той же транзакции. Сгорание реализуется через «лоты» начислений с `expires_at`: списание потребляет лоты по FIFO. Это event-sourcing-lite без фреймворка, и его проще портировать на другой язык.
- Полный ES (spatie/EventSauce) оправдан для отдельных агрегатов со сложной историей, например состояния кампаний. Verbs (0.9, pre-1.0) не стоит брать для ядра ledger.
- `afterCommit` — не outbox. Если процесс упадёт между commit и push в Redis, событие потеряется. Для webhooks партнёрам и событий в аналитику или будущие Go-сервисы нужна outbox-таблица с relay-воркером. Готового mainstream-пакета для Laravel не найдено.
- Идемпотентность checkout-операций лучше хранить в PostgreSQL: unique (`tenant_id`, `idempotency_key`) и снимок ответа. Cache-пакет подходит для менее критичных эндпоинтов: кеш может вытеснить ключ, а скоуп «на пользователя» не совпадает со скоупом «на tenant/терминал».
- brick/money пока 0.x, поэтому версию стоит фиксировать (`~0.15`). moneyphp 4.x — стабильная альтернатива.
- Если временно остаться на PHP 8.3, использовать activitylog v4 или owen-it v14, а для model-states — версию до 2.14.

### Gaps
- Функциональные различия spatie/laravel-event-sourcing v7 и EventSauce 3 по документации не сравнивались.
- Mainstream-пакет transactional outbox для Laravel не найден. Отсутствие не подтверждено исчерпывающим поиском.

## 5. API-слой: Sanctum vs Passport (OAuth2 для партнёров), версионирование, OpenAPI, rate limiting по арендатору

### Takeaway
Sanctum подходит для first-party токенов: SPA кабинета и API-ключи касс и терминалов с abilities. Если партнёрам нужен стандартный OAuth2, нужен Passport:
- client credentials для M2M;
- authorization code + PKCE для партнёрских приложений, действующих от имени мерчанта;
- device authorization для POS.

OpenAPI удобно генерировать через Scramble: автоматически из кода, OpenAPI 3.1. Лимиты по арендатору задаются через `RateLimiter::for(...)->by(...)`.

### Cited Findings
- Выбор между Passport и Sanctum по документации: «If your application absolutely needs to support OAuth2, then you should use Laravel Passport». Для SPA, мобильных приложений и выдачи API-токенов рекомендован Sanctum, который «does not support OAuth2» — [Passport docs](https://laravel.com/docs/13.x/passport)
- Passport построен на League OAuth2 Server. Поддерживает authorization code, PKCE, device authorization, client credentials («suitable for machine-to-machine authentication»). Password и implicit grant: «We no longer recommend» — [Passport docs](https://laravel.com/docs/13.x/passport)
- Для client credentials токенов `sub` равен ID клиента, по умолчанию клиенты имеют UUID. При `$clientUuids = false` возможна коллизия с ID пользователя — [Passport docs](https://laravel.com/docs/13.x/passport)
- laravel/passport v13.8.0 (28.08.2026), Laravel 11.35–13; v13.0.0 вышел 25.04.2025 — [Packagist](https://packagist.org/packages/laravel/passport)
- laravel/sanctum v4.3.3 (23.06.2026), Laravel 11–13, ~9,3 млн загрузок в месяц — [Packagist](https://packagist.org/packages/laravel/sanctum)
- В Laravel 13 появились first-party JSON:API resources — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)
- Scramble генерирует документацию без PHPDoc-аннотаций, в формате OpenAPI 3.1.0 с UI Stoplight Elements. Scramble PRO добавляет поддержку spatie/laravel-data, laravel-query-builder, laravel-actions — [Scramble](https://scramble.dedoc.co/). Версия v0.13.45 (18.09.2026), Laravel 10–13, ~2 млн загрузок в месяц — [Packagist](https://packagist.org/packages/dedoc/scramble)
- darkaonline/l5-swagger 11.1.0 (12.06.2026), Laravel 11.44–13, ~1,4 млн загрузок в месяц — [Packagist](https://packagist.org/packages/darkaonline/l5-swagger)
- Rate limiting поддерживает сегментацию ключом, несколько лимитов сразу (в минуту и в сутки) и кастомный ответ 429. Пример из документации: `RateLimiter::for('api', fn (Request $r) => Limit::perMinute(60)->by($r->user()?->id ?: $r->ip()))` — [Routing docs](https://laravel.com/docs/13.x/routing)
- Для jobs есть middleware `RateLimited` и `RateLimitedWithRedis` — [Queues docs](https://laravel.com/docs/13.x/queues)

### Inferences
- Аутентификация по сценариям:
  - **checkout-API:** API-ключ на терминал или интеграцию (Sanctum token с abilities) с кешированием lookup токена;
  - **партнёрские интеграции и embed:** Passport, client credentials и auth code + PKCE;
  - **кабинет мерчанта:** Sanctum cookie SPA или сессия Filament.
- Версионирование: URI-префикс `/api/v1` через route groups, отдельные Resource/DTO-классы на версию, отдельный OpenAPI-документ на версию, заголовки `Deprecation`/`Sunset`. Официального рецепта в документации Laravel нет.
- Лимиты по арендатору: `->by("tenant:{$tenantId}:client:{$clientId}")`, значения — из тарифа арендатора (кешировать). Лимиты checkout отделить от admin API. Под нагрузкой использовать Redis-лимитер.
- В API сразу заложить заголовок `Idempotency-Key` (раздел 4), `X-Request-Id` для трассировки и cursor-пагинацию (урок Sportmonks из раздела 2).

### Gaps
- Не найдено замеров накладных расходов на проверку токенов Sanctum (DB lookup) и Passport (JWT) под Octane.
- Официальных рекомендаций Laravel по версионированию API нет.

## 6. Кабинет мерчанта и white-label встраивание: Filament vs Inertia vs Livewire

### Takeaway
Filament v5 (на Livewire 4) — самый быстрый способ собрать back-office и кабинет мерчанта. В нём есть встроенная tenancy и собственные домены арендаторов (`tenantDomain`). Для глубокого white-label встраивания в продукты партнёров лучше отдельный фронт: Inertia v3 + Vue/React, SPA или web components поверх публичного API. Встраивание через iframe требует cookie с `SameSite=None; Secure; Partitioned`: в Laravel есть опция `partitioned`, в PHP 8.5 — ключ `partitioned` в `setcookie()`. Альтернатива — токенная авторизация.

### Cited Findings
- filament/filament: v4.0.0 — 11.08.2025, v5.0.0 — 16.01.2026, текущая v5.8.4 — 20.09.2026, ~4 млн загрузок в месяц — [Packagist](https://packagist.org/packages/filament/filament)
- «Apart from Livewire v4 support, Filament v5 has no additional changes over v4». Новые функции выходят в обе версии, для апгрейда есть скрипт — [Filament blog](https://filamentphp.com/insights/danharrin-filament-v5-blueprint)
- livewire/livewire: v4.0.0 — 14.01.2026, текущая v4.4.6 — 21.09.2026, 23,6k звёзд — [Packagist](https://packagist.org/packages/livewire/livewire)
- inertiajs/inertia-laravel: v3.0.0 — 24.03.2026, текущая v3.4.0 — 25.09.2026, Laravel 11.35–13 — [Packagist](https://packagist.org/packages/inertiajs/inertia-laravel)
- Filament tenancy:
  - `HasTenants` и `canAccessTenant()`;
  - tenant в URL-префиксе, на поддомене `tenantDomain('{tenant:slug}.example.com')` или на полном домене `tenantDomain('{tenant:domain}')`;
  - страницы регистрации и профиля tenant;
  - биллинг через Spark или собственный `BillingProvider`.

  [Filament 5.x Tenancy](https://filamentphp.com/docs/5.x/users/tenancy)
- В `config/session.php` Laravel есть `same_site` (по умолчанию `lax`) и `partitioned` (`SESSION_PARTITIONED_COOKIE`). Partitioned-cookie принимаются браузером, «when flagged "secure" and the Same-Site attribute is set to "none"» — [laravel/laravel config/session.php](https://github.com/laravel/laravel/blob/13.x/config/session.php)
- `SameSite=None` в Laravel требует `secure = true` и HTTPS — [Laracasts](https://laracasts.com/discuss/channels/laravel/laravel-session-cookie-cannot-be-set-to-none-for-samesite)
- CHIPS: partitioned-cookie «double-keyed» — по сайту, который её установил, и по top-level сайту. Требуется `Secure`, сценарий — сторонние embeds. Статус «Baseline 2025» (декабрь 2025). Firefox по умолчанию применяет state partitioning — [MDN: Partitioned cookies](https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Privacy_sandbox/Partitioned_cookies)
- В PHP 8.5 `setcookie()` поддерживает ключ `partitioned` — [PHP 8.5 Release](https://www.php.net/releases/8.5/en.php)
- В Laravel 13 защита от request forgery стала origin-aware (`PreventRequestForgery`). Это важно для cross-origin сценариев — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)

### Inferences
Варианты white-label по возрастанию сложности:
- **A.** Панель Filament на собственном домене партнёра или мерчанта (CNAME + `tenantDomain`) с брендингом per-tenant. Проще всего и без iframe-проблем.
- **B.** Iframe с Filament. Нужны partitioned session cookie, SSO-handoff (короткоживущий подписанный токен → сессия) и per-tenant CSP `frame-ancestors`. Livewire зависит от серверных round-trip и сессионной cookie, поэтому этот вариант чувствителен к политикам сторонних cookie.
- **C.** Встраиваемые виджеты или web components (например, Vue custom elements) поверх публичного API с OAuth-токенами. Лучший контроль UX и изоляции.
- **D.** Отдельный Inertia/SPA-кабинет для полностью кастомного UX.

Практичная комбинация: Filament — для внутреннего back-office и базового кабинета мерчанта (A); компоненты C — для встраивания в партнёрские продукты.

### Gaps
- Официальных рекомендаций Filament по встраиванию в iframe и CSP не найдено.
- Не проверено актуальное поведение Safari с partitioned-cookie во вложенных iframe.
- Возможности тем и брендинга per-tenant в Filament по документации не проверены.

## 7. Очереди и фоновые задачи: Horizon + Redis vs RabbitMQ vs Kafka; сгорание и кампании на миллионах счетов; Reverb

### Takeaway
Horizon + Redis тянет сотни миллионов jobs в сутки: в одном кейсе 100 млн jobs за 12 часов. Ограничения: только Redis, Redis Cluster не поддерживается, нужен pcntl (Linux). RabbitMQ и Kafka подключаются сторонними пакетами. Kafka разумнее использовать как шину событий (аналитика, будущие Go-сервисы), а не как основную очередь задач. Сгорание баллов на миллионах счетов лучше делать set-based SQL-батчами по диапазонам ID или партициям, а не отдельной job на каждый счёт.

### Cited Findings
- Встроенные драйверы очередей: database, Redis, SQS, Beanstalkd, sync, null. RabbitMQ и Kafka «из коробки» нет — [Laravel Queues docs](https://laravel.com/docs/13.x/queues)
- Horizon:
  - требует Redis; «Horizon is not compatible with Redis Cluster at this time»;
  - стратегии балансировки auto/simple/false, `autoScalingStrategy` time/size/log;
  - лимиты воркера: memory (по умолчанию 128 MB), `maxJobs`, `maxTime`;
  - timeout должен быть меньше `retry_after`, иначе возможна двойная обработка;
  - при деплое выполнять `horizon:terminate`.

  [Horizon docs](https://laravel.com/docs/13.x/horizon)
- laravel/horizon v5.50.0 (15.09.2026) требует `ext-pcntl` и `ext-posix` — [Packagist](https://packagist.org/packages/laravel/horizon)
- vladimir-yuldashev/laravel-queue-rabbitmq v15.0.2 (02.09.2026), 2,1k звёзд — [Packagist](https://packagist.org/packages/vladimir-yuldashev/laravel-queue-rabbitmq)
- mateusjunges/laravel-kafka v2.11.5 (25.08.2026), Laravel 12–13 — [Packagist](https://packagist.org/packages/mateusjunges/laravel-kafka)
- Инструменты очередей Laravel — [Queues docs](https://laravel.com/docs/13.x/queues):
  - job batching: `Bus::batch`, `then/catch/finally`, `allowFailures`, таблица `job_batches`, `queue:prune-batches`;
  - `ShouldBeUnique` и `WithoutOverlapping`;
  - rate limiting jobs;
  - hash-теги в именах очередей для Redis Cluster;
  - `Queue::route`.
- Для обновления по фильтруемой колонке нужно использовать `chunkById`/`lazyById`: обычный `chunk` даёт «unexpected and inconsistent results». `cursor()` держит одну модель в памяти и не умеет eager loading. `MassPrunable` удаляет массовыми запросами без событий моделей — [Eloquent docs](https://laravel.com/docs/13.x/eloquent)
- Кейсы: больше 100 млн jobs за 12 часов на Horizon + Redis + MySQL — [Mateus Guimarães](https://mateusguimaraes.com/posts/scaling-laravel); 150–200 именованных очередей Horizon и больше 1 000 jobs в секунду — [Sportmonks / Laravel](https://laravel.com/cloud/customer-stories/how-sportmonks-handles-600m-api-requests-a-week-on-laravel-cloud)
- Reverb:
  - WebSocket-сервер, горизонтально масштабируется через Redis pub/sub (`REVERB_SCALING_ENABLED=true`);
  - для больше чем 1 000 одновременных соединений нужен event loop на `ext-uv`: `stream_select` ограничен ~1 024 файлами;
  - требуется тюнинг ulimit и nginx; диапазон портов даёт ~28k соединений на сервер.

  [Reverb docs](https://laravel.com/docs/13.x/reverb). laravel/reverb v1.12.0 (22.09.2026) — [Packagist](https://packagist.org/packages/laravel/reverb)

### Inferences
- **Сгорание баллов.** Лоты с `expires_at` лежат в таблице, партиционированной по месяцу. Периодическая job по каждому арендатору обходит истёкшие лоты диапазонами ID (10–50 тыс. строк на транзакцию). Операции `expire` пишутся в ledger через `INSERT ... SELECT`, одновременно обновляется проекция баланса. `Bus::batch` на арендатора даёт прогресс и отмену. Уведомления о скором сгорании строятся из того же индекса.
- **Кампании и рассылки.** Сегмент выбирается SQL-запросом (или из ClickHouse), затем fan-out на чанки ID получателей. `RateLimited` ставится по провайдеру или каналу, чтобы не упереться в лимиты SMS/email-провайдеров.
- **Отдельные supervisors Horizon по классам нагрузки:**
  - `critical` — побочные эффекты checkout;
  - `webhooks`;
  - `bulk` — сгорания и кампании, с ограничением `maxProcesses`;
  - `exports`.
- **Redis HA.** Horizon не поддерживает Redis Cluster, поэтому нужен primary/replica + Sentinel или managed Redis/Valkey без cluster mode. Инстансы Redis для кеша и для очередей лучше разделить.
- **Kafka** нужна, когда появляются стриминг в ClickHouse, несколько независимых потребителей, replay или Go-сервисы. **RabbitMQ** — если нужна маршрутизация между разнородными сервисами. Для чисто Laravel-очередей Horizon + Redis проще.

### Gaps
- Нет публичного сравнения пропускной способности Horizon/Redis и RabbitMQ в Laravel.
- Не проверена совместимость Horizon с managed Valkey в российских облаках.

## 8. Хранилища: PostgreSQL vs MySQL, Redis, ClickHouse, поиск, партиционирование ledger

### Takeaway
Для этого домена PostgreSQL сильнее:
- RLS для изоляции арендаторов;
- декларативное партиционирование ledger;
- advisory locks для сериализации операций по счёту;
- в Laravel 13 — pgvector и документированная работа через PgBouncer;
- расширенные возможности через tpetry/laravel-postgresql-enhanced.

Для аналитики — ClickHouse, из Laravel через smi2/phpclickhouse или glushkovds/phpclickhouse-laravel. Managed ClickHouse есть у российских облаков, в том числе в 152-ФЗ-контуре.

### Cited Findings
- First-party поддержка БД в Laravel: MariaDB 10.3+, MySQL 5.7+, PostgreSQL 10.0+, SQLite 3.26+, SQL Server 2017+. Есть read/write соединения с опцией `sticky` и pooled PostgreSQL с отдельным `direct`-соединением — [Laravel DB docs](https://laravel.com/docs/13.x/database)
- RLS: default-deny, обход для superuser/BYPASSRLS/owner без FORCE, covert channels через constraints — [PostgreSQL RLS](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
- Партиционирование (документация PostgreSQL, текущая версия 18.x) — [PostgreSQL Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html):
  - виды: range, list, hash;
  - `DROP`/`DETACH PARTITION` «far faster than a bulk operation» и не создают нагрузки VACUUM, как bulk `DELETE`;
  - unique и PK на партиционированной таблице должны включать все колонки ключа партиционирования;
  - планировщик нормально работает с «up to a few thousand partitions», если pruning отсекает большинство.
- Advisory locks бывают session-level (не подчиняются транзакционной семантике) и transaction-level (снимаются в конце транзакции). Документация предостерегает от их использования с `LIMIT` — [PostgreSQL Explicit Locking](https://www.postgresql.org/docs/current/explicit-locking.html)
- В Laravel 13 есть векторный поиск на PostgreSQL + pgvector — [Laravel 13 Release Notes](https://laravel.com/docs/13.x/releases)
- tpetry/laravel-postgresql-enhanced 3.7.0 (17.05.2026), Laravel 6–13 — [Packagist](https://packagist.org/packages/tpetry/laravel-postgresql-enhanced); [GitHub](https://github.com/tpetry/laravel-postgresql-enhanced). Возможности:
  - zero-downtime миграции с таймаутами блокировок;
  - partial indexes и include columns;
  - materialized views;
  - `RETURNING`, CTE, lateral joins;
  - full-text search и domain types.
- ClickHouse-клиенты: smi2/phpclickhouse 1.26.925 (25.09.2026; 854 звезды, ~626k загрузок в месяц) — [Packagist](https://packagist.org/packages/smi2/phpclickhouse); glushkovds/phpclickhouse-laravel v2.8.0 (21.08.2026; 207 звёзд) — [Packagist](https://packagist.org/packages/glushkovds/phpclickhouse-laravel)
- laravel/scout v11.8.0 (22.09.2026), Laravel 9–13 — [Packagist](https://packagist.org/packages/laravel/scout)
- Managed PostgreSQL в Selectel: версии 15–18; SLA HA-кластера 99,95% на запись и 99,99% на чтение; соответствие 152-ФЗ до УЗ-1 — [Selectel Managed PostgreSQL](https://selectel.ru/services/cloud/managed-databases/postgresql/)
- Managed ClickHouse для ПДн: Yandex Cloud упоминает Managed PostgreSQL, Managed ClickHouse и Object Storage на странице 152-ФЗ — [Yandex Cloud 152-ФЗ](https://yandex.cloud/ru/solutions/152-fz). ClickHouse есть в 152-ФЗ-сегментах Selectel — [Selectel 152-ФЗ](https://selectel.ru/services/cloud/servers/152fz/) и Timeweb Cloud — [Timeweb 152-ФЗ](https://timeweb.cloud/152fz)

### Inferences
- **Ledger.** Range-партиции по `created_at` (месяц). Индексы (`tenant_id`, `account_id`, `created_at`). PK вида (`id`, `created_at`), потому что PK обязан включать ключ партиции. Старые партиции архивируются через `DETACH`.
- **Сериализация операций по счёту:** `SELECT ... FOR UPDATE` на строке баланса или `pg_advisory_xact_lock(hash(tenant_id, account_id))`. С PgBouncer в transaction mode допустимы только transaction-level блокировки.
- **Прочее в PostgreSQL:**
  - JSONB с GIN-индексами — для определений правил и кампаний;
  - партиционирование по hash(`tenant_id`) — только если один арендатор или таблица станут слишком большими.
- **Redis/Valkey** — кеш правил и балансов (read-through), rate limiting, Horizon, locks. Источником истины для балансов он быть не должен.
- **Поиск** в кабинете (клиенты по телефону или email) — PostgreSQL full-text или trigram. Meilisearch/OpenSearch (managed OpenSearch есть у Selectel и Timeweb) подключать только при реальной потребности.
- **Путь в аналитику:** outbox → Kafka → ClickHouse (Kafka engine) или периодические batch-insert из PHP. OLAP-запросы по сырым транзакциям в OLTP-PostgreSQL не гонять.
- **MySQL** жизнеспособен, но не даёт встроенного RLS-механизма уровня политик, и изоляцию придётся гарантировать только кодом. Это общее знание, в сессии не перепроверялось.

### Gaps
- Сравнительных бенчмарков MySQL и PostgreSQL для ledger-нагрузки не найдено.
- Отсутствие RLS в MySQL по первоисточнику в этой сессии не проверялось.
- Доступные версии PostgreSQL (17/18) проверены только у Selectel.

## 9. Структура проекта: модульный монолит, границы, тесты, статанализ, CI/CD

### Takeaway
Рекомендуемая схема — модульный монолит. Модули живут в `app-modules/` через internachi/modular (следует конвенциям Laravel, модули — Composer path-пакеты) или в собственных папках `src/<Context>`. Границы контролируются Pest arch-тестами и deptrac/deptrac 4.x (пакет qossmic/deptrac заброшен). Для качества — Larastan 3 и Pint. Pest 5 требует PHP 8.4+.

### Cited Findings
- internachi/modular 3.0.2 (23.03.2026): PHP ≥8.3, Laravel 11–13, 1,2k звёзд — [Packagist](https://packagist.org/packages/internachi/modular). Устройство:
  - модули в `app-modules/`, у каждого `composer.json`, `src/`, `tests/`, `routes/`, `resources/`, `database/`;
  - модули подключаются как Composer path repositories;
  - auto-discovery команд, миграций, фабрик, политик, Blade-компонентов, listeners и переводов;
  - команды `make:module` и `--module=`.

  Позиционирование: «as much a set of conventions as it is a package». nwidart, по словам автора modular, лучше подходит для CMS-подобных динамических модулей — [GitHub: InterNACHI/modular](https://github.com/InterNACHI/modular)
- nwidart/laravel-modules v13.0.0 (19.03.2026), PHP ^8.3, 6,2k звёзд, ~775k загрузок в месяц — [Packagist](https://packagist.org/packages/nwidart/laravel-modules)
- deptrac/deptrac 4.7.2 (15.09.2026), PHP ^8.2 — [Packagist](https://packagist.org/packages/deptrac/deptrac). qossmic/deptrac помечен abandoned с заменой на deptrac/deptrac — [Packagist](https://packagist.org/packages/qossmic/deptrac)
- Pest arch testing: `toUse`, `toOnlyUse`, `toOnlyBeUsedIn`, `toBeUsedIn`, `not->toUse`, `toExtend`, `toImplement`, `toBeFinal`, `toHaveSuffix`; пресеты php, security, laravel, strict, relaxed — [Pest docs](https://pestphp.com/docs/arch-testing)
- Версии инструментов:
  - larastan/larastan v3.12.2 (19.09.2026), Laravel 11.44–13 — [Packagist](https://packagist.org/packages/larastan/larastan)
  - laravel/pint v1.32.1 (10.09.2026), PHP ^8.3 — [Packagist](https://packagist.org/packages/laravel/pint)
  - pestphp/pest v5.2.1 (PHP ^8.4); v4 — на PHP ^8.3 — [Packagist](https://packagist.org/packages/pestphp/pest)
- `Model::preventLazyLoading(! app()->isProduction())` включает строгий режим Eloquent — [Eloquent docs](https://laravel.com/docs/13.x/eloquent)
- laravel/boost v2.10.0 — first-party инструмент, дающий AI-агентам контекст приложения — [Packagist](https://packagist.org/packages/laravel/boost)

### Inferences
- **Модули (bounded contexts):**

  | Модуль | Ответственность |
  |---|---|
  | `Tenancy` | арендаторы, домены, тарифы |
  | `Identity` | пользователи мерчантов, роли — spatie/laravel-permission, OAuth-клиенты |
  | `Customers` | участники программ, согласия, сегменты |
  | `Ledger` | счета, лоты, операции, балансы |
  | `Rules` / `Campaigns` | движок правил, акции, кампании |
  | `Processing` / `Checkout` | hot path: calculate, authorize, commit, cancel, refund |
  | `Communications` | email, SMS, push |
  | `Analytics` | экспорт в ClickHouse, отчёты |
  | `Billing` | подписки SaaS, счета, акты |
  | `Integrations` | webhooks, коннекторы касс и e-com |
  | `Admin` | Filament-панели |

- **Правило зависимостей.** Модуль открывает только namespace `Contracts`: интерфейсы, DTO на spatie/laravel-data, доменные события. Чужие `Models`/`Internal` импортировать нельзя. Правило проверяется deptrac-слоями и Pest arch-тестами (`expect('Modules\\Ledger\\Internal')->toOnlyBeUsedIn('Modules\\Ledger')`).
- `Processing` зависит только от контрактов `Ledger` и `Rules` — это готовит будущий вынос hot path в отдельный сервис (раздел 13).
- **CI-конвейер:**
  1. Pint `--test`.
  2. Larastan (уровень поднимать постепенно).
  3. Pest (с `--parallel`) на реальном PostgreSQL-сервисе с RLS-ролью.
  4. deptrac.
  5. Прогон миграций вверх и вниз.
  6. Сборка Docker-образа FrankenPHP.
  7. Нагрузочный smoke checkout-эндпоинтов (k6/wrk).

### Gaps
- Детали `pest --parallel` с PostgreSQL (отдельные БД на процесс) по документации не проверены.
- Готовой deptrac-конфигурации под internachi/modular не найдено.

## 10. Наблюдаемость и эксплуатация; доступность Laravel Cloud / Forge / Vapor / Nightwatch из России

### Takeaway
В российском контуре реалистичен self-hosted стек:
- Pulse — лёгкий production-дашборд;
- Telescope — только dev и stage;
- OpenTelemetry PHP (стабилен) → self-hosted Collector и Grafana-стек;
- self-hosted Sentry — тяжёлый: от 16 GB RAM + 16 GB swap.

Nightwatch — полностью managed SaaS с ЦОД в US и EU, передача туда ПДн означает трансграничную передачу. Laravel Cloud и Vapor работают на AWS без российских регионов. У Forge, Cloud и Vapor есть санкционные и платёжные барьеры.

### Cited Findings
- Версии инструментов наблюдаемости:
  - laravel/pulse v1.8.1 (20.08.2026), Laravel 10–13 — [Packagist](https://packagist.org/packages/laravel/pulse)
  - laravel/telescope v5.25.0 (09.09.2026) — [Packagist](https://packagist.org/packages/laravel/telescope)
  - laravel/nightwatch v1.30.2 (18.09.2026), ~2 млн загрузок в месяц — [Packagist](https://packagist.org/packages/laravel/nightwatch)
- Nightwatch:
  - «Our data centers are located in the US and EU», позже обещаны Австралия, Великобритания и Сингапур;
  - «Nightwatch is a fully-managed product», self-hosting нет;
  - агент умеет редактировать PII до отправки;
  - хранение по умолчанию 90 дней;
  - тарифы Free $0 (300k событий), Pro $20 (7,5 млн), Team $60 (30 млн), Business $300 (180 млн).

  [Nightwatch Pricing](https://laravel.com/nightwatch/pricing)
- OpenTelemetry PHP: traces, metrics и logs имеют статус Stable, auto-instrumentation требует PHP 8.0+ — [OpenTelemetry PHP](https://opentelemetry.io/docs/languages/php/). Laravel-пакеты: open-telemetry/opentelemetry-auto-laravel 1.9.1 (17.09.2026, Laravel до 13) — [Packagist](https://packagist.org/packages/open-telemetry/opentelemetry-auto-laravel); keepsuit/laravel-opentelemetry 2.2.5 (11.09.2026) — [Packagist](https://packagist.org/packages/keepsuit/laravel-opentelemetry)
- Self-hosted Sentry:
  - минимум 4 CPU, 16 GB RAM + 16 GB swap, 20 GB диска; рекомендуется 32 GB RAM;
  - «no guarantees or dedicated support»;
  - лицензия FSL.

  [Sentry Self-Hosted](https://develop.sentry.dev/self-hosted/). sentry/sentry-laravel 4.28.0 (23.09.2026) — [Packagist](https://packagist.org/packages/sentry/sentry-laravel)
- Метрики и health-checks: spatie/laravel-prometheus 1.7.0 (PHP ^8.4) — [Packagist](https://packagist.org/packages/spatie/laravel-prometheus); spatie/laravel-health 1.40.2 — [Packagist](https://packagist.org/packages/spatie/laravel-health)
- Reverb интегрируется с Pulse (recorders для соединений и сообщений) — [Reverb docs](https://laravel.com/docs/13.x/reverb)
- Рестарты при деплое: `octane:reload` — [Octane docs](https://laravel.com/docs/13.x/octane); `horizon:terminate` — [Horizon docs](https://laravel.com/docs/13.x/horizon); `reverb:restart` — [Reverb docs](https://laravel.com/docs/13.x/reverb)
- Laravel Cloud:
  - «runs on dedicated AWS EC2 servers»;
  - «9 regions across the US, Canada, Europe, and Asia Pacific»;
  - Private Cloud — в приватном AWS-аккаунте;
  - Vapor — serverless на AWS Lambda.

  [Laravel Cloud](https://laravel.com/cloud)
- Условия Forge (Laravel Holdings Inc., право штата Нью-Йорк): сервисом нельзя пользоваться, «if subject to U.S. sanctions»; подписка автоматически списывается регулярными платежами — [Forge Terms](https://laravel.com/legal/forge-terms)
- Обновление Amazon от 8 марта: «AWS is no longer accepting new sign-ups based in Russia or Belarus» — [About Amazon](https://www.aboutamazon.com/news/community/amazons-assistance-in-ukraine)
- Visa (5 марта 2022): карты, выпущенные в России, «will no longer work outside the country» — [Visa](https://usa.visa.com/about-visa/newsroom/press-releases.releaseId.18871.html)
- 152-ФЗ, ст. 18 ч. 5: запись, систематизация, накопление и хранение ПДн граждан РФ — с использованием баз данных на территории РФ. Ст. 12 регулирует трансграничную передачу и уведомление Роскомнадзора — [Гарант: 152-ФЗ](https://base.garant.ru/12148567/)

### Inferences
- **Laravel Cloud и Vapor** не подходят как основная площадка для ПДн граждан РФ: нет российского региона, действует требование локализации. Практически мешают и оплата (карты РФ за рубежом не работают), и санкционные условия.
- **Forge** технически управляет серверами по SSH и мог бы обслуживать VM в российских облаках, но подписка и ToS несут риск. Надёжнее Ansible, Deployer или GitOps на Kubernetes.
- **Nightwatch** использовать не стоит. Если всё же нужен — только с полным редактированием ПДн (телефоны, email, ID) и после юридической оценки трансграничной передачи.
- **Рекомендуемая эксплуатация:**
  - Docker-образ на базе FrankenPHP → Managed Kubernetes в российском облаке, с rolling updates и readiness probes;
  - раздельные Deployments: `api` (Octane), `horizon` (по supervisor), `scheduler` (одна реплика и `onOneServer`), `reverb`;
  - миграции — pre-deploy job по схеме expand/contract;
  - PgBouncer перед PostgreSQL.
- **Наблюдаемость:** OTel SDK → OTel Collector → Tempo/Jaeger, Prometheus/Mimir и Loki в Grafana. Pulse — для быстрых инсайтов. Ошибки — self-hosted Sentry (с учётом его требований) или облегчённые альтернативы (в этой сессии не проверены).

### Gaps
- Не проверены полный список регионов Laravel Cloud и явные ограничения регистрации из РФ в Cloud/Nightwatch Terms (проверены только Forge Terms).
- Точные текущие редакции ст. 12 и ст. 18 ч. 5 152-ФЗ после поправок 2025–2026 годов не извлечены. Оглавление Гаранта показывает изменения в этот период — нужна сверка с юристом.
- Не проверены managed-сервисы Prometheus/Grafana/трейсинга у российских облаков.

## 11. Хостинг в РФ с соответствием 152-ФЗ: Yandex Cloud, VK Cloud, Selectel, Cloud.ru, Timeweb Cloud

### Takeaway
Все пять провайдеров заявляют соответствие высшему уровню защищённости ПДн (УЗ-1) хотя бы для части платформы и предлагают managed PostgreSQL и Kubernetes. Аттестат провайдера покрывает только инфраструктуру: SaaS-компания остаётся оператором ПДн со своими обязанностями. Ориентир цены managed PostgreSQL — около 6 тыс. ₽ в месяц за хост 2 vCPU / 8 GB (Yandex, VK Cloud, с НДС).

### Cited Findings
**Yandex Cloud**
- По странице решения «Соответствие 152-ФЗ на высшем уровне защищенности (УЗ-1) подтверждено аттестатом». Разделение ответственности: клиент контролирует доступы и остаётся «владельцем данных и должны выполнять все обязанности оператора». Для ПДн упомянуты Managed PostgreSQL, Managed ClickHouse и Object Storage — [Yandex Cloud: 152-ФЗ](https://yandex.cloud/ru/solutions/152-fz)
- Меры защиты применяются по ПП №1119 и приказу ФСТЭК №21 для УЗ-1; у BareMetal отдельный аттестат. Также PCI DSS, ISO 27001/27017/27018/42001 и ГОСТ Р 57580.1 (5-й уровень соответствия) — [Yandex Cloud: Соответствие требованиям](https://yandex.cloud/ru/docs/overview/security/conform)
- Первая добровольная аттестация по 152-ФЗ — июнь 2021 — [Блог Yandex Cloud](https://cloud.yandex.ru/blog/posts/2021/06/accreditation)
- Пример из прайса Managed PostgreSQL: кластер из 3 хостов s3-c2-m8 за 30 дней стоит 18 005,76 ₽. В расчёте используются 1,8792 ₽ за vCPU-час, 0,5072 ₽ за GB RAM в час и 3,744 ₽ за GB network-HDD в месяц — [Yandex Managed PostgreSQL: цены](https://yandex.cloud/ru/docs/managed-postgresql/pricing)
- В Managed Kubernetes тарифицируется мастер (не тарифицируется, если кластер остановлен), узлы оплачиваются как VM Compute Cloud, 100 GB исходящего трафика в месяц бесплатно — [Yandex Managed Kubernetes: цены](https://yandex.cloud/ru/docs/managed-kubernetes/pricing)

**VK Cloud**
- ФСТЭК-сертификат подтверждает УЗ-1. «Облако 152-ФЗ» поддерживает УЗ-3, УЗ-2 и УЗ-1, ответственность разделена. О запросах правоохранительных органов клиента уведомляют в течение 72 часов — [VK Cloud docs: 152-ФЗ](https://cloud.vk.ru/docs/ru/intro/it-security/compliance-152fz)
- VK Secure Cloud имеет аттестат №3740.00024.2026 от 20.02.2026 (класс К1, УЗ-1, значимые объекты КИИ до 1 категории) — [VK Secure Cloud](https://cloud.vk.ru/secure-cloud/) (данные из выдержки поиска). Подтверждение УЗ-1 платформы VK Cloud — сентябрь 2022 — [VK press release](https://vk.company/ru/press/releases/11271/)
- Прайс-лист с 12.01.2026, цены с НДС за 30 дней:

  | Ресурс | Managed PostgreSQL (Cloud Databases) | Мастер Kubernetes |
  |---|---|---|
  | vCPU (Intel Cascade Lake) | 1 024,49 ₽ | 983,51 ₽ |
  | RAM, за 1 GB | 278,31 ₽ | 267,18 ₽ |
  | SSD, за 1 GB | 16,59 ₽ | — |

  [VK Cloud: прайс-лист](https://cloud.vk.ru/pricelist)

**Selectel**
- «Облако 152-ФЗ»: у облачных серверов есть «акт оценки эффективности до первого уровня защищенности (УЗ-1)». Доступны:
  - managed БД: PostgreSQL, MySQL, Redis, ClickHouse, Kafka, OpenSearch;
  - Kubernetes, S3, бэкапы, балансировщики, CDN;
  - защита от DDoS включена.

  Selectel отвечает за физическую и инфраструктурную безопасность, клиент — за организационные меры, защиту на уровне приложения и документы для регуляторов. Трафик: 3 TB в месяц бесплатно, дальше 0,90 ₽ за GB — [Selectel: Облако 152-ФЗ](https://selectel.ru/services/cloud/servers/152fz/)
- Managed PostgreSQL 15–18: «Соответствуем 152-ФЗ до УЗ-1», SLA 99,95% на запись и 99,99% на чтение для HA — [Selectel Managed PostgreSQL](https://selectel.ru/services/cloud/managed-databases/postgresql/)
- Защищённый сегмент «от 25 000 ₽/мес». Это сторонний агрегатор, дата не указана — [help152.ru](https://help152.ru/hosters/selectel/cloud-152fz)

**Cloud.ru (Evolution)**
- Публичное облако Evolution аттестовано по 152-ФЗ на УЗ-1, открыта третья зона доступности (март 2025) — [Блог Cloud.ru](https://cloud.ru/blog/cloud-ru-otkryl-tretyu-zonu-dostupnosti-i-attestoval-platformu-cloud-ru-evolution); [CNews](https://www.cnews.ru/news/line/2025-03-03_cloudru_otkryl_tretyu_zonu_dostupnosti)
- Сертификаты: PCI DSS, ISO/IEC 27001:2022, сертификат ФСТЭК №4979, запись в реестре российского ПО. Данные из выдержки поиска — [Cloud.ru: сертификаты и аттестаты](https://cloud.ru/docs/evolution/overview/topics/security__compliance)

**Timeweb Cloud**
- Соответствие 152-ФЗ и УЗ-1 «подтверждено документально» (акт соответствия). В сегмент входят облачные серверы, VDS, выделенные серверы, managed БД (PostgreSQL, MySQL, MongoDB, ClickHouse, OpenSearch, Valkey), Kubernetes, S3 и бэкапы. Реестр ПО, запись №15725 — [Timeweb Cloud: 152-ФЗ](https://timeweb.cloud/152fz)
- Подтверждение УЗ-1 — январь 2026 — [CNews](https://safe.cnews.ru/news/line/2026-01-14_timeweb_cloud_podtverdil_sootvetstvie)

**Законодательная рамка**
- Ст. 18 ч. 5 152-ФЗ — локализация баз данных с ПДн граждан РФ; ст. 12 — трансграничная передача — [Гарант: 152-ФЗ](https://base.garant.ru/12148567/)

### Inferences
- Сопоставимая стоимость хоста 2 vCPU / 8 GB с 100 GB диска — порядка 5,9–6,0 тыс. ₽ за 30 дней. VK Cloud с SSD: 2 × 1 024,49 + 8 × 278,31 + 100 × 16,59 ≈ 5 934 ₽. Yandex по примеру (network-HDD) — ≈ 6 002 ₽ на хост. HA-кластер из 2–3 хостов обойдётся в 12–18 тыс. ₽ в месяц. Это расчёт по опубликованным единичным ценам, а не счёт.
- Для SaaS лояльности (ФИО, телефоны, email, история покупок покупателей мерчантов) нужен провайдер с аттестатом УЗ-1. Конкретный УЗ определяется моделью угроз и объёмом субъектов по ПП №1119 — его нужно оформить с ИБ-специалистом или юристом.
- В роли SaaS компания, скорее всего, выступает обработчиком по поручению мерчантов-операторов. Это нужно закрепить договором поручения — требует юридической проверки.
- Выбор площадки:
  - **Yandex Cloud** — самый широкий набор managed-сервисов (PostgreSQL, ClickHouse, Kafka, Kubernetes, Valkey);
  - **Selectel** — сильная комбинация 152-ФЗ, managed БД и bare metal;
  - **VK Cloud** и **Cloud.ru** — корпоративные альтернативы;
  - **Timeweb Cloud** — дешёвый старт.

  Стоит проверить: наличие managed PostgreSQL 17/18, PgBouncer, pgvector, логической репликации и managed Redis без cluster mode (из-за Horizon).

### Gaps
- Официальные цены managed PostgreSQL и Kubernetes у Selectel, Timeweb и Cloud.ru не извлечены: калькуляторы не отдают данные в текстовом виде. Цена мастера Kubernetes в Yandex тоже не извлечена.
- Номера и даты аттестатов Yandex Cloud, Selectel и Timeweb в текстах страниц не приведены.
- Для VK Cloud и Cloud.ru не выяснено, какие именно managed-сервисы входят в аттестованный периметр.
- Сопоставление «оператор vs обработчик» и выбор УЗ не проверены по первоисточникам в этой сессии.

## 12. Биллинг самой SaaS в России: вместо Cashier — ЮKassa, CloudPayments, Т-Касса, Robokassa; B2B-счета и ЭДО

### Takeaway
Laravel Cashier (Stripe/Paddle) неприменим: Stripe в России недоступен. Нужен собственный модуль Billing (планы, подписки, счета, платежи, dunning) и платёжные адаптеры:
- **ЮKassa** — автоплатежи по картам, ЮMoney и СБП; в боевом магазине включаются через менеджера;
- **CloudPayments** — API подписок;
- **Т-Касса** — `Recurrent` / `RebillId` / `Charge`;
- **Robokassa** — `Recurring` с `PreviousInvoiceID`.

Для B2B-мерчантов основной сценарий — счёт → безналичная оплата → акт или УПД через ЭДО. У Диадока есть HTTP API.

### Cited Findings
- laravel/cashier v16.8.0 (01.09.2026) — [Packagist](https://packagist.org/packages/laravel/cashier). Россия отсутствует в списке стран, где доступен Stripe — [Stripe Global](https://stripe.com/global)
- ЮKassa, автоплатежи:
  - схема: сохранить способ оплаты (`payment_method_id`) → списывать без участия пользователя → «отключить», удалив ID у себя;
  - способы оплаты: банковские карты, кошелёк ЮMoney, СБП;
  - «По умолчанию автоплатежи работают только в тестовом магазине», для боевого магазина нужно написать менеджеру.

  [ЮKassa: автоплатежи](https://yookassa.ru/developers/payment-acceptance/scenario-extensions/recurring-payments/basics)
- Привязать способ оплаты можно во время платежа или платежом на нулевую сумму — [ЮKassa: привязка во время платежа](https://yookassa.ru/developers/payment-acceptance/scenario-extensions/recurring-payments/save-payment-method/save-during-payment); [ЮKassa: привязка на нулевую сумму](https://yookassa.ru/developers/payment-acceptance/scenario-extensions/recurring-payments/save-payment-method/save-without-payment). Автоплатежи также возможны по выставленному счёту — [ЮKassa: автоплатежи по счёту](https://yookassa.ru/developers/payment-acceptance/scenario-extensions/invoices/recurring-payments)
- yoomoney/yookassa-sdk-php 3.15.1 (13.08.2026) — [Packagist](https://packagist.org/packages/yoomoney/yookassa-sdk-php)
- CloudPayments. API создаёт и отменяет подписки, задаёт период (в том числе нестандартный) и максимальное число платежей. После первой оплаты карта получает токен для рекуррентов. Сервис подписок включает чеки по 54-ФЗ. Данные из выдержек официальных страниц — [CloudPayments: рекуррентные платежи](https://cloudpayments.ru/features/recurrent); [CloudPayments: подписки](https://cloudpayments.ru/payments/subscriptions/); [Документация CloudPayments](https://developers.cloudpayments.ru/)
- Т-Касса: первичный платёж создаётся через `Init` с `Recurrent=Y` и обязательным `CustomerKey`. `RebillId` приходит в нотификации со статусом AUTHORIZED или CONFIRMED. Повторное списание — `Init` + `Charge` с `RebillId` без редиректа — [T-Bank Dev Portal: Init](https://developer.tbank.ru/eacq/api/init)
- Robokassa: первый платёж идёт с параметром `Recurring`, дочерние — через `https://auth.robokassa.ru/Merchant/Recurring` с `PreviousInvoiceID` и новым `InvoiceID` — [Robokassa: периодические платежи](https://docs.robokassa.ru/recurring/). Тестового режима у endpoint нет: SDK бросает исключение — [GitHub: robokassa/sdk-php](https://github.com/robokassa/sdk-php)
- Диадок: HTTP API для любого языка. Позволяет создавать, подписывать и отправлять акты, счета-фактуры и УПД в утверждённом XML, автоматически подписывать квалифицированной ЭП, отслеживать статусы и контрагентов — [Диадок API](https://www.diadoc.ru/integrations/api). С 01.04.2025 генерация и отправка УПД и СФ в предыдущих форматах недоступны, нужен формат 5.03 — [Диадок: переход на новый формат](https://www.diadoc.ru/articles/55319-perexod_na_novuyu_versiyu)
- В Filament можно подключить биллинг через Spark или собственную реализацию интерфейса `BillingProvider` с route action и subscription middleware — [Filament Tenancy](https://filamentphp.com/docs/5.x/users/tenancy)

### Inferences
- Архитектура модуля Billing:
  - интерфейс `PaymentGateway` с адаптерами под ЮKassa, CloudPayments, Т-Кассу и Robokassa;
  - приём webhooks через spatie/laravel-webhook-client;
  - идемпотентная обработка статусов;
  - dunning (повторы списаний) — scheduled jobs;
  - блокировка функций при неоплате — через Pennant или флаги тарифа;
  - в Filament — собственный `BillingProvider`.
- Сценарии оплаты:
  - **SMB** — ежемесячное автосписание с карты или по СБП;
  - **средний и крупный бизнес** — счёт с QR/реквизитами, оплата по безналу, закрывающие документы (акт или УПД) через Диадок API; альтернатива — ЭДО-оператор Saby/СБИС (не проверено).
- Автоплатежи ЮKassa требуют согласования с менеджером — это нужно заложить в план запуска.

### Gaps
- Не проверена доступность Paddle для российских продавцов и покупателей.
- Не проверены API Saby (СБИС), Контур.Эльбы и «СБП-подписок» у каждого провайдера.
- Комиссии провайдеров не собраны.
- Требования 54-ФЗ к чекам при B2B-оплатах картой и безналом в этой сессии не верифицированы.

## 13. Пределы Laravel: что со временем переписывать (например, на Go) и как заложить «швы» сейчас

### Takeaway
Laravel с Octane, скорее всего, хватит на первые годы. Кейсы уровня Sportmonks (600 млн запросов в неделю) показывают, что ограничивает обычно БД и архитектура, а не PHP. Кандидаты на вынос в Go:
- ядро процессинга checkout (quote, authorize, commit);
- вычисление правил;
- приём событий и чеков;
- диспетчер webhooks;
- realtime-шлюз.

Швы стоит заложить сразу:
- contract-first OpenAPI;
- изолированный модуль `Processing` за интерфейсом;
- инварианты ledger на уровне БД;
- outbox-события;
- ключи идемпотентности;
- декларативные правила (JSON), вычислимые на любом языке.

### Cited Findings
- Потолок на ядро: Laravel ~16,8 тыс. RPS против ~338 тыс. у Go Fiber и ~244 тыс. у Spring в TechEmpower R23 Fortunes (вторичная сводка) — [DEV: сводка R23](https://dev.to/tuananhpham/popular-backend-frameworks-performance-benchmark-1bkh)
- Octane даёт кратный прирост к FPM: 2,5–3,1× в одном замере, 4–5× в другом — [Deploynix](https://dev.to/deploynix/php-fpm-vs-laravel-octane-on-deploynix-real-world-performance-comparison-53gp); [EdgeServers](https://www.edgeservers.com.au/en/articles/laravel-octane-roadrunner-swoole)
- Fathom: «your database is going to be the bottleneck as you scale». При этом Laravel-ядро дополнили EU-прокси на Go — [Fathom](https://usefathom.com/blog/does-laravel-scale)
- Sportmonks: 600 млн запросов в неделю, пик 24 тыс. запросов к БД в секунду на Laravel, после переноса инфраструктуры (managed cache, БД и очереди) — [Laravel Customer Story](https://laravel.com/cloud/customer-stories/how-sportmonks-handles-600m-api-requests-a-week-on-laravel-cloud)
- FrankenPHP и RoadRunner — application-серверы на Go — [Octane docs](https://laravel.com/docs/13.x/octane)
- Strangler Fig: заменять систему постепенно, новые компоненты строятся «on top of, yet separate to the legacy code base» — [Martin Fowler](https://martinfowler.com/bliki/StranglerFigApplication.html)
- Transactional outbox даёт гарантированную публикацию событий при commit и требует идемпотентных потребителей — [microservices.io](https://microservices.io/patterns/data/transactional-outbox.html)

### Inferences
**Когда выносить.** Когда после Octane, кеширования правил и оптимизации БД checkout-эндпоинты не укладываются в SLO на целевом RPS. Другие поводы:
- стоимость CPU на запрос становится существенной статьёй расходов;
- нужны долгоживущие соединения или стриминг (приём событий касс, gRPC-стримы).

**Что выносить первым:**
1. `Processing`: calculate, authorize, commit, cancel, refund над ledger.
2. Движок правил (чистая функция «чек + контекст → начисления и скидки»).
3. Ingestion событий и чеков с высоким fan-in.
4. Диспетчер webhooks (много исходящих HTTP).

Кабинет, кампании, биллинг, интеграции и администрирование логично оставить на Laravel.

**Швы, которые нужны уже в монолите:**
- Публичный контракт `Processing` описан в OpenAPI (Scramble), а внутри монолита вызывается через интерфейс или DTO, а не через Eloquent-модели.
- Правила хранятся декларативно (JSON с версией схемы), к ним есть набор эталонных тест-векторов «вход → ожидаемый результат». Эти векторы потом прогоняются против Go-реализации.
- Инварианты ledger — в БД: CHECK, unique (`tenant_id`, `idempotency_key`), append-only без UPDATE и DELETE, сериализация по счёту. Бизнес-логики в Eloquent observers и model events нет: Go-сервис эти хуки не увидит.
- События из модулей идут через outbox с версионируемыми схемами (JSON Schema или Protobuf), чтобы потребитель мог быть на любом языке.
- Контекст арендатора и трассировки передаётся явно: заголовки, JWT-claims, W3C traceparent через OpenTelemetry.
- Контрактные тесты API и нагрузочные профили хранятся в репозитории и запускаются против любой реализации.
- Миграция по схеме strangler: shadow-трафик (дублирование и сравнение ответов) → канареечный процент арендаторов → полный переключатель, управляемый feature flag (Pennant) на уровне арендатора.

### Gaps
- Проверяемые кейсы миграции PHP → Go в российских компаниях (процессинг и лояльность) в этой сессии не найдены: лимит поиска исчерпан.
- Нет данных о фактической пропускной способности Laravel-процессинга лояльности (checkout с правилами и ledger) у российских вендоров. Возможности Laravel оценены только по косвенным кейсам: Sportmonks, SMS-SaaS, Fathom.
