На главную

Документация

Полное руководство по шаблону: от установки до production. Технические спеки в папке docs/ репозитория дополняют эту страницу.


Быстрый старт

Micro SaaS Starter — шаблон для запуска коммерческого веб-приложения на React Router 8, PostgreSQL, Better Auth, Mantine и YooKassa. Ниже — минимальный путь от клонирования до работающего dashboard.

  • Склонируйте репозиторий и выполните npm install

  • Скопируйте .env.example в .env и заполните DATABASE_URL и BETTER_AUTH_SECRET

  • Поднимите PostgreSQL и выполните npm run db:push

  • Запустите npm run dev и откройте http://localhost:5173

  • Зарегистрируйтесь через /auth/signup и откройте /dashboard

Для оплаты подключите тестовый магазин YooKassa (YOOKASSA_SHOP_ID, YOOKASSA_SECRET_KEY). Для AI-агентов — DEEPSEEK_API_KEY. Без этих ключей остальные части приложения работают: auth, демо-агенты, аналитика.

npm install
cp .env.example .env
npm run db:push
npm run dev

Структура проекта

Маршруты разделены на публичные (marketing) и защищённые (app). Публичные страницы — лендинг, блог, документация, privacy — живут под layout _marketing.tsx без проверки сессии. Всё внутри приложения — под _app.tsx с обязательной авторизацией.

ПутьНазначение

app/routes/

Маршруты React Router: страницы, loaders, actions

app/components/

React-компоненты UI

app/lib/

Серверная логика: auth, billing, analytics, AI, db

app/lib/config/

Тарифы, админы, тема — настройки в одном месте

docs/

Markdown-спеки для разработчиков (аналитика, биллинг)

tests/

Unit, component, integration и e2e тесты

Серверный код помечайте суффиксом .server.ts и импортируйте только из loaders, actions и других server-модулей. Клиентский бандл не должен тянуть подключение к БД или секреты.

Переменные окружения

Все секреты и URL задаются через .env. В production используйте переменные хостинга, не коммитьте .env в git.

ПеременнаяОписание

DATABASE_URL

Строка подключения PostgreSQL (обязательно)

BETTER_AUTH_SECRET

Секрет для подписи сессий, минимум 32 символа

BETTER_AUTH_URL

Публичный URL приложения (в dev — http://localhost:5173)

YOOKASSA_SHOP_ID

ID магазина YooKassa

YOOKASSA_SECRET_KEY

Секретный ключ YooKassa

DEEPSEEK_API_KEY

Ключ API для LLM-агентов

ADMIN_EMAILS

Email админов через запятую (доступ к /admin)

TOOL_APPROVAL_SECRET

Опционально: HMAC для tool approval агентов

TEST_BILLING_MOCK

true — мок checkout в тестах без реальной YooKassa

APP_URL / BETTER_AUTH_URL должен совпадать с доменом, на котором открывают приложение. Иначе ссылки в письмах сброса пароля и redirect после оплаты будут неверными.

База данных

Схема описана в app/lib/db/schema.ts через Drizzle ORM: пользователи и сессии Better Auth, подписки, платежи, события аналитики, учёт запусков агентов, очередь pg-boss.

  • npm run db:push — синхронизация схемы в dev (быстро, без истории)

  • npm run db:generate — сгенерировать SQL-миграцию после изменения schema.ts

  • npm run db:migrate — применить миграции (production)

  • npm run db:studio — веб-UI для просмотра таблиц

Подключение централизовано в app/lib/db/db.server.ts. Для операций «списать квоту + записать usage» используйте db.transaction — это предотвращает race condition при параллельных запросах к агентам.

Аутентификация

Better Auth обрабатывает регистрацию, вход, сброс пароля и сессии в PostgreSQL. Конфигурация — app/lib/auth/auth.server.ts. API-эндпоинты — /api/auth/*.

МаршрутНазначение

/auth/signup

Регистрация нового пользователя

/auth/login

Вход по email и паролю

/auth/forgot-password

Запрос ссылки сброса пароля

/auth/reset-password

Установка нового пароля по токену

Валидация форм — Zod-схемы в app/lib/validation/auth.schemas.ts. Защищённые маршруты проверяют сессию в loader _app.tsx. Админские страницы дополнительно сверяют email со списком ADMIN_EMAILS.

При успешном signup и login отправляются аналитические события signup_completed и login_completed, а анонимный visitorId связывается с userId (stitch).

Подписки и YooKassa

Тарифы описаны в app/lib/config/plans.ts: Daily (тест вебхуков), Pro и Enterprise с месячной и годовой оплатой. Цены, интервалы и agentRunsIncluded настраиваются в одном файле.

  • Пользователь выбирает план на /billing или /premium

  • Создаётся платёж в YooKassa, редирект на страницу оплаты

  • Webhook /api/yookassa/webhook подтверждает оплату и активирует подписку

  • Cron и loader проверяют expiresAt и инициируют продление

Для локальной отладки webhook используйте тестовый магазин YooKassa и проброс туннеля (ngrok) на localhost. В production принимайте webhook только с IP-адресов провайдера.

Страница /billing показывает текущий план, дату продления, историю платежей и остаток квоты агентов (AgentUsageMeter).

AI-агенты

Production-агенты доступны на /agents: support (поддержка, возвраты, KB) и incident (SRE on-call, расследование). Построены на Vercel AI SDK v7 с ToolLoopAgent и human-in-the-loop (toolApproval) для опасных действий.

  • Конфигурация — app/lib/ai/agents/config.ts

  • API — POST /api/agents/:slug (стриминг, учёт квоты)

  • Демо без списания квоты — /demo/:slug на mock-данных

  • Одобрение крупных возвратов и remediation — в UI чата

Каждый тариф включает agentRunsIncluded запусков за период подписки. Учёт в app/lib/usage/usage.server.ts: reserve → commit/release. При исчерпании квоты API возвращает 402 с предложением апгрейда.

Добавление своего агента: скопируйте support-agent.ts, определите инструменты с Zod-схемами, зарегистрируйте slug в config.ts.

Аналитика

First-party аналитика без сторонних скриптов. События пишутся в PostgreSQL через React Router instrumentation (сервер + клиент) и ручные track-вызовы.

СобытиеКогда

page_view

SSR-загрузка и клиентские переходы

loader / action / fetcher

Завершение data-операций маршрута

signup_completed / login_completed

Регистрация и вход

agent_viewed / agent_message_sent

Страница агента и API

checkout_started / payment_succeeded

Воронка оплаты

Посетитель идентифицируется cookie analytics_vid и analytics_sid. После входа visitorId связывается с userId. Дашборд — /admin/analytics (DAU, воронка, топ страниц, журнал).

Песочница /analytics-sandbox — для отладки track() без искажения production-метрик. Подробнее: docs/analytics.md в репозитории.

import { track } from "~/lib/analytics/track.client";

track("pricing_plan_selected", { planId: "pro-month" });

Админ-панель

Раздел /admin доступен только пользователям из ADMIN_EMAILS. Включает сводку метрик, управление пользователями и аналитический дашборд.

СтраницаСодержимое

/admin

Сводка: регистрации, подписки, события за сутки

/admin/users

Список пользователей, тариф, статус подписки

/admin/analytics

DAU, воронка, графики, журнал событий

Daily digest — email-отчёт админам за вчера (cron через pg-boss). Требует настроенный SMTP. Трафик админов исключён из аналитики, чтобы разработка не искажала метрики.

Тестирование

КомандаЧто запускает

npm test

Vitest: unit-тесты рядом с кодом

npm run test:component

Тесты React-компонентов

npm run test:integration

Loaders/actions с тестовой БД

npm run test:e2e

Playwright: сценарии в браузере

npm run test:ci

Vitest + e2e (CI pipeline)

Перед PR прогоните npm run typecheck и npm run lint. Seed-данные для integration-тестов — tests/helpers/seed.ts. E2E использует TEST_BILLING_MOCK для мока оплаты без реальной YooKassa.

Деплой

  • npm run build && npm run start — production-сборка

  • Примените db:migrate на production БД (не db:push)

  • Зарегистрируйте webhook YooKassa на /api/yookassa/webhook

  • Убедитесь, что pg-boss workers стартуют (entry.server.tsx)

  • Настройте HTTPS, алерты на 5xx и бэкапы PostgreSQL

Staging: отдельный инстанс с тестовым магазином YooKassa. После выката пройдите smoke test: регистрация → оплата → сообщение агенту → проверка /admin/analytics.

Блог (Velite)

Статьи блога — Markdown (.md) и MDX (.mdx) в content/blog/. Velite собирает две коллекции (posts и postsMdx) в .velite/ с типами Post и PostMdx. Локальные картинки копируются в public/static/; для placeholder можно указать внешний URL.

  • Markdown: content/blog/my-post.md — content рендерится в HTML на этапе сборки

  • MDX: content/blog/my-post.mdx — code компилируется в React; компоненты вроде BlogCallout подключаются в BlogMdxContent

  • Опционально cover: https://… в frontmatter — обложка над текстом статьи

  • npm run content:build — пересобрать контент вручную

  • RSS, sitemap и prerender подхватывают .md и .mdx автоматически

---
title: "Заголовок"
slug: my-post
date: "6 июля 2026"
publishedAt: 2026-07-06
excerpt: "Краткое описание"
cover: https://example.com/hero.png
---

![Схема](https://example.com/diagram.png)

<BlogCallout title="Совет">
Короткая заметка для читателя.
</BlogCallout>

Справочник команд

# Разработка
npm run dev
npm run typecheck
npm run lint

# База данных
npm run db:push
npm run db:generate
npm run db:migrate
npm run db:studio

# Тесты
npm test
npm run test:e2e
npm run test:ci

# Production
npm run build
npm run start

Не нашли ответ? Загляните в блог или на страницу релизов.