From 952ebae334323c798469f68ed92d92a28f027dcb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 21 Mar 2026 21:27:50 +0000 Subject: [PATCH] Add detailed project implementation plan Co-authored-by: Igor Lekomtsev --- docs/plan/detailed-development-plan.md | 1065 ++++++++++++++++++++++++ 1 file changed, 1065 insertions(+) create mode 100644 docs/plan/detailed-development-plan.md diff --git a/docs/plan/detailed-development-plan.md b/docs/plan/detailed-development-plan.md new file mode 100644 index 0000000..c8759e0 --- /dev/null +++ b/docs/plan/detailed-development-plan.md @@ -0,0 +1,1065 @@ +# Детальный план разработки SaaS-платформы управления ресурсами + +## 1. Назначение документа + +Этот документ превращает исходный `docs/plan.md` в подробный исполнимый план. Он нужен для другой модели, чата или разработчика, чтобы можно было: + +- понять продуктовую цель без дополнительного контекста; +- развернуть архитектуру проекта; +- реализовать MVP по этапам; +- не потерять критичные бизнес-правила; +- проверять готовность каждого этапа по явным критериям. + +Документ исходит из следующих вводных: + +- фронтенд: `Next.js`, `shadcn/ui`, `Zod`, `Formik`, `Tailwind CSS`, `Biome`, `FSD`; +- бэкенд: монолитный `Nest.js` с multitenant-архитектурой; +- БД: `Postgres`; +- авторизация: `Supabase`; +- продукт: SaaS для компаний, которые управляют своими ресурсами и арендой внутри своего tenant. + +## 2. Цель MVP + +Собрать multitenant-систему, в которой: + +1. одна учетная запись пользователя может быть связана с несколькими компаниями; +2. каждая компания существует как отдельный tenant; +3. компания может пройти онбординг через заявку; +4. модераторы компании управляют пользователями, ролями и ресурсами; +5. обычные пользователи могут просматривать доступные ресурсы и отправлять заявки на аренду; +6. поддержка внутри tenant подтверждает или отклоняет заявки; +7. пользователь видит историю и календарь своих аренд; +8. система отправляет email-уведомления и создает события в Google Calendar; +9. модераторы видят статистику по использованию ресурсов. + +## 3. Принципы реализации + +### 3.1 Архитектурные принципы + +- Один backend-монолит обслуживает все tenant. +- Tenant-изоляция обеспечивается на уровне данных и авторизации. +- Пользователь хранится глобально, а членство в компаниях хранится отдельно. +- Бизнес-правила доступа строятся не только на роли, но и на принадлежности к tenant, статусе учетной записи и явных исключениях. +- Любое действие с ресурсами, арендой, статистикой и пользователями всегда выполняется в контексте выбранной компании. + +### 3.2 Организационные принципы + +- Разработка идет итерациями: сначала каркас и авторизация, потом ресурсы, потом аренда, потом уведомления и статистика. +- На каждом этапе должны быть готовы миграции, API, UI и минимальный набор тестов. +- Все спорные моменты фиксируются как assumptions и не блокируют разработку каркаса. + +## 4. Scope MVP + +## 4.1 Что входит в MVP + +- заявка на подключение компании; +- выбор бизнес-плана и фиксация выбранного способа оплаты как заглушки; +- глобальный пользователь и membership в нескольких компаниях; +- вход, восстановление доступа, статус "на модерации после восстановления"; +- роли и иерархия ролей внутри компании; +- CRUD ресурсов; +- ограничения ресурсов по минимальной роли; +- исключения по конкретным пользователям; +- добавление сотрудника в компанию с поиском по email/телефону; +- список ресурсов, карточка ресурса, календарная доступность; +- создание заявок на аренду; +- обработка заявок ролью поддержки; +- email-уведомления; +- интеграция с Google Calendar; +- статистика по ресурсам и арендам; +- аудит ключевых действий. + +## 4.2 Что не входит в MVP + +- реальный биллинг; +- штрафы и санкции за просрочку; +- мобильное приложение; +- сложные workflow согласования из нескольких уровней; +- интеграции с внешними ERP/CRM; +- публичный маркетплейс ресурсов; +- полноценная система тикетов поддержки вне процесса аренды. + +## 5. Ключевые бизнес-сценарии + +### 5.1 Онбординг новой компании + +1. Представитель компании заполняет заявку. +2. Указывает компанию, ИНН, контакты доверенного лица, бизнес-план, вариант оплаты. +3. Заявка попадает в административный контур. +4. После одобрения создается tenant компании. +5. Для доверенного лица создается или привязывается глобальный пользователь. +6. Пользователь получает membership в новой компании и стартовую роль модератора или владельца компании. + +### 5.2 Приглашение сотрудника в компанию + +1. Модератор открывает форму добавления пользователя. +2. Вводит email, телефон и ФИО. +3. Система ищет существующего пользователя по email или телефону. +4. Если пользователь найден, добавляет membership в текущую компанию. +5. Если не найден, создает нового глобального пользователя и membership. +6. Модератор назначает роль. +7. Пользователь получает письмо с инструкцией по входу или активации. + +### 5.3 Вход и восстановление доступа + +1. Пользователь проходит аутентификацию через Supabase. +2. После входа выбирает активную компанию, если memberships несколько. +3. При восстановлении пароля учетная запись переводится в статус проверки. +4. Модератор компании получает уведомление о необходимости проверки. +5. Пока проверка не завершена, пользователь видит экран ожидания и не может создавать заявки. + +### 5.4 Аренда ресурса + +1. Пользователь выбирает компанию. +2. Видит только ресурсы, доступные его роли. +3. Открывает карточку ресурса. +4. Выбирает даты в календаре. +5. Недоступные даты заблокированы, если весь доступный объем ресурса занят. +6. Создает заявку на аренду. +7. Поддержка подтверждает или отклоняет заявку. +8. Пользователь получает email. +9. При подтверждении создается событие в Google Calendar. + +### 5.5 Работа поддержки + +1. Пользователь с ролью поддержки открывает очередь заявок. +2. Просматривает ресурс, даты, заявителя, доступность и комментарии. +3. Подтверждает или отклоняет заявку. +4. Решение логируется. +5. Пользователь получает уведомление о результате. + +### 5.6 Статистика + +1. Модератор или специально уполномоченный пользователь открывает страницу статистики. +2. Выбирает период, ресурс, категорию, подразделение или роль. +3. Видит загрузку ресурсов, число заявок, число отказов, популярные ресурсы, периоды пикового спроса. + +## 6. Assumptions, которые можно принять для старта + +Если исходный документ не уточняет детали, начать реализацию можно с такими решениями: + +- tenant определяется по активной компании пользователя, а не по поддомену; +- в MVP есть системная роль `platform_admin` для обработки заявок на создание компаний; +- внутри tenant базовые роли: `employee`, `support`, `moderator`, `company_admin`; +- роли и их иерархия настраиваются в каждой компании отдельно; +- ресурс имеет тип, название, описание, количество экземпляров и флаг активности; +- аренда создается как заявка со статусами `pending`, `approved`, `rejected`, `cancelled`, `completed`; +- Google Calendar интегрируется через сервисный слой, который можно временно запускать в stub-режиме; +- выбранный бизнес-план хранится как enum плюс снимок цены/условий на момент подключения. + +Если позже появятся уточнения, эти assumptions можно заменить без полной переделки архитектурного каркаса. + +## 7. Предлагаемая структура репозитория + +Если проект только создается, удобно использовать monorepo: + +- `apps/web` — фронтенд на Next.js; +- `apps/api` — бэкенд на Nest.js; +- `packages/ui` — общие UI-компоненты поверх shadcn/ui; +- `packages/shared` — общие типы, схемы Zod, константы, enum; +- `packages/config` — общие конфиги Biome, TypeScript, Tailwind; +- `docs` — документация. + +## 8. Архитектура backend + +## 8.1 Модули Nest.js + +В монолите нужно выделить такие модули: + +1. `auth` +2. `users` +3. `companies` +4. `memberships` +5. `roles` +6. `resources` +7. `resource-access` +8. `rental-requests` +9. `calendar` +10. `notifications` +11. `statistics` +12. `audit` +13. `plans-billing` +14. `platform-admin` + +## 8.2 Сквозные backend-компоненты + +- `tenant-context` — извлечение активной компании из токена, заголовка или session; +- `guards` — проверка аутентификации, tenant membership, роли, статуса пользователя; +- `interceptors` — аудит и нормализация ответов; +- `filters` — единый формат ошибок; +- `repositories/services` — бизнес-логика и доступ к данным; +- `event bus` или доменные события — для уведомлений, аудита и календаря. + +## 8.3 Multitenant-модель + +Для MVP достаточно shared database + shared schema + `company_id` во всех tenant-зависимых таблицах: + +- проще запуск и миграции; +- проще аналитика; +- достаточно для MVP при строгом контроле доступа. + +Обязательное правило: + +- все запросы к tenant-данным должны фильтроваться по `company_id`; +- любые уникальные ограничения tenant-сущностей должны учитывать `company_id`; +- backend не должен доверять `company_id`, пришедшему только из клиента, без проверки membership. + +## 9. Архитектура frontend + +## 9.1 Технологический каркас + +- `Next.js` App Router; +- `shadcn/ui` для базовых компонентов; +- `Tailwind CSS` для стилизации; +- `Formik` + `Zod` для форм и валидации; +- `FSD` для организации приложения. + +## 9.2 Предлагаемые FSD-срезы + +- `app` — провайдеры, роутинг, layout; +- `processes` — логика онбординга компании, создания аренды, восстановления доступа; +- `pages` — страницы приложения; +- `widgets` — крупные блоки, например список ресурсов, очередь заявок, дашборд статистики; +- `features` — действия пользователя: выбрать компанию, добавить ресурс, отправить заявку, восстановить пароль; +- `entities` — `user`, `company`, `resource`, `role`, `rental-request`; +- `shared` — ui, api-клиент, типы, utils, константы, hooks. + +## 9.3 Обязательные frontend-экраны MVP + +- лендинг/страница заявки на подключение компании; +- логин; +- восстановление пароля; +- экран "учетная запись на проверке"; +- выбор активной компании; +- дашборд; +- список ресурсов; +- карточка ресурса; +- календарь доступности; +- мои аренды; +- календарь моих аренд; +- очередь заявок поддержки; +- управление пользователями; +- управление ролями; +- управление ресурсами; +- страница статистики; +- системная страница ошибок и forbidden. + +## 10. Модель данных + +Ниже перечислены сущности, которые нужно заложить в БД. Они опираются на `docs/entities/*.puml`, но расширены до рабочего набора. + +### 10.1 Глобальные сущности + +#### `users` + +- `id` +- `supabase_auth_id` +- `email` +- `phone_number` +- `first_name` +- `last_name` +- `patronymic` +- `status` (`active`, `pending_verification`, `disabled`) +- `created_at` +- `updated_at` + +Уникальность: + +- уникальный `email`, если не `null`; +- уникальный `phone_number`, если не `null`. + +#### `company_applications` + +- `id` +- `company_name` +- `inn` +- `contact_email` +- `contact_phone` +- `contact_first_name` +- `contact_last_name` +- `contact_patronymic` +- `selected_plan` +- `payment_method` +- `status` +- `review_comment` +- `created_at` +- `updated_at` + +#### `plans` + +- `id` +- `code` +- `name` +- `description` +- `is_active` + +### 10.2 Tenant-сущности + +#### `companies` + +- `id` +- `name` +- `inn` +- `contact_email` +- `contact_phone` +- `contact_first_name` +- `contact_last_name` +- `contact_patronymic` +- `subscription_status` +- `selected_plan_id` +- `created_at` +- `updated_at` + +#### `memberships` + +- `id` +- `company_id` +- `user_id` +- `role_id` +- `status` (`active`, `invited`, `blocked`) +- `is_default_company` +- `created_at` +- `updated_at` + +Ограничение: + +- уникальная пара `company_id + user_id`. + +#### `roles` + +- `id` +- `company_id` +- `name` +- `code` +- `priority` +- `description` +- `is_system` +- `created_at` +- `updated_at` + +Правило: + +- чем выше `priority`, тем выше роль в иерархии. + +#### `resources` + +- `id` +- `company_id` +- `name` +- `code` +- `description` +- `category` +- `quantity_total` +- `quantity_active` +- `min_role_id` +- `is_active` +- `created_by` +- `updated_by` +- `created_at` +- `updated_at` + +#### `resource_user_exceptions` + +- `id` +- `company_id` +- `resource_id` +- `user_id` +- `rule_type` (`allow`, `deny`) +- `reason` +- `created_at` + +#### `rental_requests` + +- `id` +- `company_id` +- `resource_id` +- `user_id` +- `requested_start_at` +- `requested_end_at` +- `status` (`pending`, `approved`, `rejected`, `cancelled`, `completed`) +- `decision_comment` +- `processed_by` +- `processed_at` +- `created_at` +- `updated_at` + +#### `rental_allocations` + +Если у ресурса количество больше 1, полезно хранить фактические подтвержденные слоты отдельно: + +- `id` +- `company_id` +- `resource_id` +- `rental_request_id` +- `start_at` +- `end_at` +- `quantity_reserved` +- `created_at` + +#### `notifications` + +- `id` +- `company_id` +- `user_id` +- `type` +- `channel` (`email`, `system`) +- `status` +- `payload_json` +- `sent_at` +- `created_at` + +#### `audit_logs` + +- `id` +- `company_id` +- `actor_user_id` +- `action` +- `entity_type` +- `entity_id` +- `payload_json` +- `created_at` + +## 11. Права доступа и роли + +Нужно реализовать RBAC в два слоя: + +1. роль пользователя в компании; +2. дополнительные бизнес-ограничения на конкретный ресурс. + +### 11.1 Минимальный набор прав + +#### `employee` + +- просмотр доступных ресурсов; +- просмотр карточек доступных ресурсов; +- создание заявки на аренду; +- просмотр своих аренд; +- просмотр календаря своих аренд. + +#### `support` + +- все права `employee`; +- просмотр очереди заявок; +- подтверждение и отклонение заявок; +- просмотр календаря занятости ресурсов. + +#### `moderator` + +- все права `support`; +- создание и редактирование ресурсов; +- удаление или деактивация ресурсов; +- управление пользователями компании; +- назначение ролей; +- настройка исключений для пользователей; +- доступ к статистике. + +#### `company_admin` + +- все права `moderator`; +- управление иерархией ролей; +- назначение пользователей со специальным доступом к статистике; +- управление настройками компании. + +#### `platform_admin` + +- обработка заявок на создание компаний; +- просмотр всех компаний; +- активация и деактивация tenant; +- управление планами. + +### 11.2 Правила проверки доступа к ресурсу + +При попытке показать ресурс пользователю backend должен: + +1. проверить membership в компании; +2. проверить, что ресурс принадлежит этой компании; +3. получить роль пользователя и `priority`; +4. получить минимальную роль для ресурса; +5. применить персональные исключения; +6. вернуть `allowed` или `forbidden`. + +Логика исключений: + +- `deny` сильнее обычного ролевого доступа; +- `allow` может открывать ресурс пользователю с более низкой ролью; +- если есть одновременно `allow` и `deny`, в MVP приоритет у `deny`, чтобы избежать риска. + +## 12. API-контракты, которые надо реализовать + +Ниже перечислен минимальный набор REST endpoint для MVP. GraphQL тоже возможен, но REST проще для старта. + +### 12.1 Auth + +- `POST /auth/login` +- `POST /auth/logout` +- `POST /auth/refresh` +- `POST /auth/password-reset/request` +- `POST /auth/password-reset/confirm` +- `GET /auth/me` +- `POST /auth/select-company` + +### 12.2 Company applications / platform admin + +- `POST /company-applications` +- `GET /platform/company-applications` +- `PATCH /platform/company-applications/:id/approve` +- `PATCH /platform/company-applications/:id/reject` + +### 12.3 Companies and memberships + +- `GET /companies/my` +- `GET /companies/:companyId` +- `GET /companies/:companyId/members` +- `POST /companies/:companyId/members` +- `PATCH /companies/:companyId/members/:membershipId` +- `PATCH /companies/:companyId/members/:membershipId/status` + +### 12.4 Roles + +- `GET /companies/:companyId/roles` +- `POST /companies/:companyId/roles` +- `PATCH /companies/:companyId/roles/:roleId` +- `DELETE /companies/:companyId/roles/:roleId` + +### 12.5 Resources + +- `GET /companies/:companyId/resources` +- `POST /companies/:companyId/resources` +- `GET /companies/:companyId/resources/:resourceId` +- `PATCH /companies/:companyId/resources/:resourceId` +- `DELETE /companies/:companyId/resources/:resourceId` +- `GET /companies/:companyId/resources/:resourceId/availability` +- `GET /companies/:companyId/resources/:resourceId/exceptions` +- `POST /companies/:companyId/resources/:resourceId/exceptions` +- `DELETE /companies/:companyId/resources/:resourceId/exceptions/:exceptionId` + +### 12.6 Rental requests + +- `GET /companies/:companyId/rentals/my` +- `GET /companies/:companyId/rentals` +- `POST /companies/:companyId/rentals` +- `GET /companies/:companyId/rentals/:rentalId` +- `PATCH /companies/:companyId/rentals/:rentalId/approve` +- `PATCH /companies/:companyId/rentals/:rentalId/reject` +- `PATCH /companies/:companyId/rentals/:rentalId/cancel` + +### 12.7 Statistics + +- `GET /companies/:companyId/statistics/overview` +- `GET /companies/:companyId/statistics/resources` +- `GET /companies/:companyId/statistics/rentals` + +## 13. Логика календаря и доступности ресурсов + +Это одна из самых важных частей проекта, поэтому ее надо заложить заранее. + +### 13.1 Правила доступности + +- ресурс можно бронировать только в допустимом диапазоне дат; +- дата должна быть недоступна для выбора, если на весь период уже исчерпан `quantity_active`; +- при подтверждении заявки нужно повторно проверить доступность, потому что состояние могло измениться; +- запросы на перекрывающиеся интервалы считаются конфликтующими; +- отмененные и отклоненные заявки не резервируют ресурс; +- подтвержденные заявки резервируют ресурс через `rental_allocations`. + +### 13.2 Алгоритм проверки + +1. Получить ресурс и его `quantity_active`. +2. Найти все подтвержденные аренды по ресурсу, пересекающиеся с выбранным периодом. +3. Для каждого дня или временного слота посчитать суммарный reserved quantity. +4. Если в любой точке периода reserved quantity >= quantity_active, период недоступен. +5. Вернуть фронтенду карту доступности по датам. + +### 13.3 UI-календарь + +На фронтенде нужно: + +- показывать только доступные даты; +- блокировать недоступные; +- показывать причину, если ресурс закрыт по роли или исключению; +- отображать пользователю его текущие и прошлые аренды. + +## 14. Уведомления + +## 14.1 Email-уведомления MVP + +Отправлять письма при: + +- добавлении пользователя в компанию; +- запросе на восстановление доступа; +- переводе пользователя в статус проверки; +- подтверждении заявки на аренду; +- отклонении заявки на аренду; +- создании компании после одобрения заявки. + +## 14.2 Google Calendar + +Для MVP достаточно такой логики: + +- при подтверждении аренды создается событие; +- при отмене или отклонении подтвержденной аренды событие удаляется или помечается отмененным; +- в событие попадают название ресурса, период, компания, комментарий. + +Нужно сделать интеграцию через абстракцию: + +- `CalendarProvider`; +- реализация `GoogleCalendarProvider`; +- заглушка `NoopCalendarProvider` для локальной разработки и тестов. + +## 15. Статистика + +Минимальный набор показателей: + +- количество ресурсов по категориям; +- количество заявок за период; +- количество подтверждений и отказов; +- уровень загрузки ресурсов; +- топ наиболее арендуемых ресурсов; +- периоды наибольшего спроса; +- пользователи с наибольшим числом аренд. + +Для MVP не нужен отдельный data warehouse. Достаточно агрегирующих SQL-запросов и materialized view, если понадобится ускорение. + +## 16. Этапы реализации + +Ниже — рекомендуемый порядок, в котором другая модель или разработчик должны выполнять работу. + +### Этап 0. Инициализация проекта + +#### Задачи + +- создать monorepo или согласованную структуру каталогов; +- инициализировать `Next.js` и `Nest.js`; +- подключить `Tailwind`, `shadcn/ui`, `Biome`, `TypeScript`; +- настроить `.env` и шаблоны env-файлов; +- поднять `Postgres`; +- настроить подключение к `Supabase`; +- выбрать ORM или query builder (`Prisma` предпочтителен для быстрого старта). + +#### Результат + +- проект запускается локально; +- есть healthcheck backend; +- frontend умеет ходить в backend; +- есть первая миграция БД. + +#### Definition of Done + +- `web` стартует; +- `api` стартует; +- база подключена; +- есть README по локальному запуску. + +### Этап 1. Базовая доменная модель и multitenant-каркас + +#### Задачи + +- описать таблицы `users`, `companies`, `memberships`, `roles`; +- добавить системные enum и справочники; +- реализовать `tenant-context`; +- реализовать guards на membership и role; +- добавить seed для базовых ролей. + +#### Результат + +- backend умеет определять активную компанию пользователя; +- любой tenant-запрос изолируется по `company_id`. + +#### Definition of Done + +- созданы миграции; +- написаны тесты на tenant-изоляцию; +- нельзя получить данные чужой компании. + +### Этап 2. Авторизация и восстановление доступа + +#### Задачи + +- интегрировать вход через `Supabase`; +- реализовать endpoint `me`; +- реализовать выбор активной компании; +- реализовать запрос и подтверждение восстановления пароля; +- после восстановления переводить пользователя в `pending_verification`; +- отправлять уведомление модераторам. + +#### Результат + +- пользователь может войти; +- пользователь с несколькими компаниями может выбрать контекст; +- после восстановления аккаунт блокируется до проверки. + +#### Definition of Done + +- есть end-to-end сценарий логина; +- есть сценарий password reset; +- экран "на проверке" работает. + +### Этап 3. Онбординг компаний + +#### Задачи + +- сделать публичную форму заявки на подключение компании; +- реализовать хранение `company_applications`; +- реализовать platform admin review flow; +- при одобрении создавать `company`, membership доверенного лица и стартовую роль. + +#### Результат + +- новая компания может появиться в системе без ручного SQL. + +#### Definition of Done + +- заявка создается; +- platform admin может одобрить или отклонить; +- после одобрения пользователь может войти в tenant. + +### Этап 4. Управление ролями и пользователями + +#### Задачи + +- реализовать CRUD ролей; +- реализовать иерархию ролей; +- реализовать экран списка пользователей компании; +- реализовать добавление пользователя по email/телефону; +- если пользователь существует, только привязывать membership; +- если не существует, создавать нового пользователя. + +#### Результат + +- модератор управляет доступами и составом компании. + +#### Definition of Done + +- пользователь не дублируется при повторном добавлении; +- роли можно назначать и менять; +- права на эти действия ограничены. + +### Этап 5. Управление ресурсами + +#### Задачи + +- реализовать модель `resources`; +- сделать CRUD ресурсов; +- добавить `min_role_id`; +- реализовать пользовательские исключения `allow/deny`; +- сделать UI для списка и карточки ресурса. + +#### Результат + +- модератор управляет каталогом ресурсов компании. + +#### Definition of Done + +- ресурс создается и редактируется; +- ресурс нельзя увидеть из чужой компании; +- ограничения по роли и исключения применяются корректно. + +### Этап 6. Подача заявок на аренду + +#### Задачи + +- реализовать availability endpoint; +- реализовать календарь выбора дат; +- реализовать создание `rental_requests`; +- показать пользователю мои заявки и историю; +- добавить календарное представление моих аренд. + +#### Результат + +- сотрудник может отправить заявку на аренду доступного ресурса. + +#### Definition of Done + +- недоступные даты заблокированы; +- недоступные по роли ресурсы скрыты; +- при прямом заходе на закрытый ресурс показывается понятное сообщение. + +### Этап 7. Обработка заявок поддержкой + +#### Задачи + +- реализовать очередь заявок; +- сделать approve/reject; +- при approve создавать `rental_allocations`; +- отправлять email; +- писать аудит. + +#### Результат + +- support управляет жизненным циклом аренд. + +#### Definition of Done + +- при approve повторно проверяется доступность; +- конфликтующая аренда не подтверждается; +- письма и аудит создаются. + +### Этап 8. Интеграция с Google Calendar + +#### Задачи + +- реализовать интерфейс календарного провайдера; +- подключить Google Calendar; +- на подтверждение аренды создавать событие; +- на отмену или отклонение обновлять событие. + +#### Результат + +- подтвержденная аренда попадает в календарь пользователя. + +#### Definition of Done + +- событие создается успешно; +- в dev-режиме доступна безопасная заглушка; +- ошибки интеграции не валят основной бизнес-процесс. + +### Этап 9. Статистика + +#### Задачи + +- реализовать агрегирующие запросы; +- сделать дашборд статистики; +- ограничить доступ по ролям и специальному разрешению; +- добавить фильтры по периоду и ресурсам. + +#### Результат + +- модератор видит картину использования ресурсов. + +#### Definition of Done + +- данные совпадают с фактами в БД; +- фильтры работают; +- страница доступна только разрешенным пользователям. + +### Этап 10. Hardening и подготовка к расширению + +#### Задачи + +- довести аудит; +- покрыть критичный функционал тестами; +- добавить rate limiting на auth и публичные формы; +- добавить валидацию и защиту от неконсистентных состояний; +- подготовить точки расширения для штрафов и биллинга. + +#### Результат + +- MVP можно безопасно показывать первым пользователям. + +#### Definition of Done + +- закрыты ключевые ошибки доступа; +- есть базовое логирование; +- описаны дальнейшие точки роста. + +## 17. Что нужно реализовать на frontend по страницам + +### 17.1 Public + +- `/` — краткое описание продукта; +- `/company-application` — заявка на подключение компании; +- `/login`; +- `/password-reset/request`; +- `/password-reset/confirm`. + +### 17.2 Authenticated + +- `/select-company`; +- `/dashboard`; +- `/resources`; +- `/resources/[id]`; +- `/my-rentals`; +- `/calendar`; +- `/support/rentals`; +- `/admin/users`; +- `/admin/roles`; +- `/admin/resources`; +- `/statistics`; +- `/account-under-review`. + +### 17.3 Для каждой страницы определить заранее + +Для другой модели важно, чтобы перед разработкой каждого экрана она описала: + +- источник данных; +- доступные действия; +- роли, которым доступен экран; +- пустые состояния; +- loading/error состояния; +- валидацию форм; +- success/error уведомления. + +## 18. Что нужно реализовать на backend по сервисам + +### 18.1 AuthService + +- синхронизация пользователя `Supabase` с локальной записью; +- восстановление доступа; +- переключение активной компании. + +### 18.2 MembershipService + +- поиск memberships пользователя; +- создание membership без дублирования; +- проверка активного статуса участника. + +### 18.3 RoleService + +- CRUD ролей; +- проверка иерархии; +- защита от удаления системной роли, если она используется. + +### 18.4 ResourceService + +- CRUD ресурсов; +- определение доступности ресурса пользователю; +- применение исключений. + +### 18.5 RentalRequestService + +- создание заявки; +- пересчет доступности; +- approve/reject/cancel; +- формирование данных для календаря пользователя. + +### 18.6 NotificationService + +- шаблоны писем; +- асинхронная отправка; +- повторные попытки и логирование ошибок. + +### 18.7 StatisticsService + +- агрегаты по арендам и ресурсам; +- фильтры; +- подготовка данных под графики. + +## 19. Тестовая стратегия + +Для другой модели этот раздел обязателен: разработка каждого этапа должна сопровождаться проверками. + +### 19.1 Unit tests + +Минимум покрыть: + +- проверку tenant-контекста; +- проверку ролевого доступа; +- логику исключений `allow/deny`; +- алгоритм доступности ресурса; +- approve/reject аренды; +- статус `pending_verification` после восстановления доступа. + +### 19.2 Integration tests + +Покрыть: + +- создание пользователя и membership; +- добавление существующего пользователя в новую компанию; +- создание ресурса; +- создание заявки на аренду; +- подтверждение заявки с конфликтом и без конфликта; +- изоляцию tenant-данных. + +### 19.3 E2E tests + +Минимальный набор: + +- логин и выбор компании; +- добавление сотрудника модератором; +- создание ресурса; +- подача заявки пользователем; +- подтверждение заявки поддержкой; +- просмотр истории аренд; +- просмотр статистики модератором. + +### 19.4 Manual QA checklist + +- пользователь не видит ресурсы чужой компании; +- пользователь с низкой ролью не видит закрытый ресурс; +- пользователь видит понятное сообщение при прямом переходе в закрытый ресурс; +- даты блокируются корректно; +- после восстановления доступа пользователь заблокирован до проверки; +- письма и календарные события создаются; +- статистика не доступна обычному сотруднику без прав. + +## 20. Нефункциональные требования + +- все даты хранить в UTC; +- в UI явно показывать timezone или использовать локальный timezone пользователя; +- backend должен быть идемпотентен там, где возможны повторные запросы; +- критичные действия должны логироваться; +- все формы должны иметь Zod-валидацию; +- все backend DTO должны валидироваться; +- все удаление tenant-сущностей в MVP лучше делать soft delete или деактивацией, если это снижает риск потери данных. + +## 21. Риски и меры снижения + +### Риск 1. Ошибки tenant-изоляции + +Мера: + +- централизованный tenant guard; +- обязательный `company_id` в tenant-таблицах; +- тесты на доступ к чужим данным. + +### Риск 2. Конфликты аренды при параллельных подтверждениях + +Мера: + +- транзакции; +- повторная проверка доступности при approve; +- блокировка строки или оптимистичная версия. + +### Риск 3. Несогласованность между Supabase и локальной БД + +Мера: + +- отдельный sync layer; +- обработка повторной синхронизации при логине; +- хранение внешнего `supabase_auth_id`. + +### Риск 4. Сложность кастомной иерархии ролей + +Мера: + +- хранить числовой `priority`; +- сначала реализовать простую линейную иерархию; +- не переходить к графовой модели ролей в MVP. + +### Риск 5. Нестабильность внешних интеграций + +Мера: + +- все email/calendar действия выполнять через абстракции; +- держать fallback и retry; +- не ломать основной бизнес-флоу из-за недоступной интеграции. + +## 22. Бэклог после MVP + +- штрафы за просрочку; +- биллинг и подписки; +- автопродление ресурсов; +- SLA и escalation для поддержки; +- дашборды по департаментам; +- экспорт статистики; +- webhooks; +- SSO для компаний; +- поддомены под tenant; +- расширенный audit trail. + +## 23. Инструкция для другой модели или чата + +Если этот проект будет делать другая модель, ей нужно работать так: + +1. Сначала поднять каркас проекта и БД. +2. Затем реализовать multitenant-ядро и авторизацию. +3. После этого двигаться по этапам 3-10 строго по порядку. +4. На каждом этапе сначала описывать модель данных и API, потом писать backend, потом frontend. +5. Не переходить к следующему этапу, пока не выполнены `Definition of Done` текущего. +6. Для всех спорных мест использовать раздел assumptions и явно отмечать, где принято временное решение. +7. Не начинать статистику и внешние интеграции, пока не стабилизированы сущности пользователей, ролей, ресурсов и аренд. +8. Любую tenant-зависимую фичу проверять на утечку данных между компаниями. + +## 24. Краткий порядок работ в одной строке + +Инициализация проекта → multitenant-каркас → auth → онбординг компаний → роли и пользователи → ресурсы → аренда → support workflow → уведомления и Google Calendar → статистика → hardening.