← Все проекты уровня 13
Уровень 13 · Сервис для нескольких организацийВариант A

CRM

Многопользовательская CRM с организациями, ролями, клиентами, сделками, аудитом и квотами.

Техническое задание

Данные и доступ

Реализуйте REST CRM с организациями, пользователями, клиентами и сделками. Организация tenant имеет неизменяемый ID. Членство пользователя в организации содержит одну роль: owner, manager или reader. Owner управляет членствами и настройками, создаёт, читает, меняет, архивирует и экспортирует записи. Manager создаёт и меняет клиентов и сделки, читает записи и аудит, но не меняет членства, квоты и настройки. Reader читает записи и аудит, не меняя их и не экспортируя. Каждая запись содержит tenant_id; сервер берёт текущий tenant из проверенного членства, а не из тела запроса. Для каждой операции, включая get-by-ID, поиск, count, вложенные ресурсы и экспорт, tenant-фильтр обязателен. Чужая запись и отсутствующая запись одинаково отвечают 404.

REST-контракт

POST /api/v1/organizations создаёт организацию и её владельца. POST/GET /api/v1/organizations/{org_id}/members и PATCH/DELETE для member ID управляют членствами только owner. POST/GET /api/v1/organizations/{org_id}/clients, GET/PATCH/DELETE /clients/{client_id}, и соответствующие /deals маршруты управляют клиентами и сделками. GET /clients/{id}/deals показывает только связанные записи текущего tenant. GET /audit и POST /exports доступны owner; manager читает audit. Все списки имеют limit 1–100, курсор по ключу; сортировка по created_at DESC, id DESC. Клиент содержит display_name (1–160 символов), email optional и status active/archived. Сделка содержит client_id, title (1–160), amount_minor, currency RUB/USD/EUR, stage lead/qualified/proposal/won/lost и expected_close_date. Сумма неотрицательна, валюта не меняется после won, client должен быть из той же организации.

Квоты, аудит и транзакции

По умолчанию tenant ограничен 10 активными пользователями и 10 000 незакрытыми клиентами плюс сделками вместе; owner может видеть usage и текущие пределы через GET /settings/usage. При превышении лимита возвращается 409 quota_exceeded. Параллельное создание последнего разрешённого объекта должно сериализовать проверку и изменение квоты так, чтобы успешное число не превышало предел. Архивация освобождает quota slot, но не удаляет историю. Удаление клиента с незакрытой сделкой возвращает 409 open_deals_exist; после закрытия сделки клиент архивируется. Экспорт включает только активные поля текущего tenant, максимум 5000 строк, и создаёт запись аудита.

Каждое изменение пишет actor, tenant, действие, объект, время UTC и список изменённых имён полей в audit_log. Данные и аудит фиксируются одной транзакцией. Полные email и другие значения не копируются в аудит. PostgreSQL используется через SQL без ORM и миграции; FK включают tenant ID, индексы начинаются с tenant_id. Контекст каждого запроса задаёт SQL timeout 3 секунды. Локальный seed создаёт owner, manager и reader для каждой организации с фиксированными токенами; token принимается только из Authorization header, actor и tenant выводятся из него, секреты не логируются. Ошибка БД превращается в безопасный 500.

Структура программы

Предметные правила проверяют роли, квоты, связи и аудит отдельно от HTTP-обработчиков и SQL-запросов; обе организации проходят через единые правила доступа. main.go только загружает конфигурацию, связывает зависимости и управляет запуском. Пакеты без циклов, общих utils и интерфейсов без потребителя. README показывает зависимости; тесты ядра без HTTP/БД, интеграционные отдельно.

Приёмка

Офлайн-тесты создают две организации, повторяющиеся display name и пользователей всех ролей. Они пытаются читать, менять, удалять, считать и экспортировать чужие записи через каждый маршрут. Тесты подтверждают матрицу ролей, 404 без утечки существования, привязку клиента и сделки к одному tenant, атомарность аудита и квоты в конкурентном создании. Критерии готовности: ни одно чужое значение не появляется в API/export; каждое успешное изменение имеет одну запись аудита; при гонке квоты не превышены и отказ не оставляет частичную запись.

Критерии готовности

Ожидаемый результат

Проверяемый результат

  • README показывает границы и направление зависимостей; main.go только связывает конфигурацию и запуск; модульные тесты ядра обходятся без HTTP и БД, интеграционные тесты отделены.
  • Запускаемое Go REST приложение с PostgreSQL и миграциями создаёт организации, членства, клиентов, сделки и аудит.
  • Роли owner, manager и reader реализуют указанную матрицу; все маршруты и экспорт изолированы по tenant.
  • Клиент и сделка связаны только внутри tenant, а ошибочный cross-tenant client_id возвращает 404.
  • Аудит создаётся атомарно с изменением и содержит имена изменённых полей без копирования контактов.
  • Конкурентная попытка превысить квоту оставляет число записей в пределах 10 пользователей и 10 000 активных сущностей.
  • Детерминированные тесты проверяют обе организации, все роли, экспорт, get-by-ID, поиски, счётчики, аудит и квоты.
  • Локальная инструкция содержит bearer fixture, миграции, таймауты и команды запуска.
  • Экспорт ограничен 5000 строками, а архивные записи сохраняются в аудируемой истории.