Пошагово разберём, как из user stories, сущностей и workflow получить схему БД: таблицы, связи, ключи и ограничения — и где помогает AI‑рассуждение.

Схема базы данных — это не просто набор таблиц. Это зафиксированные решения о том, какие данные хранятся, как они связаны и какие правила нельзя нарушать. Обычно в схему входят таблицы (сущности), поля (атрибуты), первичные и внешние ключи, ограничения (уникальность, обязательность, допустимые значения), а также правила удаления/обновления связанных записей.
Если строить схему «с головы» или только по доменным терминам, легко пропустить критичные детали: статусы, исключения, роли, условия видимости данных. Когда же схема выводится из user stories и workflow, она опирается на реальные сценарии — то есть на то, что пользователи действительно делают и что бизнес обязан проверять.
User stories отвечают на вопрос «зачем и какую ценность даёт функция» и часто содержат проверки: «пользователь видит только свои заявки», «нельзя оплатить дважды». Сущности и атрибуты дают «что именно хранить» (Заявка, Платёж, Клиент). Workflow показывает «когда и как данные меняются»: какие состояния возможны, какие переходы разрешены, какие события должны фиксироваться.
Вместе это превращает схему из абстрактной модели в инструмент исполнения требований: ограничения и связи отражают правила бизнеса, а не вкусовые предпочтения команды.
Минимальный набор артефактов:
Хорошая схема проверяется четырьмя критериями:
User story — это не только про интерфейсы и функции. В ней почти всегда спрятаны будущие таблицы, поля и ограничения. Задача — читать историю «как аналитик данных»: что хранить, как отличать сущности, и где нужны статусы и правила.
Удобный формат: роль → цель → ценность плюс критерии приёмки. Именно критерии часто содержат «точные слова» для модели данных: какие поля обязательны, какие проверки выполняются, когда что считается успешным.
Пример (схематично):
Как менеджер, я хочу подтверждать заявку, чтобы зафиксировать решение и уведомить клиента.
Из одной фразы уже видно: есть объект «заявка», действие «подтверждать», и результат «решение/уведомление» (а значит — событие, статус или запись истории изменений).
Быстрый разбор текста:
Полезный вопрос к каждой истории: «Что нужно показать, найти, отфильтровать или доказать аудитору?» Всё это почти всегда требует хранения данных.
Слова вроде «активный», «подтверждённый», «черновик» часто маскируют разные варианты:
status со справочником значений).is_active), если вариантов ровно два и это не этап процесса.Проверка: если в критериях приёмки есть «показать список всех изменений» или «откатить», одного поля статуса обычно недостаточно.
Используйте короткую карточку на каждую найденную сущность:
customer_id обязателен; approved_at заполняется только при status=approvedТакой шаблон дисциплинирует чтение историй: вы не спорите «про таблицы», вы уточняете смысл слов — и модель данных получается естественным продолжением требований.
На этом шаге вы переводите «слова из требований» в структуру данных. Хороший ориентир: если предметное слово фигурирует в историях как объект действий (создать, изменить, отправить, согласовать), скорее всего это кандидат в сущность (таблицу). Если слово описывает свойства объекта (дата, сумма, статус), это атрибут (поле).
Начните с выписки существительных из user stories и экранов: «заявка», «пользователь», «комментарий», «платёж». Затем разделите их на две группы.
Основные сущности — живут долго и участвуют в процессах: Заказ, Заявка, Клиент, Документ.
Справочники — ограниченные наборы значений, которые удобно стандартизировать: статусы, типы, категории, причины отмены, валюты. Справочники полезны тем, что уменьшают разнобой («Отменён», «отмена», «cancelled») и упрощают отчёты.
Проверка здравого смысла: если значение меняется редко и используется в разных местах — это почти всегда справочник.
Для каждого поля фиксируйте не только название, но и «правила хранения»:
Это превращает расплывчатое «пользователь указывает сумму» в конкретику: amount NUMERIC(12,2) NOT NULL CHECK (amount >= 0).
Дальше решите, чем однозначно «называется» запись.
На практике часто используют ID как первичный ключ, а естественные уникальные значения — как отдельные поля с ограничением уникальности.
Если объект просто «находится в статусе», достаточно поля status_id. Но если важно отвечать на вопросы «когда и кто изменил», «сколько времени был на этапе», «сколько раз возвращали на доработку» — храните историю изменений отдельной таблицей (например, request_status_history), где каждая строка — событие: статус, время, инициатор, комментарий.
Правило: состояние — для текущей картины, события — для аудита, аналитики и спорных ситуаций.
Связи — это место, где требования перестают быть «про тексты» и становятся про данные: кто с кем связан, сколько раз, можно ли «без пары», и что происходит при удалении или изменении.
Ищите в user stories формулировки, которые намекают на количество:
Проверяйте, не скрыта ли кардинальность в исключениях: «обычно один, но иногда несколько» — это уже 1:N.
Для M:N почти всегда создают таблицу связей (join table). Важно: связь часто имеет собственные атрибуты, которые нельзя корректно хранить ни в одной из сторон:
Тогда таблица связи становится «полноценной сущностью» (например, team_membership).
Опциональность отвечает на вопрос: может ли запись существовать без связанной записи?
order -> payment опциональна.order_item -> order обязательна.Дальше — поведение при удалении: в бизнес‑системах часто правильнее архивировать (soft delete), чем физически удалять. Если удаление разрешено, заранее определите правило: запрещаем, каскадно удаляем или «отвязываем».
Внешние ключи нужны там, где связь должна быть истинной всегда (чтобы не появлялись «сироты»). Каскады применяйте осознанно:
ON DELETE RESTRICT/NO ACTION — безопасно для важных сущностей (нельзя удалить родителя, пока есть дети).ON DELETE CASCADE — уместно для явно зависимых данных (например, позиции черновика).ON DELETE SET NULL — подходит, если связь опциональна и запись может жить дальше без привязки.Хорошее правило: каскад — это про техническую зависимость, а не про «удобно удалить всё одним махом».
Workflow — это не только «как работает процесс», но и точная подсказка, какие данные должны появляться, меняться и сохраняться во времени. Если читать шаги процесса последовательно, становится видно жизненный цикл объекта: что считается созданием, что — обновлением, где нужен след аудита, а где достаточно текущего состояния.
Каждый шаг отвечает на вопросы: какие поля нужны прямо сейчас и какие должны быть заполнены обязательно. Например, если шаг «Отправить заявку» возможен только после выбора тарифа и адреса, значит эти атрибуты либо обязательны в записи, либо фиксируются как отдельные связанные сущности до финальной отправки.
Практический приём: рядом с каждым шагом workflow выпишите минимальный набор данных, без которых шаг невозможен. Это быстро выявляет:
Workflow подсказывает, какие таблицы затрагиваются на каждом этапе. Часто выясняется, что «одна сущность» на словах на деле распадается на несколько таблиц: основная запись + события + вложения/комментарии.
Важно различать «удаление» как действие пользователя и физическое удаление в БД. Если в процессе есть «Отмена» или «Архивирование», обычно нужна логическая деактивация (например, deleted_at, canceled_at) и запрет на дальнейшие переходы.
Статусы в workflow — это требования к модели данных. Минимальный набор:
status),updated_by),updated_at).Если бизнесу важно объяснять, почему состояние сменилось, добавляется status_reason (справочник) и/или таблица событий состояния (журнал переходов). Журнал полезен, когда нужны отчёты «сколько времени было в статусе» или разбор спорных случаев.
Исключения почти всегда означают дополнительные данные:
attempt_no) или отдельная сущность «попытка/версия заявки».Так workflow превращается в набор проверяемых требований: какие статусы допустимы, какие переходы разрешены, и какие метки времени/авторы должны фиксироваться для каждого изменения.
Нормализация — это не про «академические правила», а про понятную цель: чтобы одно и то же значение хранилось в одном месте и не расходилось в разных строках и таблицах. Тогда проще обновлять данные, меньше ошибок в отчётах и яснее границы ответственности сущностей.
На практике достаточно держать в голове три шага:
Чаще всего дубликаты появляются из-за двух ошибок:
Повторяющиеся группы: phone1/phone2/phone3, address_1/address_2 или «10 колонок под характеристики». Обычно это отдельная сущность (Телефон, Адрес, Характеристика).
Смешение разных сущностей в одной таблице: когда в «Пользователе» лежат и реквизиты компании, и параметры доставки, и настройки уведомлений. Лучше разделить: Пользователь, Компания, Адрес, Настройки — и связать ключами.
Денормализация уместна, когда чтение важнее записи: витрины для отчётов, агрегаты для быстрых списков, кэшируемые поля (например, order_total). Контроль простой:
Возьмите 3–5 сценариев и «прогоните» их по схеме:
Если для сценария приходится обновлять одно и то же значение в нескольких таблицах — вы нашли источник будущих дубликатов.
AI может ускорить проектирование схемы БД, если использовать его как «второго аналитика», а не как источник истины. Самая полезная роль — быстро разложить пользовательские истории и workflow на структурированные сущности, связи и ограничения, а затем помочь проверить, не пропущено ли что-то важное.
Отдельно полезно, когда AI встроен не «в вакуумный чат», а в рабочий контур продукта: с планированием, версиями и быстрым прототипированием. Например, TakProsto.AI как vibe‑coding платформа позволяет в режиме диалога набросать структуру сущностей, затем сразу поднять черновой backend (часто на Go + PostgreSQL) и проверить модель на реальных сценариях — запросами, формами, ролями. Это не отменяет аналитики, но сильно сокращает цикл «требование → схема → прототип → уточнение».
Практичный режим работы выглядит так:
Извлечение понятий: из текстов историй AI предлагает кандидатов на сущности, атрибуты, словарь терминов и синонимы (например, «клиент» vs «покупатель»).
Построение связей: предлагает кардинальности (один-ко-многим, многие-ко-многим), ключи и справочники, подсказывает места, где нужна отдельная таблица для связей.
Проверка противоречий: ищет конфликтующие формулировки («заказ можно отменить после оплаты» vs «после оплаты нельзя»), несогласованность статусов и событий.
Генерация вариантов: предлагает несколько моделей (например, статусы как enum/справочник/таблица истории событий) с плюсами и рисками.
Формулируйте запросы так, чтобы ответ был проверяемым:
Ведите рядом со схемой короткий журнал: вопрос → принятое решение по умолчанию → риск → кому уточнить. Это снижает вероятность, что «удобная догадка» незаметно станет требованием.
AI может уверенно «додумывать» отсутствующие правила, путать термины и предлагать ограничения, которые ломают реальные процессы. Поэтому каждую рекомендацию стоит привязывать к источнику: истории, регламенту, примеру данных. Финальный контроль — за вами: проверка на реальные сценарии, тестовые записи и согласование с владельцем процесса (см. также раздел про трассируемость требований: /blog/traceability).
Трассируемость нужна, чтобы в любой момент ответить на два вопроса: «почему это поле/таблица существует?» и «какие требования сломаются, если мы это изменим?». В проектировании БД она превращает набор user stories и описаний процесса в проверяемую структуру: история → данные → правила → тесты.
Практичный формат — фиксировать для каждого элемента схемы его источник и связанные ограничения.
Пример:
orders.status, orders.cancelled_at, orders.cancel_reasonstatus IN ('new','paid'); при отмене cancelled_at NOT NULLstatus='shipped' должна вернуть ошибку; успешная отмена должна проставить дату и причинуТак вы связываете смысл (история) с моделью (поля) и проверкой (тесты), а не держите это в голове.
Сделайте простую матрицу (в таблице или wiki):
Если находится таблица/поле без историй — это сигнал: либо забыли требование, либо это «лишнее». Если есть история без данных — значит, модель не покрывает сценарий.
Введите правило ревью: каждое поле должно иметь источник (история / шаг workflow / бизнес‑правило / требование безопасности). Быстрые проверки:
created_at) помечены как технические и объяснены.Трассируемость особенно помогает при правках:
Так изменение requirements не превращается в «тихую» поломку данных: вы видите последствия до выката и можете заранее обновить тесты и ограничения.
Модель данных — это не только «как хранить», но и «кому можно видеть и менять». Если заложить безопасность в схему сразу, вы уменьшите риск утечек и упростите проверку соответствия требованиям.
Начните с ролей из user stories: «оператор видит заявки», «менеджер утверждает», «админ настраивает справочники». Это напрямую превращается в матрицу доступа (CRUD по сущностям).
На уровне БД стоит закрепить:
app_readonly, app_operator, app_admin),Аудит нужен там, где по процессу важно доказать «кто сделал действие». Для этого в ключевых таблицах держат поля created_at, created_by, updated_at, updated_by (ссылки на пользователя/сервис).
Из требований выделите, какие поля действительно нужны процессу. Если поле не влияет на решения и коммуникации — не храните его.
Для согласий и правовых оснований удобна отдельная сущность, например consent, где фиксируются: тип согласия, дата/канал получения, версия текста, срок действия/отзыва.
Сроки хранения лучше выражать явно: retention_until или статус «к удалению», чтобы можно было автоматизировать очистку.
Маскирование/псевдонимизация отражается в схеме через:
Если важно видеть «что именно», одного updated_at мало. Добавьте журнал изменений (audit_log) с полями: сущность, record_id, операция, автор, время, а также снимок изменённых полей (часто в JSON). Так проще разбирать инциденты и спорные ситуации.
Правило: всё, что защищает данные от противоречий, лучше закреплять в БД.
NOT NULL, уникальность, базовые проверки (CHECK, допустимые статусы), каскады.Так схема становится частью контроля требований, а не просто хранилищем.
Производительность лучше всего «вытаскивается» не из абстрактных правил, а из пользовательских сценариев: какие экраны открываются чаще, что люди ищут, как сортируют, какие списки обновляются каждые секунды. Поэтому индексы — это продолжение user stories в виде конкретных шаблонов запросов.
Соберите 10–20 ключевых запросов из сценариев и макетов экранов. Для каждого зафиксируйте: таблицы, условия WHERE, сортировку ORDER BY, соединения JOIN, пагинацию.
Например, история «менеджер видит список заказов клиента за период» обычно означает фильтр по customer_id и диапазону дат. Индекс под такой запрос — не «на всякий случай», а ровно под условие: (customer_id, created_at).
Составные индексы работают, когда порядок колонок совпадает с типичным использованием:
tenant_id в мультиарендности).status).created_at), если сортировка почти всегда одинаковая.Если экран допускает «поиск по строке», решите заранее: это префиксный поиск (подойдёт индекс по полю) или подстрока/морфология (нужен отдельный поисковый механизм или полнотекстовый индекс). Не пытайтесь лечить любой поиск обычным B-tree индексом.
Из workflow видно, где будет много записей: события, логи статусов, история изменений, таблицы «многие-ко-многим». Это кандидаты в «горячие» — частые вставки и чтения.
Партиционирование имеет смысл как идея, когда сценарии почти всегда ограничены по времени (например, «показать события за неделю»), а объём растёт быстро. Тогда партиция по дате может упростить обслуживание и ускорить запросы.
Каждый индекс ускоряет чтение, но замедляет запись и увеличивает стоимость обновлений. Поэтому правило простое: индекс создаётся под конкретный сценарий и измеримый выигрыш.
Также помните про целостность: уникальные индексы и внешние ключи помогают данным оставаться правильными, но тоже стоят ресурсов. Важно согласовать ожидания: что критичнее в продукте — скорость списков или надёжность данных при массовых операциях.
Хорошо выведенная схема БД ценна ровно настолько, насколько её можно проверить и согласовать. Поэтому результат важно упаковать так, чтобы его одинаково понимали аналитик, разработчик и бизнес.
Сделайте ER‑диаграмму «читаемой» без обучения нотациям. Достаточно трёх вещей:
Если нужно показать сложный кусок (например, N–M), лучше явно добавить связующую сущность (например, OrderItem) и подписать, какие поля составляют уникальность. Больше символов обычно только мешают обсуждению. Базовые принципы можно вынести в отдельную заметку: /blog/er-diagram-basics.
Словарь данных снимает 80% вопросов на ревью. Для каждого поля фиксируйте:
Например: order.status — перечисление; значения: draft, paid, cancelled; правило: переходы только по workflow; нельзя вернуть из paid в draft.
Чтобы не потерять логику вывода «из требований в данные», держите один сквозной шаблон:
цель → сущности → связи → ограничения → сценарии.
В конце добавьте короткий раздел «как этим пользоваться»: где лежит диаграмма, где словарь, кто утверждает изменения и как обновлять при новых user stories. Если вы оформляете это как часть платного пакета работ, уместно дать ссылку на условия: /pricing.
Перед тем как «заморозить» схему, полезно провести короткую проверку на полноту и непротиворечивость. Это дешевле, чем чинить миграции после старта разработки, и понятнее для бизнеса, чем обсуждение таблиц «на глаз».
Проверьте, что каждую таблицу можно объяснить одной фразой из предметной области (а не из реализации), и что за неё есть владелец в требованиях.
Чек‑лист:
Workflow чаще всего ломается не на основных ветках, а на отменах, возвратах, повторных попытках и параллельных действиях.
Чек‑лист:
status), а что — как история событий (таблица аудита/событий).Если заранее не проверить отчётные сценарии, может выясниться, что нужных разрезов и дат в данных нет.
Чек‑лист:
Сделайте небольшой прототип запросов по 5–10 главным пользовательским сценариям, сгенерируйте тестовые данные (в том числе крайние случаи) и проведите короткое ревью схемы со стейкхолдерами: бизнес, разработка, аналитика, безопасность. Это обычно выявляет последние пробелы до утверждения.
Если хочется ускорить этот этап, удобно совмещать проектирование и прототипирование: в TakProsto.AI можно в «режиме планирования» описать сущности, статусы и правила из историй, затем быстро собрать рабочий черновик приложения (web/сервер/мобильное) и проверить схему реальными запросами и ролями. А когда модель стабилизируется — выгрузить исходники, включить деплой/хостинг, настроить свой домен и держать под рукой снапшоты с откатом (rollback) для безопасных итераций.
Лучший способ понять возможности ТакПросто — попробовать самому.