20 янв. 2026 г.·6 мин

Мягкое удаление против полного удаления: выберите правильный жизненный цикл данных

Мягкое удаление против полного удаления: узнайте, как сохранять историю, избегать разрывов ссылок и при этом выполнять требования по удалению персональных данных с понятными правилами.

Мягкое удаление против полного удаления: выберите правильный жизненный цикл данных

Что на самом деле означает мягкое и полное удаление

«Удаление» может означать две очень разные вещи. Их путаница — частая причина потери истории или отказа выполнить запросы на удаление персональных данных.

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

Мягкое удаление сохраняет строку, но помечает её как удалённую, обычно полем вроде deleted_at или is_deleted. Приложение считает запись «удалённой», но данные остаются для отчётов, поддержки и аудита.

Суть выбора между мягким удалением и полным удалением проста: история против полного удаления. Мягкое удаление защищает историю и даёт возможность «отменить» действие. Жёсткое удаление уменьшает объём хранимых данных, что важно для приватности, безопасности и юридических требований.

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

Полезная модель для мышления:

  • Мягкое удаление скрывает запись от повседневного просмотра, но сохраняет её для трассировки.
  • Жёсткое удаление удаляет запись навсегда и минимизирует хранимые персональные данные.
  • Многие реальные приложения используют оба подхода: сохраняют бизнес-историю, удаляя личные идентификаторы по требованиям.

На практике вы можете мягко удалить аккаунт пользователя, чтобы запретить вход и сохранить историю заказов, а затем через заданный период окончательно удалить или анонимизировать персональные поля после подтверждённого запроса на удаление по GDPR.

Ни один инструмент не примет это решение за вас. Даже при использовании no-code платформы вроде AppMaster реальная работа — решить для каждой таблицы, что значит «удалено», и убедиться, что каждый экран, отчёт и API следует одному правилу.

Какие проблемы удаления вызывают в обычных приложениях

Большинство команд замечают последствия удаления только когда что-то ломается. «Простое» удаление может стереть контекст, историю и вашу способность объяснить, что произошло.

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

Разорванные ссылки — ещё один сюрприз. Вы удалили клиента, но его заказы остались. Теперь у вас есть заказы, указывающие ни на что, счета без имени плательщика и портал, который падает при загрузке связанных данных. Даже ограничения внешних ключей (foreign key constraints) не всегда спасают: каскадные удаления могут стереть значительно больше, чем вы предполагали.

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

Поддержка и соответствие — там боль сильнее всего. Клиент спрашивает: «Почему мне выставили платёж?» или «Кто изменил мой тариф?» Если запись удалена, вы не сможете восстановить таймлайн. Вы теряете журнал аудита, который бы ответил на базовые вопросы: что поменялось, когда и кем.

Типичные сценарии отказа при выборе мягкого или жёсткого удаления:

  • Постоянная потеря данных из-за случайных удалений или проблем в автоматизации.
  • Отсутствие родительских записей, оставляющих дочерние (заказы, тикеты) сиротами.
  • Изменение отчётов из‑за исчезновения исторических строк.
  • Случаи поддержки, которые становятся неразрешимыми без истории.

Когда мягкое удаление — лучший выбор по умолчанию

Мягкое удаление обычно безопаснее, когда запись имеет долгосрочную ценность или связана с другими данными. Вместо физического удаления вы помечаете запись как удалённую (например, deleted_at или is_deleted) и скрываете её из обычных представлений. В споре мягкое против жёсткого удаления такой выбор уменьшает количество неприятных сюрпризов.

Оно особенно полезно там, где важна возможность аудита в базах данных. Операционные команды часто должны ответить на простые вопросы: «Кто изменил заказ?» или «Почему был отменён этот счёт?» Если вы рано выполните жёсткое удаление, вы потеряете доказательства, нужные для финансовых, поддержковых и комплаенс-отчётов.

Мягкое удаление также делает возможным «откат». Администратор может восстановить тикет, закрытый по ошибке, вернуть архивный товар или восстановить контент пользователя после ложного спам-репорта. Такие сценарии трудно реализовать, если данные физически удалены.

Связи — ещё одна веская причина. Жёсткое удаление родителя может нарушить внешние ключи или оставить непонятные дыры в отчётах. При мягком удалении JOIN‑ы остаются стабильными, а исторические суммы — согласованными (ежедневная выручка, выполненные заказы, статистика времени отклика).

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

Пример: агент поддержки «удаляет» заметку к заказу с ошибкой. При мягком удалении заметка исчезает из обычного интерфейса, но супервайзеры всё ещё могут её просмотреть при споре, а финансовые отчёты остаются объяснимыми.

Когда требуется жёсткое удаление

Мягкое удаление — отличный стандарт, но иногда хранить данные, пусть и скрытые, — неверный выбор. Жёсткое удаление — это полное удаление записи, и оно иногда единственно соответствует юридическим, безопасностным или затратным требованиям.

Самый очевидный случай — обязательства по приватности и контрактам. Если человек реализует своё право на удаление по GDPR или ваш договор обещает удаление после определённого срока, пометка «удалено» часто не считается. Возможно, нужно удалить строку, её копии и все идентификаторы, по которым можно восстановить личность.

Безопасность — ещё одна причина. Некоторые данные слишком чувствительны, чтобы хранить их: необработанные access‑токены, коды сброса пароля, приватные ключи, одноразовые коды или нешифрованные секреты. Хранение таких данных ради истории редко оправдано.

Жёсткое удаление также уместно для масштабируемости. Если у вас огромные таблицы старых событий, логов или телеметрии, мягкое удаление постепенно раздувает базу и замедляет запросы. Запланированная очистка держит систему отзывчивой и предсказуемой по затратам.

Жёсткое удаление часто подходит для временных данных (кеши, сессии, импортные черновики), краткоживущих артефактов безопасности (токены сброса, OTP, коды приглашений), тестовых/демо‑аккаунтов и больших исторических наборов, где нужны лишь агрегированные статистики.

Практичный подход — разделять «бизнес‑историю» и «персональные данные». Например, сохраняйте счета для бухучёта, но жёстко удаляйте (или анонимизируйте) поля профиля, по которым можно идентифицировать человека.

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

Как смоделировать мягкое удаление без сюрпризов

Проведите прогон удаления
Протестируйте сценарий «удалить пользователя» полностью: экраны и API.
Прототип

Мягкое удаление лучше всего работает, когда оно скучно и предсказуемо. Цель проста: запись остаётся в базе, но обычные части приложения ведут себя так, как будто её нет.

Выберите один сигнал удаления и чётко опишите, что он значит

Существует три широко используемых паттерна: временная метка deleted_at, булево поле is_deleted или статус‑enum. Многие команды предпочитают deleted_at, потому что это отвечает на два вопроса сразу: удалена ли запись и когда это произошло.

Если у вас уже есть несколько состояний жизненного цикла (active, pending, suspended), enum тоже работает, но держите «deleted» отдельно от «archived» и «deactivated». Это разные вещи:

  • Deleted: не должна появляться в обычных списках и быть недоступной для использования.
  • Archived: хранится для истории, но видна в «прошлых» представлениях.
  • Deactivated: временно отключена, часто может быть восстановлена пользователем.

Позаботьтесь о уникальных полях заранее

Споры мягкое vs жёсткое удаление часто ломаются на уникальных полях: email, username, номер заказа. Если пользователь «удалён», но его email всё ещё хранится и уникален, тот же человек не сможет зарегистрироваться заново.

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

Явно задайте правила фильтрации (и соблюдайте их)

Определите, кто и что видит. Частое правило: обычные пользователи никогда не видят удалённые записи, поддержка/админы видят их с явной пометкой, а экспорты/отчёты включают их только по запросу.

Не полагайтесь на «все помнят добавить фильтр». Поместите правило в одно место: в представления, в дефолтные запросы или в слой доступа к данным. В AppMaster это обычно значит встроить фильтр в способ выборки данных в эндпоинтах и бизнес‑процессах, чтобы удалённые строки случайно не появлялись в новом экране.

Запишите значения в короткой внутренней заметке (или в комментариях к схеме). Будущему вам это пригодится, когда «deleted», «archived» и «deactivated» окажутся в одной и той же митинге.

Как поддерживать ссылки: родители, дети и JOIN-ы

Чаще всего удаления ломают приложения через связи. Запись редко бывает одна: у пользователей есть заказы, у тикетов — комментарии, у проектов — файлы. Сложность при выборе мягкого или жёсткого удаления — сохранять согласованность ссылок, при этом позволять продукту вести себя так, будто элемент «исчез».

Внешние ключи: выберите желаемый режим отказа сознательно

Внешние ключи защищают от разрыва ссылок, но каждый вариант имеет своё значение:

  • RESTRICT блокирует удаление, если есть дочерние записи.
  • SET NULL позволяет удалить, но отсоединяет детей.
  • CASCADE автоматически удаляет дочерние записи.
  • NO ACTION во многих СУБД похож на RESTRICT, но отличается по времени выполнения.

При мягком удалении RESTRICT часто самый безопасный выбор. Вы храните строку, ключи остаются валидными, и вы избегаете ситуации, когда дети указывают ни на что.

Мягкое удаление в отношениях: скрывать без сиротства

Мягкое удаление обычно не трогает внешние ключи. Вместо этого вы фильтруете удалённых родителей в приложении и в отчётах. Если клиент мягко удалён, его счета всё ещё должны правильно джоиниться, но в выпадающих списках клиент не должен появляться.

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

JOIN‑ы и отчёты нуждаются в чётком правиле: включать ли удалённые строки? Многие команды держат два стандартных запроса: «только активные» и «включая удалённые», чтобы служба поддержки и отчёты не скрывали важную историю.

Пошагово: спроектируйте жизненный цикл данных, который использует оба подхода

Сохраняйте ссылки целыми
Предотвращайте появление сиротских записей, проектируя связи и поведение при удалении вместе.
Начать

Практичная политика часто использует мягкое удаление для повседневных ошибок и жёсткое удаление для юридических или приватных потребностей. Если сводить всё к одному выбору (мягкое vs жёсткое), вы упускаете промежуточные варианты: сохранить историю какое‑то время, а затем очистить то, что требуется удалить.

Простой план из 5 шагов

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

Короткий план, работающий в большинстве команд:

  • Определите группы данных и ответственных, укажите, кто утверждает удаление.
  • Задайте правила хранения и восстановления.
  • Решите, что анонимизируется вместо удаления.
  • Добавьте шаг плановой очистки (мягкое удаление сейчас, жёсткое позже).
  • Фиксируйте событие удаления/восстановления/очистки в аудите (кто, когда, что и почему).

Пример на реальном сценарии

Клиент просит закрыть аккаунт. Сначала мягко удаляете запись пользователя, чтобы он не мог войти и чтобы не сломать связи. Затем анонимизируете персональные поля (имя, email, телефон), оставляя неперсональные факты транзакций для бухучёта. Наконец, по расписанию очистки удаляете то, что остаётся персональным после периода ожидания.

Распространённые ошибки и ловушки

Найдите баланс между историей и приватностью
Сохраняйте историю, удобную для аудита, и удаляйте чувствительные данные, когда это действительно необходимо.
Создать сейчас

Команды попадали в беду не потому, что выбрали неверный подход, а потому, что применяли его непоследовательно. Частая модель: на бумаге есть мягкое vs жёсткое удаление, а на практике — «скрываем в одном экране и забываем про остальное».

Одна простая ошибка: вы скрываете удалённые записи в UI, но они всё ещё появляются через API, CSV‑экспорты, админ‑инструменты или задания синхронизации данных. Пользователи быстро заметят, когда «удалённый» клиент появится в списке рассылки или в мобильном поиске.

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

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

Проблемы с уникальными ограничениями при мягком удалении вызывают тонкую боль. Если пользователь удалил аккаунт, потом пытается снова зарегистрироваться с тем же email — регистрация может упасть. Планируйте это заранее.

Команды по комплаенсу спросят: можно ли доказать, что удаление произошло и когда? «Мы думаем, что удалили» не пройдёт проверку политики хранения данных. Храните временную метку удаления, кто/что её инициировал, и неизменяемую запись в логе.

Перед релизом проверьте всю поверхность: API, экспорты, поиск, отчёты и фоновые задания. Также просмотрите каскады по таблицам и подтвердите, что пользователи могут воссоздать уникальные данные (email, username), если продукт это обещает.

Быстрая проверка перед релизом

Прежде чем выбирать мягкое или жёсткое удаление, проверьте реальное поведение приложения, а не только схему.

  • Восстановление безопасно и предсказуемо. При «аннулировании удаления» запись возвращается в правильное состояние, не восстанавливая чувствительные элементы, которые должны остаться удалёнными (например, отозванные токены доступа).
  • Запросы по умолчанию скрывают удалённые данные. Новые экраны, экспорты и API не должны случайно включать удалённые строки. Выберите одно правило и применяйте его везде.
  • Ссылки не ломаются. Убедитесь, что внешние ключи и JOIN‑ы не порождают сиротских записей или половинчатых экранов.
  • Очистка имеет график и владельца. Мягкое удаление — только половина плана. Определите, когда данные окончательно удаляются, кто это выполняет и что исключено (например, активные споры).
  • Удаление логируется как любое другое чувствительное действие. Записывайте инициатора, время и причину.

Затем протестируйте путь приватности целиком. Можете ли вы выполнить запрос на удаление по GDPR по всем копиям, экспортам, индексам поиска, аналитическим таблицам и интеграциям, а не только в основной базе?

Практический способ проверить — один «dry run» удаления пользователя в staging и проследить след данных.

Пример: удалить пользователя, сохранив историю выставления счетов

Сделайте удаление единым везде
Используйте единый фильтр для удалённых записей, чтобы экспорты, поиск и отчёты соответствовали UI.
Попробовать

Клиент пишет: «Удалите мой аккаунт». У вас есть счета, которые нужно хранить для бухучёта и проверки споров. Здесь мягкое vs жёсткое удаление становится практичным: вы можете удалить доступ и персональные данные, сохранив финансовые записи, которые бизнес обязан хранить.

Отделяйте «аккаунт» от «платёжной записи». Аккаунт — это про вход и идентичность. Платёжная запись — про совершённую транзакцию.

Чистый подход:

  • Мягко удалите аккаунт, чтобы пользователь не мог войти и профиль исчезал из обычных представлений.
  • Сохраните счета и платежи как активные записи, но перестаньте привязывать их к персональным полям.
  • Анонимизируйте персональные данные (имя, email, телефон, адрес), заменив их нейтральными значениями вроде «Deleted User» и внутренним ссылочным идентификатором, не позволяющим восстановить личность.
  • Жёстко удалите чувствительные артефакты доступа: API‑токены, хеши паролей, сессии, refresh‑токены и запомненные устройства.
  • Оставьте только то, что действительно требуется для соответствия и поддержки, и задокументируйте причины.

Тикеты поддержки и сообщения часто находятся посередине. Если содержание сообщения содержит персональные данные, возможно потребуется редактировать текст, удалить вложения и сохранить «оболочку» тикета (метки времени, категорию, результат) для качества. Если ваш продукт отправлял уведомления (email/SMS, Telegram), удалите исходящие идентификаторы, чтобы человек больше не получал сообщений.

Что поддержка может видеть? Обычно номера счетов, даты, суммы, статусы и пометка о том, что пользователь был удалён и когда. Что нельзя показывать — всё, что идентифицирует человека: email для входа, полное имя, адреса, данные платёжной карты или активные сессии.

Следующие шаги: зафиксируйте правила и реализуйте их одинаково

Решения об удалении работают, когда их записывают и реализуют одинаково по продукту. Рассматривайте вопрос «мягкое vs жёсткое удаление» как политический, а не как трюк программирования.

Начните с простой политики хранения данных, понятной любой команде. В ней должно быть сказано, что вы храните, как долго и зачем. «Зачем» важно, потому что это подскажет, что перевесит в случае конфликта целей (например, история поддержки против запросов на приватность).

Хороший стандарт часто выглядит так: мягкое удаление для повседневных бизнес‑записей (заказы, тикеты, проекты), жёсткое удаление для действительно чувствительных данных (токены, секреты) и всего, что не стоит хранить.

Когда политика ясна, постройте потоки, которые её обеспечивают: «корзину» для восстановления, очередь очистки для необратимого удаления после проверок и интерфейс аудита, показывающий, кто и когда совершал действия. Сделайте «очистку» сложнее, чем обычное «удаление», чтобы её не запускали по ошибке.

Если вы реализуете это в AppMaster (appmaster.io), полезно смоделировать поля мягкого удаления в Data Designer и централизовать логику удаления, восстановления и очистки в одном Business Process, чтобы одни и те же правила применялись ко всем экранам и API.

Вопросы и ответы

What’s the simplest difference between soft delete and hard delete?

A жесткое удаление физически удаляет строку из базы данных — при последующем запросе её уже нет. Мягкое удаление оставляет строку, но помечает её как удалённую (часто с помощью поля deleted_at), поэтому приложение скрывает запись в обычных интерфейсах, но сохраняет историю для поддержки, аудита и отчётности.

When should soft delete be the default?

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

When is hard delete the right choice?

Жёсткое удаление уместно, когда хранение данных создаёт риск для приватности или безопасности, либо когда правила хранения требуют полного удаления. Типичные примеры: токены сброса пароля, одноразовые коды, сессии, API-ключи и персональные данные, которые нужно стереть по запросу или после срока хранения.

Should I use `deleted_at` or `is_deleted` for soft delete?

Поле deleted_at удобно, потому что оно отвечает сразу на два вопроса: удалена ли запись и когда это произошло. Оно хорошо подходит для окон хранения (например, «очистить через 30 дней») и для аудита, когда важно знать время удаления.

How do I handle unique fields (email, username) with soft delete?

Уникальные поля (email, username) мешают повторной регистрации, если старая строка всё ещё содержит значение. Решения: делать уникальность только для не-удалённых строк или переписывать значение при удалении (например, добавлять случайный суффикс). Выбор зависит от требований приватности и аудита.

How do deletes affect foreign keys and related records?

Жёсткое удаление родительской записи может оставить «сирот» (заказы) или запустить каскад, который сотрёт больше, чем ожидалось. Мягкое удаление обычно не меняет внешние ключи — вы просто фильтруете удалённых родителей в приложении, чтобы они не показывались в списках, при этом связи остаются валидными.

Why do deletes cause reporting and analytics problems?

Если исторические строки удаляются, итоговые показатели меняются постфактум: тренды получают пробелы, LTV падает, и финансовые отчёты перестают совпадать с тем, что видели раньше. Мягкое удаление помогает сохранить историю, но только если отчёты однозначно определяют, включать ли удалённые строки или нет.

How do I support GDPR right to erasure while keeping billing history?

Метка «мягко удалён» часто недостаточна для права на стирание по GDPR, потому что персональные данные всё ещё находятся в базе и в бэкапах. Практический подход: сразу ограничить доступ (soft delete), затем безвозвратно удалить или анонимизировать идентифицирующие поля, оставив только неперсональные данные, которые нужны для бухучёта или споров.

What should I check before offering an “undo delete” feature?

Восстановление должно возвращать запись в корректное безопасное состояние без возрождения чувствительных артефактов, которые должны оставаться удалёнными (сессии, токены). Также нужно определить поведение для связанных данных, чтобы не получить «восстановлённый» аккаунт без необходимых связей или разрешений.

How can I implement consistent delete behavior in AppMaster?

Централизуйте поведение удаления, восстановления и очистки, чтобы все API, экраны, экспорты и фоновые задания применяли одинаковые правила. В AppMaster (appmaster.io) это обычно означает добавление полей мягкого удаления в Data Designer и реализацию логики один раз в Business Process, чтобы новые эндпоинты не раскрывали случайно удалённые данные.

Легко начать
Создай что-то невероятное

Экспериментируйте с AppMaster с бесплатной подпиской.
Как только вы будете готовы, вы сможете выбрать подходящий платный план.

Попробовать AppMaster
Мягкое удаление против полного удаления: выберите правильный жизненный цикл данных | AppMaster