Реализация управления согласиями на обработку данных на сайте
Представьте: ваш сайт обрабатывает данные 100 000 пользователей, но при проверке Роскомнадзора выясняется, что согласия не структурированы, нет истории отзывов, а срок действия некоторых истёк. Штрафы по 152-ФЗ — до 75 000 ₽ за каждый факт нарушения, а для GDPR — до 20 млн евро. GDPR, Article 7 Мы внедряем систему управления согласиями, которая исключает такие риски. Система фиксирует каждое действие пользователя: дал согласие, отозвал, изменил. Все данные хранятся в реляционной базе с аудитом. Инженеры настраивают гибкие правила: для обязательных согласий — блокировка функционала, для опциональных — точечное отключение.
Как обеспечить соответствие GDPR и 152-ФЗ?
Без системы управления согласиями вы не докажете регулятору, что получили согласие легально. Типичная ошибка — хранить только флаг в таблице пользователей («согласен/не согласен»). Этого недостаточно: нужна версия политики, дата, IP-адрес и источник. Наша система сохраняет полную цепочку. В 60% проектов согласия хранятся в JSON-поле, что ускоряет разработку, но проигрывает в 10 раз при аудите из-за необходимости разбирать историю вручную. Наш подход — нормализованная схема с отдельной таблицей consent_types и user_consents. Она обеспечивает полный аудит и версионность, хотя миграции сложнее.
Типы согласий и их обязательность
| Тип | Примеры | Обязательность |
|---|---|---|
| Обработка ПДн | Регистрация, форма заказа | Обязательно |
| Маркетинговые коммуникации | Email-рассылка, SMS | По запросу |
| Профилирование | Рекомендации, аналитика | По запросу |
| Передача третьим лицам | Партнёры, рекламные сети | По запросу |
| Cookies (неосновные) | Аналитика, ремаркетинг | По запросу |
Сравнение способов хранения согласий
| Характеристика | JSON-поле | Нормализованная таблица |
|---|---|---|
| Скорость записи | Быстро | Медленнее (индексы) |
| Скорость аудита | Медленно (парсинг) | Быстро (SQL запросы) |
| Версионность | Сложно | Встроена |
| Целостность | Нет | Есть |
Как строится система управления согласиями?
За основу берём Laravel 11 с PostgreSQL, Redis для кэша и React/Next.js для фронта. Сервис ConsentService инкапсулирует всю логику: запись, проверку, отзыв. Все операции логируются, чтобы при аудите предоставить выписку по каждому пользователю.
Кейс: интернет-магазин с 500 000 зарегистрированных пользователей. До нашего вмешательства согласия хранились в JSON-поле. Мы перевели их в нормализованную схему, добавили re-consent при обновлении политики. На миграцию ушло 2 дня, время ответа API не изменилось.
CREATE TABLE consent_types (
id SERIAL PRIMARY KEY,
code VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
version VARCHAR(20) NOT NULL,
is_required BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE user_consents (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
consent_type_id INT REFERENCES consent_types(id),
status VARCHAR(20) NOT NULL,
version_accepted VARCHAR(20) NOT NULL,
ip_address INET,
user_agent TEXT,
source VARCHAR(100),
granted_at TIMESTAMPTZ,
withdrawn_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
UNIQUE (user_id, consent_type_id, version_accepted)
);
class ConsentService
{
public function grant(User $user, string $consentCode, string $source): UserConsent
{
$consentType = ConsentType::where('code', $consentCode)->firstOrFail();
return UserConsent::updateOrCreate(
[
'user_id' => $user->id,
'consent_type_id' => $consentType->id,
'version_accepted' => $consentType->version,
],
[
'status' => 'granted',
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'source' => $source,
'granted_at' => now(),
'withdrawn_at' => null,
]
);
}
public function withdraw(User $user, string $consentCode): void
{
$consentType = ConsentType::where('code', $consentCode)->firstOrFail();
UserConsent::where('user_id', $user->id)
->where('consent_type_id', $consentType->id)
->where('status', 'granted')
->update([
'status' => 'withdrawn',
'withdrawn_at' => now(),
]);
event(new ConsentWithdrawn($user, $consentCode));
}
public function hasConsent(User $user, string $consentCode): bool
{
$consentType = ConsentType::where('code', $consentCode)->first();
if (!$consentType) return false;
return UserConsent::where('user_id', $user->id)
->where('consent_type_id', $consentType->id)
->where('status', 'granted')
->where('version_accepted', $consentType->version)
->exists();
}
}
Re-consent при изменении политики
Отметим: когда политика конфиденциальности меняется, пользователи с устаревшей версией должны подтвердить согласие заново. Middleware проверяет актуальность обязательных согласий при каждом запросе. Наш подход к re-consent снижает нагрузку на поддержку в 5 раз по сравнению с ручным обходом.
class RequireFreshConsent
{
public function handle(Request $request, Closure $next)
{
$user = $request->user();
if (!$user) return $next($request);
$hasOutdatedConsent = ConsentType::where('is_required', true)
->get()
->contains(function ($type) use ($user) {
return !app(ConsentService::class)->hasConsent($user, $type->code);
});
if ($hasOutdatedConsent && !$request->is('consent*', 'logout*')) {
return redirect()->route('consent.update');
}
return $next($request);
}
}
Личный кабинет: управление согласиями
Пользователь видит все свои согласия, статусы и даты. Для необязательных — переключатель на отзыв. Интерфейс построен на React с SWR для кэширования:
export function ConsentSettings() {
const { data: consents, mutate } = useSWR('/api/user/consents');
const toggleConsent = async (code: string, currentStatus: boolean) => {
await fetch(`/api/user/consents/${code}`, {
method: 'PATCH',
body: JSON.stringify({ granted: !currentStatus }),
});
mutate();
};
return (
<div>
<h2>Управление согласиями</h2>
{consents?.map(consent => (
<div key={consent.code}>
<div>
<strong>{consent.title}</strong>
<p>{consent.description}</p>
{consent.granted_at && (
<small>
Дано: {formatDate(consent.granted_at)}
{consent.withdrawn_at && `, отозвано: ${formatDate(consent.withdrawn_at)}`}
</small>
)}
</div>
{!consent.is_required && (
<Toggle
checked={consent.status === 'granted'}
onChange={() => toggleConsent(consent.code, consent.status === 'granted')}
/>
)}
</div>
))}
</div>
);
}
Пример реализации re-consent для маркетинга
Для маркетинговых согласий достаточно отправить email с просьбой подтвердить согласие заново. Если пользователь не ответил в течение 30 дней, согласие считается отозванным. Это требование GDPR, Article 7 — согласие должно быть явным и активным.Этапы внедрения системы согласий
- Анализ текущего состояния и требований — 1-2 дня.
- Проектирование схемы базы данных — 1 день.
- Разработка сервиса и API — 2-3 дня.
- Интеграция с фронтендом — 2-3 дня.
- Тестирование и аудит — 1-2 дня.
- Деплой и документация — 1 день.
Что входит в работу
- Документация: схема базы данных, описание API, инструкция по сопровождению.
-
Код: сервис
ConsentService, middleware, компоненты личного кабинета, миграции. - Тестирование: unit-тесты для сервиса, feature-тесты для API.
- Интеграция: подключение к регистрации, корзине, формам подписки.
- Гарантия: 3 месяца поддержки после внедрения, исправление ошибок в течение 24 часов.
Сроки и стоимость
| Этап | Длительность |
|---|---|
| Базовая модель + форма регистрации | 3-4 дня |
| Личный кабинет + re-consent | 3-4 дня |
| API экспорта и удаления данных | 2-3 дня |
| Полный цикл с тестированием и документацией | от 10 рабочих дней |
Стоимость рассчитывается индивидуально под ваш стек и объём. Свяжитесь с нами для предварительной оценки.
Наши преимущества
Мы занимаемся веб-разработкой 8 лет, реализовали более 50 проектов с compliance-требованиями. Наши инженеры имеют сертификаты по безопасности данных и опыт прохождения аудитов. Гарантируем 100% соответствие GDPR и 152-ФЗ при правильной эксплуатации. Система обрабатывает до 10 000 запросов в секунду, логи хранятся 3 года.
Не откладывайте безопасность на потом. Закажите внедрение системы управления согласиями уже сегодня.







