+
Любимый Креатив
+
Изделия ручной работы: вещи с характером и вниманием к деталям
+
Сайт находится в разработке и скоро будет доступен
+
Ваш IP: ${safeIp}
+
+
+`
+}
+
+export async function registerIpGate(fastify) {
+ fastify.addHook('onRequest', async (request, reply) => {
+ const allowed = process.env.SITE_ACCESS_IPS
+ if (!allowed) return
+
+ const allowedIps = allowed
+ .split(',')
+ .map((s) => normalizeIp(s.trim()))
+ .filter(Boolean)
+
+ if (allowedIps.length === 0) return
+
+ const urlPath = request.url.split('?')[0]
+
+ if (EXCLUDED_PATHS.includes(urlPath)) return
+
+ if (allowedIps.includes(normalizeIp(request.ip))) return
+
+ return reply.code(403).type('text/html').send(build403Html(request.ip))
+ })
+}
diff --git a/server/src/routes/auth.js b/server/src/routes/auth.js
index 719e90e..54a36c3 100644
--- a/server/src/routes/auth.js
+++ b/server/src/routes/auth.js
@@ -204,4 +204,18 @@ export async function registerAuthRoutes(fastify) {
})
return { user: mapUserForClient(updated) }
})
+
+ fastify.delete('/api/me', { preHandler: [fastify.authenticate] }, async (request, reply) => {
+ const userId = request.user.sub
+
+ const ACTIVE_STATUSES = ['DRAFT', 'PENDING_PAYMENT', 'PAID', 'IN_PROGRESS', 'SHIPPED', 'READY_FOR_PICKUP']
+
+ const activeOrders = await prisma.order.findMany({
+ where: { userId, status: { in: ACTIVE_STATUSES } },
+ select: { id: true },
+ })
+
+ await prisma.user.delete({ where: { id: userId } })
+ return { ok: true, activeOrderIds: activeOrders.map((o) => o.id) }
+ })
}
diff --git a/shared/constants/order-status.js b/shared/constants/order-status.js
index 7795eb7..6d9a54e 100644
--- a/shared/constants/order-status.js
+++ b/shared/constants/order-status.js
@@ -1,13 +1,13 @@
export const ORDER_STATUSES = Object.freeze([
- 'DRAFT',
- 'PENDING_PAYMENT',
- 'PAID',
- 'IN_PROGRESS',
- 'SHIPPED',
- 'READY_FOR_PICKUP',
- 'DONE',
- 'CANCELLED',
-])
+ "DRAFT",
+ "PENDING_PAYMENT",
+ "PAID",
+ "IN_PROGRESS",
+ "SHIPPED",
+ "READY_FOR_PICKUP",
+ "DONE",
+ "CANCELLED",
+]);
/**
* Допустимые переходы статусов, доступные админу.
@@ -15,24 +15,24 @@ export const ORDER_STATUSES = Object.freeze([
* Для IN_PROGRESS: объект с ключами по deliveryType.
*/
export const ADMIN_ORDER_TRANSITIONS = Object.freeze({
- DRAFT: ['PENDING_PAYMENT', 'CANCELLED'],
- PENDING_PAYMENT: ['PAID', 'CANCELLED'],
- PAID: ['IN_PROGRESS', 'CANCELLED'],
+ DRAFT: ["PENDING_PAYMENT", "CANCELLED"],
+ PENDING_PAYMENT: ["PAID", "CANCELLED"],
+ PAID: ["IN_PROGRESS", "CANCELLED"],
IN_PROGRESS: Object.freeze({
- delivery: ['SHIPPED', 'CANCELLED'],
- pickup: ['READY_FOR_PICKUP', 'CANCELLED'],
+ delivery: ["SHIPPED", "CANCELLED"],
+ pickup: ["READY_FOR_PICKUP", "CANCELLED"],
}),
-})
+});
export function getNextAdminStatuses(from, deliveryType) {
- const transition = ADMIN_ORDER_TRANSITIONS[from]
- if (!transition) return []
- if (Array.isArray(transition)) return [...transition]
- return transition[deliveryType] ? [...transition[deliveryType]] : []
+ const transition = ADMIN_ORDER_TRANSITIONS[from];
+ if (!transition) return [];
+ if (Array.isArray(transition)) return [...transition];
+ return transition[deliveryType] ? [...transition[deliveryType]] : [];
}
export function canTransitionAdminOrderStatus(order, next) {
- const from = order.status
- if (from === next) return true
- return getNextAdminStatuses(from, order.deliveryType).includes(next)
+ const from = order.status;
+ if (from === next) return true;
+ return getNextAdminStatuses(from, order.deliveryType).includes(next);
}
diff --git a/Требования Роскомнадзора к сайтам 2026_ чек-лист для бизнеса copy.md b/Требования Роскомнадзора к сайтам 2026_ чек-лист для бизнеса copy.md
new file mode 100644
index 0000000..78f16b4
--- /dev/null
+++ b/Требования Роскомнадзора к сайтам 2026_ чек-лист для бизнеса copy.md
@@ -0,0 +1,157 @@
+---
+title: "Требования Роскомнадзора к сайтам 2026: чек-лист для бизнеса"
+source: "https://www.klerk.ru/blogs/roskom24/650389/#chapter--4-cookie-uvedomlenie-i-politika"
+author:
+ - "[[Закон и бизнес | Онлайн услуги 24]]"
+published: 2025-06-10
+created: 2026-05-23
+description: "С 30 мая 2025 года в России вступили в силу изменения в законодательство о персональных данных. Для бизнеса — это не просто очередная «формальность», а вопрос безопасности и выживания."
+tags:
+ - "clippings"
+---
+Роскомнадзор усилил контроль за сайтами, включая автоматическую проверку с использованием ИИ. Теперь даже незначительные, по мнению бизнеса, нарушения могут привести **к штрафам до 18 миллионов рублей или блокировке сайта**.
+
+Если у вас есть сайт, вы — оператор персональных данных. А значит, обязаны соблюдать [ФЗ-152 «О персональных данных»](https://www.klerk.ru/cdoc/view/federalnyj-zakon-ot-27072006-no-152-fz-o-personalnyh-dannyh/). Даже если вы ИП, самозанятый или оказываете услуги онлайн. Ниже — актуальный чек-лист на 2026 год, который поможет не попасть под штраф и не дать конкурентам «закопать» ваш бизнес через жалобу в Роскомнадзор.
+
+## ✅ 1. Политика обработки персональных данных на сайте
+
+### Что это
+
+Официальный документ, размещенный на сайте (*обычно в подвале*), который описывает:
+
+- какие данные вы собираете;
+- как их обрабатываете;
+- кому передаете и на каких основаниях.
+
+### Требования 2026
+
+- Обязательно актуальная редакция.
+- Полный перечень обрабатываемых данных (*имя, email, телефон, cookies и т.д.*).
+- Указание целей и оснований обработки.
+- Контактные данные оператора.
+- Ссылки на формы согласия и порядок отзыва.
+
+📌 **Ошибка №1** — скачать шаблон и забыть про него. Политика должна соответствовать именно вашему бизнесу и интеграциям на сайте.
+
+## ✅ 2. Согласие на обработку персональных данных
+
+### Где должно быть
+
+- во всех формах на сайте: заявки, обратная связь, регистрация, квизы, покупка, консультации;
+- при подписке на рассылку;
+- в онлайн-чате, если сохраняются данные.
+
+### Требования 2026
+
+- Согласие должно быть **добровольным, конкретным, информированным и однозначным**.
+- Включает: ФИО, перечень данных, цель обработки, срок хранения, право отзыва.
+- Отдельное согласие на передачу данных третьим лицам (*например, CRM-системам*).
+- Техническая реализация: **отдельный чекбокс с обязательной активацией**, а не просто фраза «нажимая кнопку, вы соглашаетесь».
+
+📌 **Ошибка №2** — отсутствие чекбокса или невидимый текст, отсутствие Log файлов позволяющих доказать получение согласия на обработку персональных данных от пользователя сайта.
+
+## ✅ 3. Уведомление Роскомнадзора о начале обработки персональных данных
+
+### Кто обязан
+
+Любой, кто собирает ПДн через сайт — даже ИП и самозанятые.
+
+### Требования 2026
+
+- До начала обработки нужно подать уведомление через портал Роскомнадзора.
+- Указать все сведения: цели, способы обработки, меры безопасности, перечень используемых информационных систем.
+- Отдельно — факт трансграничной передачи, если используете иностранные сервисы.
+
+📌 **Ошибка №3** — не уведомили Роскомнадзор, потому что «сайт только визитка». Даже форма обратной связи — уже обработка ПДн.
+
+## ✅ 5. Юридическая информация в подвале сайта
+
+Что должно быть ([*ч. 2 ст. 10 ФЗ № 149-ФЗ «Об информации, информационных технологиях и о защите информации»*](https://www.klerk.ru/cdoc/view/federalnyj-zakon-ot-27072006-no-149-fz-ob-informacii-informacionnyh-tehnologiah-i-o-zasite-informacii/stata-10-rasprostranenie-informacii-ili-predostavlenie-informacii/#p_64595)):
+
+- Полное наименование владельца сайта.
+- Адрес места нахождения.
+- Актуальные контактные данные.
+
+### Почему это важно
+
+Размещение недостоверных сведений может привести к привлечению к административной ответственности по [статье 14.4 КоАП](https://www.klerk.ru/cdoc/view/kodeks-ob-administrativnyh-pravonaruseniah-koap-rf/stata-144-prodaza-tovarov-vypolnenie-rabot-libo-okazanie-naseleniu-uslug-nenadlezasego-kacestva-ili-s-naruseniem-ustanovlennyh-zakonodatelstvom-rossijskoj-federacii-trebovanij/) (*нарушение законодательства о рекламе*), а также к гражданско-правовой ответственности за причиненный ущерб.
+
+📌 **Ошибка №5** — указание только бренда или торговой марки без юр. лица.
+
+## ✅ 6. Российский хостинг и запрет трансграничной передачи
+
+### Суть
+
+Использование **иностранных серверов и облаков** приравнивается к трансграничной передаче ПДн.
+
+### Требования
+
+- Хостинг сайта — только на серверах, физически размещенных в России.
+- Подтверждение от хостинг-провайдера.
+- Запрет на хранение ПДн в Google Drive, Notion, Dropbox и т.д.
+- Meta