~/VibeHandbook

Глава 12 · 02

Кейс 2: Небольшой SaaS-инструмент с авторизацией + базой данных

Идея

Дизайнер-фрилансер хотела приватный дашборд, чтобы вести учёт оплачиваемых часов по каждому клиенту и экспортировать месячный CSV. Ничего вычурного, но это требовало учётных записей (чтобы её данные были только её) и сохранения данных.

Спецификация

Авторизация и база данных повышают ставки, поэтому спецификация стала более конкретной насчёт границ:

Веб-приложение с входом, где пользователь может: зарегистрироваться
/ войти по email, создавать клиентов, вносить записи времени (дата,
клиент, часы, заметка), видеть таблицу записей с фильтром по месяцу
и скачивать этот месяц как CSV. Каждый пользователь всегда видит
только свои данные. Удобно на мобильных.

«Каждый пользователь всегда видит только свои данные» выглядит как строка про UX. На самом деле это модель безопасности всего приложения, сжатая в несколько слов. Назвав это в спецификации, мы могли указывать на эту строку каждый раз, когда AI начинал дрейфовать.

Стек

Для одиночного мейкера выигрышный ход — это стек, где авторизация и база данных являются управляемыми сервисами, а не кодом, который вы пишете. Мы выбрали приложение на Next.js, задеплоенное на serverless-хостинге, с размещённой базой данных Postgres и готовым провайдером авторизации, который берёт на себя вход по email, сессии и сброс паролей за нас. Меньше кода, в котором можно ошибиться, — меньше кода, в котором AI может ошибиться за нас. Авторизация в особенности — это категория, которую почти никогда не хочется писать вручную вместе с AI: режимы отказа тихие, радиус поражения — все аккаунты, а у управляемого провайдера крайние случаи обкатаны миллионами входов.

Ключевые промпты

Мы дали шаблону самого провайдера авторизации сделать тяжёлую работу, а затем направили AI наложить доменную логику поверх:

Мы используем стартер для Next.js от [провайдер авторизации].
Добавь схему Postgres с двумя таблицами: clients (id, user_id, name)
и time_entries (id, user_id, client_id, date, hours, note). Каждый
запрос ОБЯЗАН фильтровать по id залогиненного пользователя из сессии.
Сгенерируй миграцию и типизированные функции доступа к данным.

Строка «ОБЯЗАН фильтровать по user_id» была самым важным предложением во всём проекте. Мы повторяли это ограничение почти в каждом промпте, который касался данных, потому что самый страшный баг в многопользовательском приложении — это когда один пользователь видит строки другого. Когда печатаешь, повтор ощущается избыточным; именно эта избыточность вас и спасает, потому что у модели нет памяти о том, насколько важно это ограничение, в разных отдельных промптах.

Для экспорта:

Добавь маршрут /api/export, который принимает месяц (YYYY-MM),
вытягивает time_entries залогиненного пользователя за этот месяц,
соединённые с именами клиентов, и стримит скачивание CSV. Отклоняй
запрос, если нет валидной сессии.

Препятствие

При тестировании мы создали две учётные записи и обнаружили, что аккаунт B мог видеть клиентов аккаунта A в выпадающем списке. Это ровно тот баг, которого мы боялись. Вместо того чтобы просить AI «исправить это», мы сначала заставили его доказать проблему:

Аккаунт B видит клиентов аккаунта A. Покажи мне каждый запрос к базе
данных в кодовой базе, который читает таблицу clients, и для каждого
скажи, фильтрует ли он по user_id из сессии. Пока ничего не исправляй
— просто проведи аудит.

Аудит выявил один запрос — загрузчик выпадающего списка, — который был написан до того, как мы добавили ограничение, и проскользнул мимо. Мы попросили его добавить недостающий фильтр, а затем запросили защиту:

Добавь единый хелпер, через который проходит каждое чтение, который
принимает сессию и подставляет фильтр по user_id, чтобы ни один
будущий запрос не мог про него забыть. Отрефактори существующие
запросы под его использование.

Это превратило разовое исправление в структурную гарантию. Затем мы сделали гарантию проверяемой, потому что защита, которую нельзя проверить, — это просто надежда:

Напиши тест, который создаёт двух пользователей, заставляет каждого
создать клиента, а затем проверяет, что сессия пользователя A никогда
не может прочитать клиента пользователя B ни через одну из функций
доступа к данным.

Урок: когда AI вносит баг безопасности, не просто латайте конкретный случай — направьте его на устранение категории ошибки, а затем заприте эту категорию тестом, который громко падает, если кто-то откроет её снова.

Запуск

Мы засеяли тестовый месяц данных, экспортировали CSV, открыли его в таблице, чтобы убедиться, что числа и кодировка верны, затем поставили надёжный пароль базы данных и ротировали учётные данные из любых локальных файлов. Мы задеплоили на serverless-хостинг, добавили продакшен-переменные окружения в его панели и дали ей URL. Она сама прошла онбординг с реальной регистрацией. Вся сборка заняла выходные.

Хотите офлайн-версию?

Получите PDF + EPUB + скачиваемую библиотеку промптов + обновления версий.

$ Получить PDF — $39