Перейти к содержанию

Приостановка и завершение работы организации

Организация в SaaS живёт дольше отдельного проекта. Её могут временно перевести в режим чтения, закрыть для новых действий или окончательно удалить прикладные данные. Одного DELETE из таблицы организаций недостаточно: остаются участники, приглашения, очередь и выгрузки, которые способны продолжать старые действия.

В завершении курса соберём эти зависимости в явный жизненный цикл «Пространства». Состояние компании проверяется в каждой транзакции и перед фоновым результатом. Только owner меняет его. Полные маршруты LifecycleEndpoints.cs и очистка worker находятся в архиве. Процедура при подготовке не запускалась; её эффект описан как ожидаемый.

Состояние определяет разрешённые действия

В нашем контракте active допускает обычную работу. Read_only сохраняет просмотр и экспорт, но прекращает прикладную запись. Deleting прекращает новые пользовательские задания и выдачу обычных данных на период очистки. Deleted является окончательным состоянием и не возвращается к active обычным маршрутом.

Состояние Чтение Запись проектов Новый экспорт Очистка
active да да да нет
read_only да нет да нет
deleting нет нет нет продолжается
deleted нет нет нет завершена

Read_only не меняет роли участников. Вера остаётся editor, но состояние организации ограничивает её запись. После возврата к active роль снова разрешит изменение. Если вместо состояния массово понизить всех участников до viewer, сервис потеряет прежние роли и не сможет корректно восстановить работу.

Режим чтения также не считается неоплаченностью автоматически. В следующем курсе доступ к отдельным функциям будет определяться entitlement. Финансовое состояние и административный жизненный цикл связаны продуктовым решением, но это разные данные. Отмена подписки не должна без объяснения уничтожать компанию или менять её владельца.

Блокировка задаёт момент остановки записи

Владелец переводит active в read_only в транзакции с исключительной блокировкой строки организации. Обычная запись проекта берёт совместимую блокировку этой же строки и проверяет active. Поэтому обе операции получают порядок: либо проект фиксируется раньше остановки, либо уже видит read_only и получает отказ.

Ниже приведён полный SQL изменения состояния из обработчика. В архиве перед ним проверяется owner и допустимый переход, а после него записывается аудит. Организация уже заблокирована текущим сеансом.

UPDATE organizations
SET status=@status,version=version+1
WHERE id=@organization
RETURNING id,status,version;

Важно не смешивать эту операцию с обычным переименованием проекта. Изменение состояния относится ко всем последующим действиям компании. Если только сохранить поле status без общей проверки в сеансах, часть маршрутов продолжит писать по старому коду. Контракт жизненного цикла находится в общем Database.OpenAsync, а не копируется случайно в нескольких обработчиках.

Клиент получает новое состояние и версию организации. Уже отправленный ответ с данными не может быть отозван сервером. Остановка означает прекращение новых разрешённых операций после согласованного перехода, а не стирание информации из памяти всех участников. Такая граница особенно существенна для ранее скачанного экспорта.

Удаление начинается с команды

При переходе к deleting транзакция создаёт задание очистки. Сначала сохраняется намерение, затем worker выполняет зависимые операции. API возвращает 202 и состояние deleting. Ответ «удалено» до очистки был бы неточным, а длинное синхронное удаление могло бы оборваться после потери HTTP-соединения.

Задание повторяемое. Worker удаляет задачи перед проектами, отзывает приглашения, очищает готовые пользовательские результаты и затем переводит организацию в deleted. Повтор после сбоя должен видеть уже выполненные этапы и продолжать, не создавая новую компанию. Составные внешние ключи помогают выбрать порядок удаления, но не определяют продуктовые сроки сами по себе.

Аудит обычных операций может удаляться либо сохраняться ограниченное время согласно договорённости. В учебном примере очистка удаляет прикладную историю, оставляя минимальную административную отметку состояния. Worker имеет отдельные права для этой процедуры. Это означает, что append-only для HTTP-приложения не является обещанием бесконечного хранения всех персональных сведений.

Таблица общей личности не удаляется только из-за закрытия «Севера». Анна всё ещё состоит в «Юге». Поэтому процедура удаляет членства конкретной компании, а не пользователя целиком. Удаление личного аккаунта потребовало бы другого процесса, который проверяет все связи и отличает данные личности от данных компаний.

Очередь и финансовые записи после закрытия

Уже арендованный экспорт может завершаться одновременно с удалением. Перед публикацией результата worker перечитывает состояние организации и проверяет token аренды. Если deleting уже начался, пользовательская выгрузка не становится готовой. Без этой проверки очистка могла бы убрать старый JSON, после чего поздний worker создал бы его заново.

В следующем курсе появятся заказы, платежи и возвраты. Их нельзя бесконтрольно удалить вместе с проектами: позднее уведомление провайдера и сверка всё ещё могут относиться к закрытой компании. Учебное удаление прикладных данных оставляет финансовую область для отдельной политики хранения. Курс не предлагает юридический срок хранения, поскольку он зависит от условий настоящего продукта и юрисдикции.

Системное финансовое уведомление не должно использовать пользовательское разрешение active. Оно обрабатывает уже существующую операцию, а не создаёт проект от закрытого участника. При этом оно не должно возобновлять deleted-компанию и выдавать новый доступ автоматически. Разделение прикладного жизненного цикла и финансового состояния предотвратит такую случайную связь.

Наблюдаемая завершённость процедуры

В ручном сценарии сначала переведите «Север» в read_only. Ожидаемо список доступен, создание получает 409, а экспорт разрешён. Затем верните active и убедитесь по ожидаемому контракту, что роли остались прежними. Такой вариант проверяет смысл состояния отдельно от окончательной очистки.

Перед deleting получите нужную выгрузку. После команды ожидается состояние deleting, затем deleted и отказ на старых маршрутах. «Юг» продолжает работу, членство Анны в нём сохраняется, а UUID северных проектов не превращаются в южные. Очистка одной организации не должна запускать общую очистку таблицы пользователей либо очереди всех клиентов.

Вы получили законченную модель нескольких компаний: проверенную личность, локальное членство, явную область SQL, составные связи, RLS, транзакции, очередь и жизненный цикл. Следующий связанный курс — платежи и подписки — использует те же организации. Денежные операции добавят собственные состояния и повторы, сохранив уже построенную границу данных.

Оглавление серии