Розробка SaaS-платформ
SaaS — це не просто «сайт із авторизацією та підпиской». Це набір інфраструктурних рішень, кожне з яких має нетривіальну реалізацію: multi-tenancy, біллінг, onboarding, feature flags, rate limiting, audit logs. Помилки в архітектурі на старті становляться дуже дорогими при масштабуванні.
Multi-tenancy: shared schema проти separate databases
Це перше архітектурне рішення, яке неможливо легко змінити після запуску — і саме тому його потрібно прийняти свідомо.
Shared schema (tenant_id на кожній таблиці) — найпоширеніший підхід. Всі арендатори живуть в одній базі даних, кожен запис позначений tenant_id. Простіше у обслуговуванні, мігрування застосовується один раз, менше операційної складності.
Проблема: витік даних між тенантами — це катастрофа. Один забутий WHERE tenant_id = ? у запиті — і користувач бачить чужі дані. У Laravel це вирішується через Global Scope на всіх моделях:
protected static function booted(): void
{
static::addGlobalScope('tenant', function (Builder $builder) {
$builder->where('tenant_id', TenantContext::current()->id);
});
}
Плюс — обов'язкові тести, які перевіряють: запит від тенанта A не може повернути дані тенанта B ні при яких умовах.
Separate databases — кожен тенант отримує свою схему або базу даних. Повна ізоляція даних, простіше відповідність вимогам GDPR та ISO 27001 (дані клієнта фізично відокремлені). Мінус: мігрування потрібно застосовувати до кожного тенанта послідовно, при 1000+ тенантів це операція на години.
Гібридний підхід — shared database для більшості тенантів, dedicated database для enterprise-клієнтів, які платять за ізоляцію. Це те, що роблять більшість зрілих SaaS-продуктів.
Наш стандартний вибір для нового SaaS — shared schema з жорсткою tenant isolation через глобальні скоупи та row-level security у PostgreSQL. RLS додає другий шар захисту на рівні бази даних, навіть якщо додаток припустить помилку:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::uuid);
Біллінг: підписки, trials, upgrades
Біллінг — один із найбільше недооцінених за складністю блоків. Типові ситуації, які потрібно обробляти:
- Upgrade у середині розрахункового періоду (prorata)
- Downgrade з негайним або відкладеним вступленням у силу
- Trial скінчився, користувач не додав карту — що відбувається з даними?
- Платіж провалився — grace period, dunning emails, блокування доступу
- Повернення коштів при скасуванні підписки
Stripe Billing закриває більшість цих сценаріїв з коробки — це те, що ми використовуємо за замовчуванням. Webhook-события: customer.subscription.updated, invoice.payment_failed, invoice.payment_succeeded, customer.subscription.deleted. Кожен обробляється ідемпотентно.
Idempotency key при створенні платежу — обов'язковий. Без нього retry logic на стороні клієнта може привести до подвійного списання.
Для ринків СНГ — інтеграція з ЮКасса або Tinkoff для підписок через recurring payments. Менш зручний API ніж Stripe, але охоплює вимоги локального законодавства.
Onboarding: від реєстрації до «aha moment»
Технічно onboarding — це wizard з персистентним станом, який неможливо випадково пропустити та неможливо пройти двічі.
Типова реалізація: таблиця onboarding_steps зі статусом кожного кроку для кожного користувача. Middleware перевіряє, завершено чи onboarding, та редиректить на незавершений крок. Після завершення — флаг у user settings, middleware перестає спрацьовувати.
Важливий нюанс: onboarding повинен показувати прогрес реального продукту, не абстрактні кроки. «Створіть перший проект» замість «Завершите налаштування акаунта (крок 3 з 7)».
Email-послідовність onboarding — окремий модуль. Drip-кампанія через Mailgun/SendGrid з умовною логікою: якщо користувач зробив ключову дію — наступне письмо не відправляється або змінюється. Інструменти: Customer.io, Loops, або власна черга задач з відкладеними jobs.
Feature flags та управління доступом
SaaS із кількома тарифними планами вимагає грануляного управління фічами: Free план бачить А, Pro бачить B та C, Enterprise бачить все плюс D.
Не робіть це через if ($user->plan === 'pro') розкиданими по всьому коду. Це стає непідтримуваним швидко.
Правильний підхід — feature flag система. Для Laravel: Gate + Policy з перевіркою через тарифний план, або окрема таблиця features з зв'язком до планів. Для фронтенду — контекст з флагами, завантажений при ініціалізації додатку.
Open source рішення: Growthbook або Unleash — дозволяють керувати флагами через UI, робити A/B тести, поступовий rollout.
Rate limiting та захист API
SaaS-платформа з публічним API повинна мати rate limiting. Без нього один агресивний клієнт може покласти всіх інших.
У Laravel — RateLimiter фасад або throttle middleware. Для складніших сценаріїв (різні ліміти по тарифним планам, ліміти по методах API) — Redis із sliding window counter:
Ліміти по плану: Free — 100 requests/hour, Pro — 1 000/hour, Enterprise — 10 000/hour. Заголовки X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset в кожному відповіді — це стандарт, клієнти на нього розраховують.
Моніторинг та audit logs
Audit log — обов'язковий компонент для SaaS, де кілька користувачів працюють із спільними даними. «Хто видалив цей проект?», «Коли змінилися налаштування біллінгу?» — без логу відповісти неможливо.
Таблиця audit_logs: user_id, tenant_id, action, subject_type, subject_id, old_values, new_values, ip_address, created_at. Індекси по (tenant_id, created_at) та (subject_type, subject_id).
У Laravel — Observers на ключових моделях або пакет owen-it/laravel-auditing.
Моніторинг додатку: Sentry для exception tracking, Grafana + Prometheus або Datadog для метрик, Loki для логів. Алерти на: error rate > X%, response time p95 > 2s, failed payments spike.
Архітектура для масштабування
MVP можна запустити на monolith — це нормально. Передчасна мікросервісна архітектура для SaaS на ранній стадії — це оверінжиніринг, який сповільнює розробку без реальної користі.
Monolith → Modular monolith → Microservices — правильна траєкторія при зростанні навантаження.
Горизонтальне масштабування моноліта на Laravel: Laravel Octane (Swoole/RoadRunner) прибирає overhead bootstrap на кожен запит, horizontal scaling через кілька інстансів за Nginx/HAProxy, Redis для кешів та черг, PostgreSQL із read replicas для читання.
Орієнтири за термінами
| Етап | Термін |
|---|---|
| MVP (core features + auth + billing) | 12–16 тижнів |
| Повноцінний продукт з admin panel | 20–28 тижнів |
| Enterprise SaaS з multi-tenancy + audit | 28–40 тижнів |
Вартість залежить від кількості ролей, складності біллінгової логіки, вимог до інтеграцій та рівня навантаження. Розраховується після детального discovery.







