Документация: этапы по фазам, решения D-026…D-033

- Новый порядок этапов (D-026): фаза 1 — концепт на dev без внешних
  сервисов (1b сайт, 1c вход, 1d ключи, 1e счёт и демо-оплата,
  1f демо-выдача, 1g продления, 1h рефералы); фаза 2 — Telegram;
  фаза 3 — ALTCHA, ЮKassa, почта, Twenty, Chatwoot, Umami, выдача
  через API и публичный запуск; фаза 4 — звёзды и эквайринги.
- Решения: демо-оплата по списку IP (D-027), выдача ключей через
  адаптер manual/demo/api (D-028), страницы сайта из блоков Payload
  (D-029), пересборка через revalidatePath (D-030), RU-адрес у mass
  (D-031), счётчик свободных серверов (D-032), переводы на 5 языков
  в каждом этапе (D-033).
- Тексты описывают работающий продукт; Вейликс — выделенный IP на
  общем сервере; Telegram поддержки — @veilix_support; сроки ответа
  не обещаем; VPN-серверы не ведут журналов.
- Ссылки на этапы во всех документах, Q-12 решён (ЮKassa для RUB),
  R-19 (библиотеки для headless Chromium) сделано.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
andreypr207andClaude Opus 5.5 committed 2026-10-22 03:48:10 +02:00
1 parent 0cad9bae18
commit 515acfb69d
53 files changed
+778 -348

No files matched your search

+51 -20
View File
@@ -21,21 +21,52 @@
## 2. Этапы
Фаза — цифра, этап — буква ([D-026](decisions/D-026-stage-order.md)). Каждый этап делается сразу на 5 языках; тексты описывают работающий продукт.
| Этап | Содержание | Статус |
|---|---|---|
| [0](stages/stage-0-docs.md) | Документация | готово |
### 2.1 Фаза 1. Концепт без внешних сервисов, на dev
| Этап | Содержание | Статус |
|---|---|---|
| [1a](stages/stage-1a-foundation.md) | Фундамент: Next + Payload, сайты, домены, языки, валюты, темы | готово |
| [1b](stages/stage-1b-marketing.md) | Маркетинговые страницы обоих брендов, контент, формы с ALTCHA, SEO, юр. тексты | не начат |
| [1c](stages/stage-1c-auth.md) | Вход по коду, почта, сессии | не начат |
| [1d](stages/stage-1d-billing.md) | Биллинг без эквайринга, оформление заказа, продления | не начат |
| [1e](stages/stage-1e-keys.md) | Ключи и подключения, ручная выдача | не начат |
| [1f](stages/stage-1f-cabinet.md) | Веб-кабинеты обоих брендов | не начат |
| [1g](stages/stage-1g-referral.md) | Реферальная программа | не начат |
| [1h](stages/stage-1h-launch.md) | Переводы, Umami и баннер cookies, PageSpeed, выкладка в prod | не начат |
| [2](stages/stage-2-support-crm.md) | Chatwoot и Twenty CRM | не начат |
| [3](stages/stage-3-telegram.md) | Telegram: боты, MiniApp, вход и привязка | не начат |
| [4](stages/stage-4-payments.md) | Платёжные системы: Stripe, RUB-процессинг, крипта | не начат |
| [5](stages/stage-5-keys-automation.md) | Автоматизация выдачи ключей | обсуждение при старте |
| [1b](stages/stage-1b-marketing.md) | Сайт: страницы обоих брендов из блоков Payload, FAQ, юридические черновики, SEO; формы — только интерфейс | в работе |
| [1c](stages/stage-1c-auth.md) | Вход по коду, сессии; письма — в журнал | не начат |
| [1d](stages/stage-1d-keys.md) | Ключи и подключения: ручное создание в админке, ключи в кабинете | не начат |
| [1e](stages/stage-1e-billing.md) | Счёт и оплата: заказы, баланс, демо-оплата, оформление заказа | не начат |
| [1f](stages/stage-1f-provisioning.md) | Выдача ключей «Демо» — эмулятор API выдачи | не начат |
| [1g](stages/stage-1g-renewals.md) | Продления: автопродление, льготный период, напоминания | не начат |
| [1h](stages/stage-1h-referral.md) | Реферальная программа | не начат |
### 2.2 Фаза 2. Telegram
| Этап | Содержание | Статус |
|---|---|---|
| [2a](stages/stage-2a-miniapp.md) | MiniApp | не начат |
| [2b](stages/stage-2b-bot.md) | Основной бот | не начат |
| [2c](stages/stage-2c-linking.md) | Связь аккаунтов Telegram и сайта | не начат |
### 2.3 Фаза 3. Реальные сервисы и запуск
| Этап | Содержание | Статус |
|---|---|---|
| [3a](stages/stage-3a-altcha.md) | ALTCHA | не начат |
| [3b](stages/stage-3b-yookassa.md) | ЮKassa: пополнение в RUB | не начат |
| [3c](stages/stage-3c-email.md) | Отправка почты: Postfix, DKIM | не начат |
| [3d](stages/stage-3d-crm.md) | Twenty CRM: заявки с форм | не начат |
| [3e](stages/stage-3e-chatwoot.md) | Chatwoot: виджет, боты поддержки, почта | не начат |
| [3f](stages/stage-3f-analytics.md) | Umami и баннер cookies | не начат |
| [3g](stages/stage-3g-keys-api.md) | Выдача ключей через API | обсуждение при старте |
| [3h](stages/stage-3h-launch.md) | Публичный запуск в prod | не начат |
### 2.4 Фаза 4. Позже
| Этап | Содержание | Статус |
|---|---|---|
| [4a](stages/stage-4a-stars.md) | Звёзды Telegram | обсуждение при старте |
| [4b](stages/stage-4b-acquiring.md) | Западные эквайринги и криптовалюта | обсуждение при старте |
## 3. Как запускать этап в новой сессии
@@ -54,13 +85,14 @@
| Q-02 | Цены mass в USD, суммы пополнения и реферального бонуса | Mass: «Месяц» $6.99, «Год» $69.90. Пополнение: dedicated — 2 500, 5 000, 10 000 ₽ и $25, $50, $100; mass — 700, 2 100, 6 990 ₽ и $7, $21, $70. Реферальный бонус — не деньги, а 30 дней к ключу обоим | [01-product.md](01-product.md), разделы 6 и 10; [04-billing.md](04-billing.md), разделы 4 и 11; [D-025](decisions/D-025-referral-days.md) |
| Q-03 | Валюта по умолчанию для нового посетителя | По языку: ru → RUB, остальные → USD; настраивается у домена | [06-i18n.md](06-i18n.md), раздел 6 |
| Q-04 | Валюта аккаунта | Задаётся при регистрации из выбранной; меняется, пока баланс нулевой и нет ключей; дальше — через поддержку | [04-billing.md](04-billing.md), раздел 2 |
| Q-05 | WG-конфиги mass на этапе 1 | Конфиги, добавленные администратором, по странам; другая страна — через поддержку; автоматически — этап 5 | [D-020](decisions/D-020-key-models.md) |
| Q-05 | WG-конфиги mass на этапе 1 | Конфиги, добавленные администратором, по странам; другая страна — через поддержку. Позже — адаптер выдачи: демо-эмулятор (этап 1f), API (3g) | [D-020](decisions/D-020-key-models.md) |
| Q-06 | Где Umami | На этом сервере, без Docker, под пользователем `umami`; панель — `umi.veilix.cc` | [D-018](decisions/D-018-analytics.md) |
| Q-07 | Как запускать сервисы | Каждый под своим пользователем ОС: vx_dev (dev), vx_prod (prod), umami; systemd user-юниты | [D-004](decisions/D-004-environments.md) |
| Q-08 | Email поддержки брендов | `help@veilix.app` и `help@veilixvpn.com` | [01-product.md](01-product.md), раздел 11 |
| Q-09 | Часовой пояс часов поддержки | Московское время | [01-product.md](01-product.md), раздел 11 |
| Q-12 | RUB-процессинг и криптопроцессинг: какие провайдеры | RUB — ЮKassa, только пополнения (этап 3b). Криптовалюта — этап 4b, провайдера выбираем на нём | [D-016](decisions/D-016-payments.md); [08-integrations.md](08-integrations.md), раздел 7 |
| Q-15 | Защита prod от сессий Claude | Отдельно не нужна: сессии Claude работают под vx_dev без доступа к prod, а под vx_prod нет ни редактора, ни ИИ-агентов | [D-004](decisions/D-004-environments.md) |
| Q-16 | Где принимать почту поддержки | Ящики на внешнем почтовом хостинге, их настраивает пользователь (R-18). На этапе 2 письма из них забирает Chatwoot; до этого на сайте только адрес | [09-infrastructure.md](09-infrastructure.md), раздел 6; [08-integrations.md](08-integrations.md), раздел 4 |
| Q-16 | Где принимать почту поддержки | Ящики на внешнем почтовом хостинге, их настраивает пользователь (R-18). На этапе 3e письма из них забирает Chatwoot; до этого на сайте только адрес | [09-infrastructure.md](09-infrastructure.md), раздел 6; [08-integrations.md](08-integrations.md), раздел 4 |
| Q-19 | Реферальный бонус днями: крайние случаи | Приглашённому тоже 30 дней; ключ готовится — дни добавятся при выдаче; «последний ключ» — купленный последним из неистёкших и неотменённых; такого нет — дни ждут следующего ключа; возврат заказа приглашённого бонус не отменяет | [D-025](decisions/D-025-referral-days.md); [04-billing.md](04-billing.md), раздел 11 |
### 4.2 Открытые
@@ -69,10 +101,9 @@
| № | Вопрос | Предложение | Нужно к этапу |
|---|---|---|---|
| Q-10 | Имена Telegram-ботов: 2 основных, 2 поддержки, тестовые | — | 3 |
| Q-11 | Оплата в Telegram: Stars, внешняя страница или только с баланса | — | 3 |
| Q-12 | RUB-процессинг (KZ, TR) и криптопроцессинг: какие провайдеры | — | 4 |
| Q-13 | Юрлицо для юридических текстов | Пока заглушки | 1h |
| Q-14 | Куда складывать бэкапы prod-базы | — | 1h |
| Q-17 | Нужны ли разные аккаунты одного провайдера для разных брендов | Пока нет. Если понадобятся — платёжной системе добавим поле «только для сайтов» | 4 |
| Q-18 | Кто запускает выкладку в prod | Пользователь одной командой; по желанию — sudo-правило, разрешающее vx_dev запускать только команду выкладки от имени vx_prod | 1h |
| Q-10 | Имена Telegram-ботов: 2 основных, 2 поддержки, тестовые | — | 2a, 3e |
| Q-11 | Оплата в Telegram: Stars, внешняя страница или только с баланса | До этапа 4a — демо-оплата и баланс | 2a, 4a |
| Q-13 | Юрлицо для юридических текстов | Пока заглушки | 3b, 3h |
| Q-14 | Куда складывать бэкапы prod-базы | — | 3h |
| Q-17 | Нужны ли разные аккаунты одного провайдера для разных брендов | Пока нет. Если понадобятся — платёжной системе добавим поле «только для сайтов» | 3b, 4b |
| Q-18 | Кто запускает выкладку в prod | Пользователь одной командой; по желанию — sudo-правило, разрешающее vx_dev запускать только команду выкладки от имени vx_prod | 3h |
+15 -13
View File
@@ -30,8 +30,8 @@
1. Сайт: главная, цены, локации, поддержка, юридические страницы.
2. Веб-кабинет, в том числе оформление заказа (оформление живёт на my.*, а не на сайте).
3. MiniApp в Telegram — этап 3.
4. Два Telegram-бота: основной (команды, MiniApp, уведомления) и бот поддержки, подключённый к Chatwoot. Этапы 2–3.
3. MiniApp в Telegram — этап 2a.
4. Два Telegram-бота: основной (команды, MiniApp, уведомления) и бот поддержки, подключённый к Chatwoot. Этапы 2b и 3e.
## 4. Термины
@@ -46,7 +46,7 @@
## 5. Dedicated (Вейликс)
1. Ключ — это индивидуальный IP в выбранной стране. Страна выбирается при покупке и не меняется никогда. Нужна другая страна — пользователь покупает новый ключ в другой локации и отключает автопродление старого. Отдельного функционала смены страны нет.
1. Ключ — это индивидуальный IP в выбранной стране: выделенный адрес на общем сервере, а не отдельный сервер. Страна выбирается при покупке и не меняется никогда. Нужна другая страна — пользователь покупает новый ключ в другой локации и отключает автопродление старого. Отдельного функционала смены страны нет.
2. В каждый ключ входит выделенный RU-адрес: работает и как прямое соединение, и как мост в обе стороны.
3. До 5 устройств на ключ (поле тарифа), все с одним IP. WireGuard — по конфигу на устройство. Xray — ссылка для Happ (обычная или зашифрованная crypt-ссылка Happ, которая скрывает адрес подписки).
4. Тариф — ценовой уровень со своим набором стран:
@@ -58,18 +58,19 @@
| Дальние локации | AU, BR | 9 900 ₽ | 4 999 ₽ | $99 / $49 |
5. Первый месяц дороже, потому что включает подготовку сервера: выделение адреса, настройку протоколов и маршрутизации. Период — месяц.
6. Статусы локаций: «Серверы в наличии» и «Установим за 24 часа». Оплаченный период начинается с момента выдачи ключа. На этапе 1 ключи выдаёт администратор вручную, поэтому так работает для обоих статусов.
6. Статусы локаций: «Серверы в наличии» и «Установим за 24 часа». Оплаченный период начинается с момента выдачи ключа. Ключ выдаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)): администратор вручную, демо-эмулятор (этап 1f) или API (этап 3g).
7. Каждый ключ продлевается независимо, в свою дату.
## 6. Mass (ВейликсВПН)
1. Ключ включает все страны тарифа. Страна при покупке не выбирается: список стран на сайте только показывает, что входит в ключ.
2. Happ — одна ссылка со всеми странами. WireGuard — пользователь может получить конфиги любой страны тарифа. На этапе 1 это конфиги, которые добавил администратор, по странам; нужна другая страна — через поддержку. Автоматически — на этапе 5.
2. Happ — одна ссылка со всеми странами. WireGuard — пользователь может получить конфиги любой страны тарифа: их создаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)).
3. Тарифы: «Месяц» 699 ₽ и «Год» 6 990 ₽ («582 ₽ в месяц, экономия 1 398 ₽»). Платы за подключение и доплат за страну нет: первый период стоит столько же, сколько продление.
4. До 5 устройств на ключ (поле тарифа).
5. Статусы локаций: «Включено» и «Скоро». Локации «Скоро» показываются, но не работают.
6. В кабинете — «Список ключей», как у dedicated; внутри ключа ссылка Xray и конфиги WG. Формулировки «текущая/запасная локация» из макета не используем.
7. Цены в USD (в макете их нет, решение Q-02): «Месяц» $6.99, «Год» $69.90.
8. В каждый ключ входит RU-адрес, как у dedicated; страной тарифа он не считается ([D-031](decisions/D-031-mass-ru-address.md)).
## 7. Локации из макета
@@ -108,21 +109,22 @@
| AU | Австралия | Сидней | 24 часа | дальние |
| BR | Бразилия | Сан-Паулу | 24 часа | дальние |
Координаты для карты — в массиве `L(...)` в `design/handoff/project/Price.dc.html`. Количество свободных серверов из MiniApp (NL 12, DE 10, …) — демо-данные. Показывать ли счётчик на сайте — решается в этапе 1b.
Координаты для карты — в массиве `L(...)` в `design/handoff/project/Price.dc.html`. Количество свободных серверов из MiniApp (NL 12, DE 10, …) — демо-данные. На сайте счётчик показывается, если поле заполнено ([D-032](decisions/D-032-free-servers.md)).
## 8. Пользователи
1. Аккаунты раздельные по сайтам: один email на veilix.app и на veilixvpn.com — два разных пользователя.
2. Регистрация и вход — одно поле email и одноразовый код. Отдельной регистрации нет.
3. Telegram (этап 3): аккаунт можно создать по Telegram без почты. Почта привязывается кодом, после этого работает вход на сайте. На сайте есть кнопка «Войти через Telegram». Правила объединения аккаунтов в пределах сайта — [05-auth.md](05-auth.md).
3. Telegram (этапы 2a–2c): аккаунт можно создать по Telegram без почты. Почта привязывается кодом, после этого работает вход на сайте. На сайте есть кнопка «Войти через Telegram». Правила объединения аккаунтов в пределах сайта — [05-auth.md](05-auth.md).
## 9. Деньги
1. У пользователя есть счёт (баланс) в валюте аккаунта.
2. Валюты — отдельный справочник: RUB и USD. Переключатель валюты не зависит от языка: из России часто заходят через VPN, поэтому страна по IP для выбора валюты не годится. По умолчанию валюта зависит от языка: ru → RUB, остальные → USD.
3. Платёжные системы привязаны только к валютам. Где система доступна, следует из цепочки: валюты → домены, на которых они включены → сайты:
a. RUB — процессинги, принимающие карты РФ (вероятно, из Казахстана и Турции), без автосписаний. ЮKassa — опционально, только для пополнений;
b. USD — Stripe (карты, сохранение карты, автосписания) и криптовалюта.
a. RUB — ЮKassa, только пополнения, без автосписаний (этап 3b);
b. USD — Stripe (карты, сохранение карты, автосписания) и криптовалюта (этап 4b);
c. для проверок — платёжная система «Демо», видна только с разрешённых IP ([D-027](decisions/D-027-demo-payments.md)).
4. Карта привязывается к аккаунту, а не к ключу (Stripe). Отвязать карту можно в аккаунте.
5. Продление: у каждого ключа галочка автопродления и кнопка «Продлить сейчас». Сначала списывается баланс, нехватка — с карты.
6. Не хватило денег: льготный период 3 дня (ключ работает), затем ключ истекает. Напоминание за 3 дня до окончания.
@@ -143,10 +145,10 @@
## 11. Поддержка и заявки
1. Страница поддержки: Telegram (бот поддержки бренда) и email, FAQ по разделам, форма связи.
2. Почта поддержки: `help@veilix.app` (dedicated) и `help@veilixvpn.com` (mass); в макете были домены .cc. Ящики — на внешнем почтовом хостинге; на этапе 2 письма из них забирает Chatwoot. До этого на сайте только адрес.
2. Почта поддержки: `help@veilix.app` (dedicated) и `help@veilixvpn.com` (mass); в макете были домены .cc. Ящики — на внешнем почтовом хостинге; на этапе 3e письма из них забирает Chatwoot. До этого на сайте только адрес. Telegram поддержки — `@veilix_support` у обоих брендов, пока нет ботов поддержки (этап 3e).
3. Заявка «Нужны индивидуальные условия» (dedicated) и «Нужны особые условия» (mass): имя, email, Telegram, WhatsApp, коротко о задаче.
4. Заявки и обращения сохраняются в Payload и приходят на почту поддержки (этап 1), затем уходят в Twenty CRM и Chatwoot (этап 2).
5. Часы поддержки из макета: с 10 до 20 по московскому времени в рабочие дни.
4. До этапов 3d и 3e формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)). Затем заявки уходят в Twenty CRM (3d), обращения — в Chatwoot (3e).
5. Часы поддержки: с 10 до 20 по московскому времени в рабочие дни. Сроки ответа на сайте не обещаем.
## 12. Языки
@@ -154,4 +156,4 @@ en (по умолчанию, без префикса в URL), ru, de, fr, es. П
## 13. Юридические страницы
Условия использования, политика конфиденциальности, политика возвратов, политика cookies. Черновики на RU и EN готовятся в этапе 1b, с заглушками вместо данных юрлица (Q-13). Это черновики, не юридическая консультация: перед запуском — показать юристу. Stripe при подключении проверяет эти страницы.
Условия использования, политика конфиденциальности, политика возвратов, политика cookies. Черновики на 5 языках готовятся в этапе 1b, с заглушками вместо данных юрлица (Q-13). В политике конфиденциальности: VPN-серверы не ведут журналов ([10-security.md](10-security.md), раздел 6). Это черновики, не юридическая консультация: перед запуском — показать юристу. Stripe при подключении проверяет эти страницы.
+9 -9
View File
@@ -16,9 +16,9 @@
| Vitest | 5.x | модульные тесты |
| next-intl | 4.x | переводы интерфейса, префиксы языков в URL |
| Nodemailer | через `@payloadcms/email-nodemailer` | транспорты SMTP, sendmail, «только журнал» |
| ALTCHA | 3.x | капча без третьих сторон |
| grammY | 1.x | Telegram-боты, этап 3 |
| Stripe SDK | актуальный | этап 4 |
| ALTCHA | 3.x | капча без третьих сторон, этап 3a |
| grammY | 1.x | Telegram-боты, этапы 2a–2c |
| Stripe SDK | актуальный | этап 4b |
Точные версии закреплены в `package.json`: на этапе 1a — Next 16.4.2, Payload 3.91.0, React 19.3.1, next-intl 4.14.9, Tailwind 4.3.3, pnpm 12.14. На старте 1a Payload 4 был в бете (4.0.0-beta.3), поэтому начали на 3.91 ([D-002](decisions/D-002-payload-version.md)). Телеметрия Next.js и Payload выключена.
@@ -47,14 +47,14 @@ src/
(front)/m/[host]/[locale]/[currency]/(site)/… — маркетинговые сайты
(front)/c/[host]/[locale]/(shell)/… — кабинет с навигацией
(front)/c/[host]/[locale]/(plain)/… — вход и оформление заказа
(front)/t/[host]/… — MiniApp (этап 3)
(front)/t/[host]/… — MiniApp (этап 2a)
(front)/context.ts — домен, язык и валюта страницы, данные оболочек
svc/… — свои эндпоинты: health, internal/domains; дальше ALTCHA, вебхуки
payload/
collections/ access/ fields/ hooks/ components/
core/ — бизнес-логика без привязки к UI
sites.ts domains/ routing/ currencies/ payments/ — этап 1a
billing/ keys/ auth/ referral/ email/ geo/ — следующие этапы
billing/ keys/ provisioning/ auth/ referral/ email/ geo/ — следующие этапы
brands/
dedicated/ mass/ — различия брендов; страницы и компоненты — с этапа 1b
ui/ — общие компоненты: оболочки сайта и кабинета, переключатели, тема, логотип, иконки
@@ -67,7 +67,7 @@ scripts/ — служебные скрипты (очистк
Корневые layout сайта и кабинета дают только документ: `<html>` с `lang`, `data-site` и скриптом темы. Шапка, подвал и навигация — во вложенных группах `(site)`, `(shell)` и `(plain)`.
Бизнес-логика живёт в `core/` и вызывается одинаково из хуков Payload, server actions, вебхуков, фоновых задач и (на этапе 3) бота.
Бизнес-логика живёт в `core/` и вызывается одинаково из хуков Payload, server actions, вебхуков, фоновых задач и (с этапа 2b) бота.
## 4. Окружения
@@ -89,8 +89,8 @@ scripts/ — служебные скрипты (очистк
## 5. Выкладка в prod
1. В dev: изменения схемы оформляются миграцией (`payload migrate:create`), коммит, push в Gitea, тег релиза. До первой выкладки (этап 1h) миграции не накапливаем: перед ней создаём одну начальную по итоговой схеме. Механизм проверен на этапе 1a: миграция, применённая к пустой схеме, создаёт те же таблицы, что push в dev.
2. Выкладка — команда `deploy <тег>` пользователя vx_prod, появится на этапе 1h. Запускает её пользователь; по желанию — sudo-правило, разрешающее vx_dev запускать только эту команду (Q-18). Шаги:
1. В dev: изменения схемы оформляются миграцией (`payload migrate:create`), коммит, push в Gitea, тег релиза. До первой выкладки (этап 3h) миграции не накапливаем: перед ней создаём одну начальную по итоговой схеме. Механизм проверен на этапе 1a: миграция, применённая к пустой схеме, создаёт те же таблицы, что push в dev.
2. Выкладка — команда `deploy <тег>` пользователя vx_prod, появится на этапе 3h. Запускает её пользователь; по желанию — sudo-правило, разрешающее vx_dev запускать только эту команду (Q-18). Шаги:
a. взять тег из Gitea (у vx_prod ключ только на чтение) в новую папку `releases/<дата-тег>`;
b. `pnpm install --frozen-lockfile` и `pnpm build`; ссылки на `shared/.env` и `shared/media`;
c. применить миграции к `veilix_prod`;
@@ -102,7 +102,7 @@ scripts/ — служебные скрипты (очистк
## 6. Рендеринг и кэширование
1. Маркетинговые страницы собираются статически в вариантах «домен × язык × валюта» при первом запросе (ISR) и кэшируются. Proxy выбирает вариант по префиксу языка и cookie валюты.
2. Изменение в админке (цена, статус локации, FAQ) вызывает хук Payload, и Next.js пересобирает затронутые страницы за секунды (on-demand revalidation по тегам). Запасной вариант — плановое обновление раз в 5 минут.
2. Изменение в админке (цена, статус локации, FAQ, текст страницы) вызывает хук Payload, и Next.js пересобирает маркетинговые страницы при следующем заходе (`revalidatePath`, [D-030](decisions/D-030-revalidate-path.md)). Запасной вариант — плановое обновление раз в 5 минут.
3. При оформлении заказа наличие и цена проверяются заново на сервере. Устаревшая страница не может продать то, чего нет.
4. Кабинет рендерится на сервере (SSR) для каждого запроса, без кэша.
5. Маркетинговые домены не ставят cookies, кроме выбора языка, валюты и темы.
+16 -12
View File
@@ -55,7 +55,9 @@ erDiagram
| locales | multi-select из языков конфига | языки контента сайта; en обязателен; домены показывают часть этих языков ([D-023](decisions/D-023-site-locales.md)) |
| supportEmail | email | почта поддержки: `help@veilix.app`, `help@veilixvpn.com` |
| emailFrom | group: name, address | отправитель писем, напр. «Вейликс» <no-reply@veilix.app> |
| supportBot, mainBot | text | имена ботов (этап 3) |
| supportBot | text | Telegram поддержки — имя для ссылки `t.me/…`: пока `veilix_support` у обоих брендов, с этапа 3e — бот поддержки бренда |
| supportHours | text (L) | часы поддержки: «с 10 до 20 по московскому времени в рабочие дни» |
| mainBot | text | имя основного бота (этап 2a) |
| referralEnabled | checkbox | |
| referralBonusDays | number, по умолчанию 30 | бонус «месяц в подарок»: дни срока ключа обоим ([D-025](decisions/D-025-referral-days.md)) |
| topupPresets | array: currency, amounts[] | суммы пополнения в кабинете ([04-billing.md](04-billing.md), раздел 4) |
@@ -63,9 +65,10 @@ erDiagram
| reminderDays | number, по умолчанию 3 | за сколько дней напоминать |
| renewalLeadHours | number, по умолчанию 24 | за сколько часов до окончания пробовать продлить |
| expiringBadgeDays | number, по умолчанию 7 | когда показывать «Истекает» |
| provisioningMode | select `manual` \| `demo` \| `api` | режим выдачи ключей ([D-028](decisions/D-028-provisioning-adapter.md)): `demo` — с этапа 1f, `api` — с 3g |
| seo | group: titleTemplate (L), description (L), ogImage | значения по умолчанию |
На этапе 1a сделаны `code` (после создания не меняется), `name`, `orderPrefix` и `locales`. Остальные поля добавляют этапы, которые ими пользуются: SEO и контакты — 1b, отправитель писем — 1c, сроки и пресеты — 1d и 1f, рефералы — 1g, боты — 3.
На этапе 1a сделаны `code` (после создания не меняется), `name`, `orderPrefix` и `locales`. Остальные поля добавляют этапы, которые ими пользуются: SEO, контакты и часы поддержки — 1b, отправитель писем — 1c, порог «Истекает» — 1d, пресеты пополнения — 1e, режим выдачи — 1f, сроки продлений и напоминаний — 1g, рефералы — 1h, основной бот — 2a.
### 3.2 `domains` — Домены (сайт)
@@ -80,7 +83,7 @@ erDiagram
| localeCurrency | array: locale, currency | валюта по умолчанию для языка: ru → RUB |
| isPrimary | checkbox | основной домен этого типа (у сайта один на каждый тип); используется в ссылках и sitemap |
| indexable | checkbox | разрешена ли индексация (для кабинета и MiniApp — нет) |
| umamiWebsiteId | text | этап 1h |
| umamiWebsiteId | text | этап 3f |
| active | checkbox | |
Язык и валюта по умолчанию должны входить в списки домена, язык в правилах «язык → валюта» не повторяется — это проверяется при сохранении.
@@ -102,13 +105,14 @@ erDiagram
| Поле | Тип | Описание |
|---|---|---|
| name | text | название в админке |
| adapter | select | реализация в коде: `manual`; на этапе 4 — `stripe`, `yookassa`, `crypto_*`, `rucard_*` |
| adapter | select | реализация в коде: `manual`, `demo` (1e, [D-027](decisions/D-027-demo-payments.md)); `yookassa` (3b); `stripe`, `crypto_*` (4b) |
| title | text (L) | что видит пользователь: «Банковская карта», «Карта МИР», «СБП», «Криптовалюта» |
| description | text (L) | подсказка: «USDT, BTC, ETH, курс фиксируется на 15 минут» |
| icon | upload | |
| currencies | multi-select валют | в каких валютах доступна |
| purposes | multi-select `order` \| `topup` | оплата заказа, пополнение |
| visibleToCustomers | checkbox | у `manual` всегда выключено (проверяется при сохранении): ей пользуются только администраторы |
| allowedIps | text | для `demo`: IP и подсети, с которых система видна; пусто — не видна никому |
| mode | select `test` \| `live` | |
| limits | array: currency, min, max | |
| capabilities | только чтение, из адаптера | `recurring`, `refunds`, `saveMethod`; объявлены в `src/core/payments/adapters.ts`, в базе не хранятся |
@@ -133,7 +137,7 @@ erDiagram
| city | text (L) | |
| lat, lng | number | точка города на карте |
| status | select `available` \| `on_demand` \| `soon` | dedicated: «Серверы в наличии» / «Установим за 24 часа»; mass: «Включено» / «Скоро». Чужой для бренда статус не сохранится |
| freeServers | number, необязательное | счётчик (решение о показе — этап 1b) |
| freeServers | number, необязательное | счётчик; на сайте показывается, если заполнен ([D-032](decisions/D-032-free-servers.md)) |
| visible, sort | | |
### 3.7 `tags` — Теги (общие)
@@ -178,8 +182,8 @@ erDiagram
|---|---|---|
| email | email, null | уникален в пределах сайта, хранится в нижнем регистре |
| emailVerifiedAt | date | |
| telegramId | text, null | уникален в пределах сайта (этап 3) |
| telegramUsername, telegramName | text | этап 3 |
| telegramId | text, null | уникален в пределах сайта (этап 2a) |
| telegramUsername, telegramName | text | этап 2a |
| locale | select | язык писем и бота |
| currency | select | валюта аккаунта ([04-billing.md](04-billing.md), раздел 2) |
| balance | number, только чтение | кэш суммы движений по счёту |
@@ -229,7 +233,7 @@ erDiagram
| title | text | «Устройство 1», «Ноутбук» |
| deviceSlot | number | номер устройства для WG/AWG |
| country | relationship → countries | для WG у mass — страна конфига; для RU-адреса — RU |
| isRu | checkbox | подключение к RU-адресу (dedicated) |
| isRu | checkbox | подключение к RU-адресу; у обоих брендов ([D-031](decisions/D-031-mass-ru-address.md)) |
| payload | text, зашифрованное | содержимое конфига или URL |
| fileName | text | имя файла при скачивании |
| status | select `active` \| `revoked` | |
@@ -242,7 +246,7 @@ QR-коды строятся на лету из `payload`, не хранятся
| Статус | Значение |
|---|---|
| `provisioning` | оплачен, готовится. Срок ещё не идёт. На этапе 1 так создаются все ключи: подключения добавляет администратор |
| `provisioning` | оплачен, готовится. Срок ещё не идёт. Подключения создаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)) или администратор |
| `active` | работает, срок идёт с `activatedAt` |
| `grace` | срок истёк, оплата не прошла, ключ ещё работает до `graceUntil` |
| `expired` | истёк, подключения отключаются |
@@ -319,7 +323,7 @@ QR-коды строятся на лету из `payload`, не хранятся
| customer | relationship | |
| currency | | валюта аккаунта |
| amount | number со знаком | `+` зачисление, `−` списание |
| type | select `topup` \| `order_charge` \| `refund` \| `adjustment` \| `payout` | `payout` — возврат денег с баланса на карту (этап 4). Реферальный бонус — не деньги, а дни (5.4) |
| type | select `topup` \| `order_charge` \| `refund` \| `adjustment` \| `payout` | `payout` — возврат денег с баланса на карту (этап 4b). Реферальный бонус — не деньги, а дни (5.4) |
| payment, order, key | relationship | источник записи |
| balanceAfter | number | баланс после записи |
| comment | text | обязателен для `adjustment` |
@@ -339,7 +343,7 @@ QR-коды строятся на лету из `payload`, не хранятся
### 7.1 `pages` — Страницы (сайт)
`slug` (уникальное в сайте: `terms`, `privacy`, `refund`, `cookies`), `title` (L), `content` (L, Lexical), `seo` (title (L), description (L)). Черновики и версии Payload включены.
Страницы сайта из блоков ([D-029](decisions/D-029-pages-blocks.md)): `slug` (уникальное в сайте: `home`, `pricing`, `locations`, `support`, `terms`, `privacy`, `refund`, `cookies`), `title` (L), `layout` (блоки, поля блоков локализованы), `seo` (title (L), description (L), image). Черновики и версии Payload включены. Набор блоков — в `src/payload/blocks/`, описание — по итогам этапа 1b.
### 7.2 `faq` — Вопросы и ответы (сайт)
@@ -353,7 +357,7 @@ QR-коды строятся на лету из `payload`, не хранятся
### 7.4 `leads` — Заявки (сайт)
`type` (`individual_terms` \| `contact`), `name`, `email`, `telegram`, `whatsapp`, `topic`, `message`, `locale`, `pageUrl`, `customer`, `status` (`new` \| `in_progress` \| `done` \| `spam`), `crmId` и `chatwootId` (этап 2), `ipHash`.
Этап 3d. До него формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)); нужна ли коллекция как буфер перед Twenty — решаем на этапе. Поля: `type` (`individual_terms` \| `contact`), `name`, `email`, `telegram`, `whatsapp`, `topic`, `message`, `locale`, `pageUrl`, `customer`, `status` (`new` \| `in_progress` \| `done` \| `spam`), `crmId` (3d) и `chatwootId` (3e), `ipHash`.
### 7.5 `media` — Файлы
+10 -10
View File
@@ -22,16 +22,16 @@
4. Создаётся заказ `pending`: `new_key`, сумма — `firstPeriodAmount`, действует 24 часа. Если у пользователя уже есть такой же неоплаченный заказ, используется он.
5. Шаг «Оплата»: сводка заказа, согласие с условиями (обязательная галочка со ссылками на юридические страницы) и способ оплаты.
a. Баланса хватает — кнопка «Оплатить с баланса», заказ оплачивается сразу.
b. Баланса не хватает — список платёжных систем: активные, в валюте аккаунта, с назначением `order`, видимые пользователю. Создаётся платёж `pending` на сумму «стоимость минус баланс» (показываем: «С баланса спишется X, к оплате Y»), дальше — страница или виджет провайдера (этап 4).
6. На этапе 1 видимых платёжных систем нет. Заказ создаётся, пользователь видит «Заказ создан, ожидает оплаты». Оплату проводит администратор ручным платежом, либо пользователь оплачивает с баланса, который пополнил администратор. Так проверяется весь сценарий без эквайринга.
7. После оплаты: заказ `paid`, ключ создаётся в статусе `provisioning`, письма `order_paid` пользователю и `admin_provisioning_needed` на почту поддержки.
b. Баланса не хватает — список платёжных систем: активные, в валюте аккаунта, с назначением `order`, видимые пользователю. Создаётся платёж `pending` на сумму «стоимость минус баланс» (показываем: «С баланса спишется X, к оплате Y»), дальше — страница или виджет провайдера: демо-оплата (этап 1e), Stripe (4b).
6. Если видимых платёжных систем нет, заказ создаётся, пользователь видит «Заказ создан, ожидает оплаты». Оплату проводит администратор ручным платежом, либо пользователь оплачивает с баланса, который пополнил администратор. В фазе 1 «Демо» видна только с разрешённых IP ([D-027](decisions/D-027-demo-payments.md)).
7. После оплаты: заказ `paid`, ключ создаётся в статусе `provisioning`, письма `order_paid` пользователю и `admin_provisioning_needed` на почту поддержки. Дальше ключ выдаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)).
## 4. Пополнение баланса
1. Платёж с назначением `topup`. Суммы — пресеты сайта для валюты (`sites.topupPresets`) или своя сумма в пределах лимитов платёжной системы. Пресеты: dedicated — 2 500, 5 000, 10 000 ₽ и $25, $50, $100; mass — 700, 2 100, 6 990 ₽ и $7, $21, $70 (Q-02).
2. После зачисления — письмо `topup_succeeded`.
3. После любого пополнения система сама оплачивает с баланса неоплаченные заказы на продление этого пользователя, начиная со старого. Неоплаченные заказы на новые ключи сама не оплачивает.
4. Криптовалюта (этап 4): счёт в монете, курс фиксируется на 15 минут, зачисление в валюте аккаунта после подтверждения сети.
4. Криптовалюта (этап 4b): счёт в монете, курс фиксируется на 15 минут, зачисление в валюте аккаунта после подтверждения сети.
## 5. Проведение платежа: `processPayment`
@@ -58,7 +58,7 @@
1. Найти или создать заказ `renewal`: `renewalFor = expiresAt`, сумма — `renewalAmount` ключа.
2. Баланса хватает — списание, заказ `paid`, `expiresAt = renewalFor + period`, статус `active`, письмо `renewal_succeeded`.
3. Не хватает, но есть сохранённая карта с автосписанием (Stripe, этап 4) — платёж на разницу без участия пользователя. Неудача — повтор: за 24 часа до окончания, в момент окончания, через 24 и 48 часов (внутри льготного периода). После первой неудачи — письмо `renewal_failed`.
3. Не хватает, но есть сохранённая карта с автосписанием (демо-карта — этап 1g, Stripe — 4b) — платёж на разницу без участия пользователя. Неудача — повтор: за 24 часа до окончания, в момент окончания, через 24 и 48 часов (внутри льготного периода). После первой неудачи — письмо `renewal_failed`.
4. Нет ни денег, ни карты — заказ ждёт оплаты. Его оплатит пополнение (раздел 4.3) или кнопка «Продлить сейчас».
### 6.2 «Продлить сейчас»
@@ -82,13 +82,13 @@
1. `active`, срок истёк, продление не оплачено → `grace`, `graceUntil = expiresAt + graceDays`, письмо `grace_started`. Ключ работает.
2. Продление оплачено в льготный период → `active`, новый срок считается от старого `expiresAt`: бесплатных дней нет.
3. `grace`, `graceUntil` наступил → `expired`, неоплаченный заказ на продление → `expired`, письмо `key_expired`. На этапе 1 ключ попадает в список «К отключению» в админке; отключение автоматическое — этап 5.
3. `grace`, `graceUntil` наступил → `expired`, неоплаченный заказ на продление → `expired`, письмо `key_expired`. Подключения отключает адаптер выдачи: у `manual` ключ попадает в список «К отключению» в админке, у `demo` и `api` — автоматически ([D-028](decisions/D-028-provisioning-adapter.md)).
4. Правило одинаковое для ключей с автопродлением и без. Без автопродления пользователь сам решает, продлевать ли в льготный период.
5. Истёкший ключ не продлевается: покупается новый. Администратор может вернуть ключ вручную.
## 8. Выдача ключа
1. Админка, ключ в статусе `provisioning`: администратор добавляет подключения (WG/AWG по устройствам, ссылку Happ, RU-адрес), IP-адреса и нажимает «Выдать ключ».
1. Режим `manual`: в админке у ключа в статусе `provisioning` администратор добавляет подключения (WG/AWG по устройствам, ссылку Happ, RU-адрес), IP-адреса и нажимает «Выдать ключ». В режимах `demo` и `api` это делает адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)).
2. Нужно хотя бы одно активное подключение. Затем: `active`, `activatedAt = сейчас`, `expiresAt = сейчас + период` плюс дни продлений без оплаты, которые ждали выдачи (раздел 6.4), письмо `key_ready`.
3. Список «Очередь выдачи» в админке: ключи `provisioning` по времени создания; локации `on_demand` помечены сроком «24 часа».
@@ -108,8 +108,8 @@
## 10. Возвраты
1. Политика: если сервер не заработал по нашей вине — полностью в течение первых 7 дней; если пользователь передумал — остаток неиспользованного периода. Сумму считает администратор, система подсказывает остаток пропорционально дням.
2. Этап 1 — только возврат на баланс.
3. Этап 4 — возврат на исходный способ оплаты, если провайдер умеет. Запись `refund` (+) на баланс по заказу, затем `payout` (−) — деньги уходят на карту. Итог: баланс не меняется, деньги у пользователя на карте.
2. До этапа 4b — только возврат на баланс.
3. Этап 4b — возврат на исходный способ оплаты, если провайдер умеет. Запись `refund` (+) на баланс по заказу, затем `payout` (−) — деньги уходят на карту. Итог: баланс не меняется, деньги у пользователя на карте.
## 11. Реферальное вознаграждение
@@ -139,7 +139,7 @@
| Возврат | `refund_issued` | |
| Администраторам | `admin_new_order`, `admin_provisioning_needed`, `admin_new_lead` | на почту поддержки сайта |
С этапа 3 те же уведомления дублируются в основного бота, если Telegram привязан.
С этапа 2b те же уведомления дублируются в основного бота, если Telegram привязан.
## 13. Статусы
+4 -4
View File
@@ -12,7 +12,7 @@
### 2.1 Запрос кода
1. Пользователь вводит email и проходит ALTCHA.
1. Пользователь вводит email и проходит ALTCHA (с этапа 3a).
2. Сервер нормализует email (обрезает пробелы, переводит в нижний регистр) и проверяет лимиты:
a. по email — не чаще раза в 60 секунд и не больше 5 кодов в час;
b. по IP — не больше 20 запросов в час.
@@ -51,14 +51,14 @@
Шаг «Почта» на странице заказа — тот же вход по коду. После подтверждения пользователь остаётся на шаге «Оплата».
## 6. Telegram (этап 3)
## 6. Telegram (этапы 2a–2c)
### 6.1 Вход из MiniApp
1. MiniApp передаёт серверу `initData` от Telegram.
2. Сервер проверяет подпись: HMAC-SHA256 с ключом `HMAC_SHA256("WebAppData", токен основного бота)`, `auth_date` не старше суток.
3. Ищем пользователя (сайт, telegramId). Нет — создаём: `registeredVia = telegram`, язык — из `language_code` Telegram (если он среди включённых), валюта — по умолчанию домена.
4. Сессия `kind = miniapp`. Как её хранить (cookie внутри WebView Telegram или токен в памяти) — решаем на этапе 3.
4. Сессия `kind = miniapp`. Как её хранить (cookie внутри WebView Telegram или токен в памяти) — решаем на этапе 2a.
### 6.2 Привязка почты из Telegram
@@ -97,7 +97,7 @@
| `vx_ref` | хост кабинета | 60 дней | реферальный код |
| `NEXT_LOCALE` | каждый хост | 1 год | выбранный язык |
| `vx_currency` | хост сайта и кабинета | 1 год | выбранная валюта (у вошедшего — валюта аккаунта) |
| `vx_consent` | хост сайта и кабинета | 1 год | согласие на cookies (этап 1h) |
| `vx_consent` | хост сайта и кабинета | 1 год | согласие на cookies (этап 3f) |
| `payload-token` | хост админки | сессия админки | вход администратора |
Тема (светлая, тёмная, как в системе) хранится в localStorage, как в макете, и применяется скриптом до отрисовки, без мигания.
+4 -4
View File
@@ -52,10 +52,10 @@
## 7. Как переводим
1. Источник: русские тексты макетов и английские из словаря макета `design/handoff/project/i18n.js` (около 515 строк). Они ложатся в `ru.json` и `en.json` и в контент Payload.
2. Немецкий, французский, испанский — машинный перевод LLM с глоссарием на этапе 1h. Вычитки носителями нет, поэтому глоссарий и контекст обязательны.
1. Источник: русские тексты макетов и английские из словаря макета `design/handoff/project/i18n.js` (около 515 строк). Интерфейс ложится в `messages/*.json`, тексты страниц и остальной контент — в Payload ([D-029](decisions/D-029-pages-blocks.md)).
2. Немецкий, французский, испанский переводит Claude с глоссарием в каждом этапе, вместе с RU и EN ([D-033](decisions/D-033-translations.md)). Вычитки носителями нет, поэтому глоссарий и контекст обязательны. Финальная проверка — на публичном запуске (этап 3h).
3. В юридических текстах пункт: «При расхождениях между версиями действует английская».
4. Новая строка интерфейса: разработчик добавляет ключ в `en.json` и `ru.json`; de, fr, es переводятся пакетно перед выкладкой.
4. Новая строка интерфейса или контента сразу появляется на 5 языках.
## 8. Глоссарий
@@ -76,4 +76,4 @@
| реферальная программа | referral program | |
| установим за 24 часа | ready within 24 hours | статус локации dedicated |
Колонки для de, fr, es добавляются на этапе 1h.
Колонки для de, fr, es добавляются на этапе 1b.
+12 -6
View File
@@ -17,7 +17,7 @@
| `Support` / `MassSupport` | `/support` | `/support` |
| `Order` / `MassOrder` | my.veilix.app `/order` | my.veilixvpn.com `/order` |
| `App` / `MassApp` | my.veilix.app: `/login`, `/`, `/keys`, `/keys/[id]`, `/buy`, `/billing`, `/referral` | то же на my.veilixvpn.com |
| `AppTG` / `MassAppTG` | tg.veilix.app (этап 3) | tg.veilixvpn.com (этап 3) |
| `AppTG` / `MassAppTG` | tg.veilix.app (этап 2a) | tg.veilixvpn.com (этап 2a) |
Плюс страницы без макета: `/legal/terms`, `/legal/privacy`, `/legal/refund`, `/legal/cookies`, 404 и 500 — в стиле сайта.
@@ -61,7 +61,7 @@
Общие для брендов: `--warn` (62% .14 62 / 78% .13 62), `--tg` (62% .15 250 / 70% .13 250), `--veil` (белый 55% / 7%), `--shadow`, цвета карты `--land`, `--land-line`, `--ocean`.
В коде токены — `src/styles/tokens.css`, утилиты Tailwind называются так же (`bg-surface`, `text-ink-2`, `bg-sel`); стандартная палитра Tailwind отключена. У Вейликса `--sel` равен `--accent-soft`. Цвета карты Вейликса в `Main` светлее, чем в `Locations`; на этапе 1a взяты из `Locations`, окончательно решаем на этапе 1b.
В коде токены — `src/styles/tokens.css`, утилиты Tailwind называются так же (`bg-surface`, `text-ink-2`, `bg-sel`); стандартная палитра Tailwind отключена. У Вейликса `--sel` равен `--accent-soft`. Цвета карт Вейликса: глобус в hero — значения `Main` (они светлее), плоская карта — значения `Locations` (решено на этапе 1b).
## 5. Шрифты, иконки, логотип
@@ -74,12 +74,13 @@
1. В макете карта строится в браузере через d3 и topojson с загрузкой данных с CDN. В продукте SVG-карта рендерится на сервере при сборке: d3-geo, проекция Natural Earth, данные `world-atlas` (countries-110m) из npm.
2. В браузере — только интерактив: подсветка, всплывающая карточка, синхронизация с сеткой локаций.
3. На узком экране карта прокручивается горизонтально, как в макете.
4. Глобус в hero главной (`Main`, `MassMain`) — ортографическая проекция, тоже рисуется на сервере, без интерактива.
## 7. Решения по расхождениям в макетах
1. Устройств — 5, это поле тарифа. Цена продления dedicated — 2 499 ₽, цены задаются тарифами (3 уровня).
2. Оформление заказа получает тариф, локацию и валюту из ссылки. В макете там всегда Нидерланды и 4 900 ₽.
3. Поля номера карты из макета `Order` не делаем: карта вводится в виджете провайдера (этап 4). На этапе 1 платёжных систем для пользователя нет ([04-billing.md](04-billing.md), раздел 3.6).
3. Поля номера карты из макета `Order` не делаем: карта вводится в виджете провайдера (этап 4b). В фазе 1 — демо-оплата ([D-027](decisions/D-027-demo-payments.md)).
4. Mass: в кабинете «Список ключей», без «текущей/запасной локации» и без экрана смены страны. Внутри ключа — ссылка Xray и WG-конфиги по странам.
5. Статус локации показываем везде одинаково: в списках, карточках и на карте.
6. Кнопка «Получить VPN» на главной ведёт к блоку цен на этой же странице, на остальных страницах — на `/pricing`.
@@ -87,13 +88,18 @@
8. Контакты поддержки берутся из настроек сайта, Telegram — ссылка на бота поддержки.
9. Плашки способов оплаты в подвале — по активным платёжным системам сайта.
10. Добавляем то, чего нет в макете: переключатель валюты, `<title>` и мета-описания, H1 на каждой странице, поддержку `prefers-reduced-motion` для анимаций.
11. Показывать ли на сайте количество свободных серверов (в MiniApp макет его показывает) — решаем на этапе 1b. По умолчанию — только статус.
11. Количество свободных серверов показываем рядом со статусом, если поле заполнено ([D-032](decisions/D-032-free-servers.md)).
12. Переключатели при 5 языках и с валютой (в макете только RU/EN, валюты нет). В шапке — выпадающие списки языка и валюты. В подвале, мобильном меню и кабинете — сегменты с кодами языков (EN RU DE FR ES) и символами валют (₽ $). В оболочке кабинета валюты нет: она появится в настройках (1f).
13. В подвале четыре документа: добавлена «Политика cookies». Плашек способов оплаты нет, пока нет видимых пользователю платёжных систем (пункт 9).
14. Кабинет mass: подписи навигации те же, что у dedicated («Список ключей», «Купить ключ», «Ключи»). Подписи макета MassApp («Подключения», «Выбрать страну», «Подписка») не используем (пункт 4).
15. Ширина надписи логотипа — по содержимому: в макете она подогнана под русское название.
16. 404. При `notFound()` Next 16 отдаёт пустую оболочку (`<html id="__next_error__">`), а страница 404 в оформлении бренда отрисовывается в браузере; статус ответа — 404. Серверную отрисовку 404 и 500 решаем на этапе 1b вместе с их оформлением: вариант — `global-not-found.js`.
17. Реферальная программа (1g): бонус — дни срока ключа, а не деньги ([D-025](decisions/D-025-referral-days.md)). Текст под ссылкой «Месяц начисляется вам и другу… и применяется к ближайшему списанию» заменяем на условия в днях. В истории платежей строка «Реферальный бонус» показывает «+30 дней» вместо «+2 499 ₽». Счётчик «Месяцев начислено» и статусы приглашённых остаются.
17. Реферальная программа (1h): бонус — дни срока ключа, а не деньги ([D-025](decisions/D-025-referral-days.md)). Текст под ссылкой «Месяц начисляется вам и другу… и применяется к ближайшему списанию» заменяем на условия в днях. В истории платежей строка «Реферальный бонус» показывает «+30 дней» вместо «+2 499 ₽». Счётчик «Месяцев начислено» и статусы приглашённых остаются.
18. Тексты описывают работающий продукт, а не ограничения текущего этапа: «сразу после оплаты», оплата картой, автопродление, смена страны — как в макетах ([D-026](decisions/D-026-stage-order.md)).
19. Тексты страниц — в Payload, страницы собираются из блоков ([D-029](decisions/D-029-pages-blocks.md)).
20. Вейликс — «индивидуальный IP»: выделенный адрес на общем сервере. Формулировки «персональный сервер», «без соседей по серверу», «персональные VPN-серверы» не используем.
21. ВейликсВПН: RU-адрес входит в ключ, но страной не считается ([D-031](decisions/D-031-mass-ru-address.md)); число стран — из данных, только «Включено»; протоколы — Xray и WireGuard.
22. Поддержка: сроки ответа не обещаем, часы — «с 10 до 20 по московскому времени в рабочие дни». Telegram — `@veilix_support` у обоих брендов, пока нет ботов поддержки (этап 3e).
## 8. Состояния, которых нет в макетах
@@ -101,7 +107,7 @@
1. Вход: ошибка кода, истёкший код, таймер повторной отправки, загрузка.
2. Ключ: готовится (до 24 часов), льготный период, истёк, заблокирован; пустой список ключей; ключ без подключений.
3. Заказ: «ожидает оплаты» (этап 1), не хватает баланса, оплата не прошла; 3-D Secure и счёт в криптовалюте — этап 4.
3. Заказ: «ожидает оплаты», не хватает баланса, оплата не прошла (этап 1e); 3-D Secure и счёт в криптовалюте — этап 4b.
4. Счёт: своя сумма пополнения, подтверждение отвязки карты, результат пополнения.
5. Общие: уведомления (тосты), скелетоны загрузки, страницы 404 и 500, ошибки валидации форм.
+18 -18
View File
@@ -1,12 +1,12 @@
# 08. Интеграции
## 1. Почта (этап 1c)
## 1. Почта (этапы 1c и 3c)
1. Шаблоны — в Payload (`email-templates`): тема и текст на каждом языке, для каждого сайта свои. Шапка (логотип) и подвал (контакты, юридические ссылки) — в коде, у каждого бренда свои.
2. Отправка — через email-адаптер Payload на Nodemailer. Транспорт переключается в админке (глобал «Почта»):
a. `smtp` — внешний SMTP-провайдер (данные в настройках, пароль зашифрован);
b. `sendmail` — локальный Postfix (`/usr/sbin/sendmail`);
c. `log_only` — не отправлять, только записать в журнал (для разработки).
c. `log_only` — не отправлять, только записать в журнал. До этапа 3c работает только он.
3. Письма уходят через фоновую задачу `send-email` с повторами при ошибке. Каждое письмо пишется в журнал писем; коды входа — по флагу ([05-auth.md](05-auth.md), раздел 4).
4. Кнопка «Отправить тестовое письмо» проверяет текущий транспорт.
5. Чтобы письма через Postfix не попадали в спам (root, [09-infrastructure.md](09-infrastructure.md), раздел 6):
@@ -15,7 +15,7 @@
c. проверить, что исходящий порт 25 открыт и IP нет в чёрных списках.
6. Новые IP почтовые сервисы поначалу принимают настороженно, поэтому SMTP-провайдер держим запасным вариантом.
## 2. ALTCHA (этап 1c)
## 2. ALTCHA (этап 3a)
1. Капча на proof-of-work без сторонних сервисов: браузер решает небольшую вычислительную задачу, сервер проверяет подпись.
2. Эндпоинт выдачи задачи — `/svc/altcha/challenge`, ключ подписи — в `.env`.
@@ -29,7 +29,7 @@
3. Страна используется только для выбора языка по умолчанию, не для валюты.
4. Если понадобится страна произвольного IP (антифрод), приложение читает тот же `.mmdb` библиотекой `maxmind`.
## 4. Chatwoot (этап 2)
## 4. Chatwoot (этап 3e)
1. Один экземпляр на отдельном VPS обслуживает оба бренда. У каждого бренда свои входящие каналы:
a. виджет на сайте и в кабинете;
@@ -38,12 +38,12 @@
2. Для вошедших пользователей виджет получает идентификацию с HMAC-подписью: оператор видит, кто пишет, а подделать её нельзя. Передаём атрибуты: сайт, id пользователя, email, число ключей.
3. Почему бот поддержки отдельный: Telegram отдаёт обновления одного бота только одному получателю. Основной бот принадлежит нашему приложению, бот поддержки — Chatwoot.
## 5. Twenty CRM (этап 2)
## 5. Twenty CRM (этап 3d)
1. Заявки из `leads` уходят в Twenty через API: человек и сделка с полями заявки, брендом и страницей. Отправка — фоновой задачей с повторами; id в Twenty сохраняется в `leads.crmId`.
2. До этапа 2 заявки видны в админке Payload и приходят письмом `admin_new_lead` на почту поддержки.
1. Заявки с форм уходят в Twenty через API: человек и сделка с полями заявки, брендом и страницей. Нужен ли буфер в базе (`leads` с отправкой фоновой задачей и повторами) — решаем на этапе 3d.
2. До этапа 3d формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)). С 3d — письмо `admin_new_lead` на почту поддержки.
## 6. Telegram (этап 3)
## 6. Telegram (этапы 2a–2c)
1. Боты для каждого бренда:
a. основной: команды, кнопка MiniApp, уведомления. Код — grammY в нашем приложении, вебхук `/svc/telegram/<сайт>/webhook` с секретным токеном;
@@ -52,7 +52,7 @@
2. MiniApp — на tg.*, вход по `initData` ([05-auth.md](05-auth.md), раздел 6). Dev-MiniApp доступна только Telegram-аккаунтам из списка разрешённых.
3. Черновик команд основного бота: `/start` (в том числе с реферальным кодом или токеном привязки), `/keys`, `/buy`, `/balance`, `/topup`, `/referral`, `/language`, `/support` (ссылка на бота поддержки), `/help`. Тексты и кнопки — в Payload, локализованные.
4. Уведомления из [04-billing.md](04-billing.md) (раздел 12) дублируются в бот, если Telegram привязан.
5. Оплата в Telegram (Q-11): по правилам Telegram цифровые товары в ботах и MiniApp оплачиваются Telegram Stars, за нарушения ботов блокируют. Варианты: Stars, внешняя страница оплаты, покупки в Telegram только с баланса. Решаем на старте этапа.
5. Оплата в Telegram (Q-11): по правилам Telegram цифровые товары в ботах и MiniApp оплачиваются Telegram Stars, за нарушения ботов блокируют. Варианты: Stars, внешняя страница оплаты, покупки в Telegram только с баланса. Решаем на этапе 4a; до него в MiniApp — демо-оплата и баланс.
## 7. Платёжные системы
@@ -61,15 +61,15 @@
b. `handleWebhook` — проверить подпись и вернуть новый статус платежа;
c. по возможностям: `chargeSavedMethod` (автосписание), `refund`, `detachMethod`.
2. Запись в коллекции `payment-systems` включает адаптер в валютах и для назначений ([03-data-model.md](03-data-model.md), 3.4). На каком сайте система доступна, следует из валют его доменов. Ключи доступа — в `.env`.
3. Этап 1: только `manual` — для администраторов.
4. Этап 4:
a. Stripe — USD: карты, сохранение карты, автосписания без участия пользователя на переменную сумму («цена минус баланс»), без Stripe Subscriptions. Сначала тестовый режим;
b. RUB — процессинги, принимающие карты РФ (вероятно, KZ и TR), только пополнения. Провайдеров выбираем на этапе (Q-12);
c. криптовалюта — пополнения в RUB и USD, провайдер выбирается на этапе;
d. ЮKassa — опционально, только пополнения, если примет категорию.
3. Фаза 1: `manual` — для администраторов, `demo` — для проверок ([D-027](decisions/D-027-demo-payments.md)).
4. Реальные провайдеры:
a. ЮKassa — пополнения в RUB (этап 3b);
b. Stripe — USD: карты, сохранение карты, автосписания без участия пользователя на переменную сумму («цена минус баланс»), без Stripe Subscriptions; сначала тестовый режим (этап 4b);
c. криптовалюта — пополнения в RUB и USD, провайдер выбирается на этапе 4b;
d. звёзды Telegram — этап 4a.
5. Вебхуки — `/svc/payments/<адаптер>/webhook`; обработка идемпотентная ([04-billing.md](04-billing.md), раздел 14).
## 8. Umami и баннер cookies (этап 1h)
## 8. Umami и баннер cookies (этап 3f)
1. Umami — своя аналитика без cookies, данные не уходят третьим лицам ([D-018](decisions/D-018-analytics.md)).
a. Ставится на этот сервер из исходников, без Docker: Node.js и PostgreSQL здесь уже есть. Umami 3.x поддерживает только PostgreSQL.
@@ -78,6 +78,6 @@
2. Скрипт и отправка событий проксируются через домены брендов под нейтральными путями (переменные Umami `TRACKER_SCRIPT_NAME` и `COLLECT_API_ENDPOINT`), чтобы их не резали блокировщики рекламы. Реальный IP посетителя Umami берёт из заголовка nginx (`CLIENT_IP_HEADER`). Телеметрия Umami выключена (`DISABLE_TELEMETRY=1`).
3. Баннер cookies: обязательные (сессия, язык, валюта) и функциональные (чат Chatwoot). Решение пользователя хранится в cookie `vx_consent`, необязательные скрипты загружаются только после согласия. Библиотека — vanilla-cookieconsent или своя лёгкая реализация.
## 9. Автоматизация ключей (этап 5)
## 9. Выдача ключей через API (этап 3g)
Подбор свободного сервера по тарифу (страны, теги) и автоматическая выдача подключений. Обсуждаем при старте этапа.
Адаптер `api` на месте демо-эмулятора ([D-028](decisions/D-028-provisioning-adapter.md)): подбор свободного сервера по тарифу (страны, теги) и автоматическая выдача подключений. Обсуждаем при старте этапа.
+15 -14
View File
@@ -56,7 +56,7 @@ vx — личный пользователь администратора, к п
b. `dev.tg.*` — отдельный `server` без ограничения по IP, с `X-Robots-Tag: noindex`.
c. На порту 80 — `location / { return 301 https://$host$request_uri; }`. Именно внутри `location`, а не на уровне `server`: так certbot при продлении может вставить свой `location` для проверки домена.
7. Лимиты запросов (`limit_req`) на эндпоинты входа и формы.
8. Для tg.* (этап 3) разрешить показ во фрейме Telegram Web (`frame-ancestors` для доменов telegram.org).
8. Для tg.* (этап 2a) разрешить показ во фрейме Telegram Web (`frame-ancestors` для доменов telegram.org).
9. Пути трекера Umami на доменах брендов проксируются на 127.0.0.1:3300 ([08-integrations.md](08-integrations.md), раздел 8).
10. Конфигурацию готовит Claude текстом на согласование, применяет root.
@@ -77,7 +77,7 @@ vx — личный пользователь администратора, к п
b. DKIM: TXT `mail._domainkey.<домен>` с открытым ключом;
c. DMARC: `_dmarc.<домен>` — сначала `v=DMARC1; p=none; rua=mailto:…`, после проверки — `p=quarantine`.
4. Проверить, что хостер не закрывает исходящий порт 25 и что 169.58.76.183 нет в чёрных списках.
5. Почта поддержки (Q-16): ящики `help@veilix.app` и `help@veilixvpn.com` — на внешнем почтовом хостинге, MX-записи доменов указывают на него (пользователь, R-18). На этапе 2 Chatwoot забирает письма по IMAP и отвечает через SMTP хостинга. Доменов брендов в `mydestination` Postfix нет и быть не должно: тогда письма администраторам на `help@…` уходят на хостинг, а не остаются на этом сервере.
5. Почта поддержки (Q-16): ящики `help@veilix.app` и `help@veilixvpn.com` — на внешнем почтовом хостинге, MX-записи доменов указывают на него (пользователь, R-18). На этапе 3e Chatwoot забирает письма по IMAP и отвечает через SMTP хостинга. Доменов брендов в `mydestination` Postfix нет и быть не должно: тогда письма администраторам на `help@…` уходят на хостинг, а не остаются на этом сервере.
## 7. Бэкапы
@@ -87,7 +87,7 @@ vx — личный пользователь администратора, к п
## 8. Задачи для root по этапам
| № | Этап | Задача | Статус на 21.10.2026 |
| № | Этап | Задача | Статус на 22.10.2026 |
|---|---|---|---|
| R-00 | 0 | Переезд разработки: перенести `/home/vx/veilix_dev` в `/home/vx_dev/veilix_dev` (владелец vx_dev); SSH-ключ vx_dev для VSCode; Claude Code под vx_dev | сделано |
| R-01 | 0 | Репозиторий в Gitea; SSH-ключ vx_dev с правом push; для vx_prod — ключ только на чтение (deploy key) | vx_dev — сделано: `origin` — `ssh://git@gte.apr.sh:26789/andreypr207/veilix.app.git`, ключ `~/.ssh/veilix_gitea_ed25519` добавлен в Gitea как deploy key с правом записи, `main` отправлен. Ключ vx_prod — на этапе 1h |
@@ -96,15 +96,16 @@ vx — личный пользователь администратора, к п
| R-04 | 1a | Пользователи vx_dev, vx_prod, umami; `loginctl enable-linger` для них | сделано |
| R-05 | 1a | nginx и сертификаты для всех хостов (раздел 4) | сделано: опечатка исправлена, `X-Robots-Tag` на всех dev-хостах |
| R-06 | 1a | MaxMind: `geoipupdate` (ключ в `/etc/GeoIP.conf`, база в `/var/lib/GeoIP`, таймер `geoipupdate.timer`); отключить старый модуль GeoIP v1; блок `geoip2` (раздел 4, пункт 4) | сделано |
| R-07 | 1c | Postfix, OpenDKIM, DNS-записи SPF, DKIM, DMARC — или данные SMTP-провайдера | |
| R-08 | 1h | PostgreSQL для prod — если не сделано вместе с R-02 | сделано в R-02 |
| R-09 | 1h | nginx и сертификаты для prod-хостов | сделано вместе с R-05 |
| R-10 | 1h | Umami: nginx и сертификат для `umi.veilix.cc` (DNS уже есть; база — в R-02) | |
| R-11 | 1h | Бэкапы prod-базы и media на внешний сервер (Q-14) | |
| R-12 | 2 | VPS с Chatwoot и Twenty, ключи API; 2 бота поддержки в BotFather | |
| R-13 | 3 | Боты в BotFather: 2 основных и тестовые; домен для Telegram Login; адреса MiniApp | |
| R-14 | 4 | Аккаунты платёжных систем (сначала тестовые), адреса вебхуков | |
| R-15 | 1h | По желанию (Q-18): sudo-правило, разрешающее vx_dev запускать от имени vx_prod только команду выкладки | |
| R-16 | 1h | По желанию: правило nftables — к 127.0.0.1:3000 подключаются только `www-data` (nginx) и vx_prod ([10-security.md](10-security.md), раздел 7) | |
| R-07 | 3c | Postfix, OpenDKIM, DNS-записи SPF, DKIM, DMARC — или данные SMTP-провайдера | |
| R-08 | 3h | PostgreSQL для prod — если не сделано вместе с R-02 | сделано в R-02 |
| R-09 | 3h | nginx и сертификаты для prod-хостов | сделано вместе с R-05 |
| R-10 | 3f | Umami: nginx и сертификат для `umi.veilix.cc` (DNS уже есть; база — в R-02) | |
| R-11 | 3h | Бэкапы prod-базы и media на внешний сервер (Q-14) | |
| R-12 | 3d, 3e | VPS с Chatwoot и Twenty, ключи API; 2 бота поддержки в BotFather | |
| R-13 | 2a | Боты в BotFather: 2 основных и тестовые; домен для Telegram Login; адреса MiniApp | |
| R-14 | 3b, 4b | Аккаунты платёжных систем (сначала тестовые), адреса вебхуков | |
| R-15 | 3h | По желанию (Q-18): sudo-правило, разрешающее vx_dev запускать от имени vx_prod только команду выкладки | |
| R-16 | 3h | По желанию: правило nftables — к 127.0.0.1:3000 подключаются только `www-data` (nginx) и vx_prod ([10-security.md](10-security.md), раздел 7) | |
| R-17 | 1a | nginx dev: отдельный `location /_next/hmr` с `proxy_read_timeout 1h` во всех трёх server-блоках dev на 443: `dev.plc.veilix.cc`, сайты и кабинеты, `dev.tg.*`. В Next 16.4 WebSocket горячей перезагрузки — `/_next/hmr`, и сервер может молчать дольше 30 секунд, а `nginx.conf` закрывает соединение после 30 секунд тишины (`proxy_read_timeout 30`) | сделано: на всех семи dev-хостах соединение держится 70 секунд без сообщений |
| R-18 | 1h | Почта поддержки (Q-16): ящики `help@veilix.app` и `help@veilixvpn.com` на почтовом хостинге, MX-записи доменов; хостинг — в SPF (раздел 6). До этого письма администраторам и заявки видны только в админке и журнале писем | |
| R-18 | 3c | Почта поддержки (Q-16): ящики `help@veilix.app` и `help@veilixvpn.com` на почтовом хостинге, MX-записи доменов; хостинг — в SPF (раздел 6). До этого письма администраторам и заявки видны только в админке и журнале писем | |
| R-19 | 1b | Библиотеки для headless Chromium — сверка страниц с макетами по скриншотам и Lighthouse: `libatk1.0-0t64 libatk-bridge2.0-0t64 libatspi2.0-0t64 libasound2t64 libxcomposite1 libxdamage1 libxfixes3 libxrandr2`. Сам браузер (Chrome for Testing) лежит в папке vx_dev, без root | сделано 22.10.2026: скриншоты снимаются |
+3 -2
View File
@@ -23,7 +23,7 @@
## 4. Пользователи
1. Коды входа хранятся только как HMAC, проверяются за постоянное время, 5 попыток, 10 минут жизни.
2. ALTCHA и лимиты по IP и email на запрос кода.
2. Лимиты по IP и email на запрос кода; ALTCHA — с этапа 3a.
3. Ответ на запрос кода не выдаёт, есть ли аккаунт.
4. Токены сессий в базе — только SHA-256. Cookie — `HttpOnly`, `Secure`, `SameSite=Lax`, привязаны к хосту.
5. CSRF: `SameSite=Lax`, проверка Origin в server actions и своих POST-эндпоинтах.
@@ -42,7 +42,8 @@
2. IP пользователей в базе не храним в открытом виде — только HMAC для сравнения (самоприглашения, лимиты). Логи nginx — ротация 14 дней.
3. В списке приглашённых почта замаскирована: `m···@gmail.com`.
4. Аналитика — Umami без cookies, данные не уходят третьим лицам.
5. Что и зачем храним — в политике конфиденциальности (этап 1b).
5. VPN-серверы не ведут журналов трафика и подключений: так сказано в политике конфиденциальности, и выдача через API (этап 3g) это соблюдает.
6. Что и зачем храним — в политике конфиденциальности (этап 1b).
## 7. Окружения
+3 -3
View File
@@ -1,6 +1,6 @@
# D-016. Платёжные системы по валютам; автосписания — Stripe
Статус: принято, 20.10.2026. Провайдеры для RUB и криптовалюты выбираются на этапе 4 (Q-12).
Статус: принято, 20.10.2026. Провайдеры (Q-12): RUB — ЮKassa, только пополнения (этап 3b); криптовалюта — этап 4b.
## Решение
@@ -8,8 +8,8 @@
2. USD — Stripe (карты, сохранение карты, автосписания на переменную сумму, без Stripe Subscriptions) и криптовалюта.
3. RUB — процессинги, принимающие карты РФ (вероятно, KZ и TR), только пополнения, без автосписаний. ЮKassa — опционально, только пополнения.
4. Пользователи с картами РФ продлевают ключи с баланса; напоминание — за 3 дня.
5. Оплата внутри Telegram (Stars) — решаем на этапе 3.
5. Оплата внутри Telegram (Stars) — решаем на этапе 4a.
## Последствия
На этапе 1 работает только `manual`. Модель данных готова к любому набору провайдеров.
В фазе 1 работают `manual` и `demo` ([D-027](D-027-demo-payments.md)). Модель данных готова к любому набору провайдеров.
+1 -1
View File
@@ -1,6 +1,6 @@
# D-017. Статические маркетинговые страницы с пересборкой по событию
Статус: принято, 20.10.2026.
Статус: принято, 20.10.2026. Пункт 2 уточнён в [D-030](D-030-revalidate-path.md).
## Решение
+1 -1
View File
@@ -10,4 +10,4 @@
## Последствия
До этапа 2 заявки видны в админке Payload и приходят письмом на почту поддержки.
Подключаются на этапах 3d (Twenty) и 3e (Chatwoot); до них формы — только интерфейс ([D-026](D-026-stage-order.md)).
+3 -3
View File
@@ -1,6 +1,6 @@
# D-020. Модели ключей dedicated и mass
Статус: принято, 20.10.2026.
Статус: принято, 20.10.2026. Уточнено в [D-028](D-028-provisioning-adapter.md) и [D-031](D-031-mass-ru-address.md).
## Решение
@@ -9,8 +9,8 @@
3. Тип ключа определяется полем `type` тарифа.
4. Подключения гибкие: у ключа любой набор подключений разных видов, поэтому ручная выдача на этапе 1 покрывает любой вариант.
5. Оплаченный период начинается с момента выдачи ключа.
6. На этапе 1 WG-конфиги mass — те, что добавил администратор, по странам. Нужна другая страна — через поддержку. Автоматически — на этапе 5.
6. На этапе 1 WG-конфиги mass — те, что добавил администратор, по странам. Нужна другая страна — через поддержку. Автоматически — на этапе 3g.
## Последствия
Автоматическая выдача (этап 5) создаёт те же подключения, что сейчас добавляет администратор.
Автоматическая выдача (этап 3g) создаёт те же подключения, что сейчас добавляет администратор.
+26
View File
@@ -0,0 +1,26 @@
# D-026. Порядок этапов: сначала концепт на dev с демо-режимами
Статус: принято, 22.10.2026. Заменяет порядок этапов 1b–1h и 2–5 из этапа 0.
## Контекст
В прежнем плане внешние сервисы (почта, CRM, платёжные системы, Telegram) появлялись вперемешку с основным функционалом, а продукт целиком можно было проверить только перед запуском. Этапы были крупными.
## Решение
1. Фаза 1 — концепт без внешних сервисов, на dev: сайт, вход, ключи, оплата, выдача, продления, рефералы. Оплата и выдача ключей работают в демо-режимах ([D-027](D-027-demo-payments.md), [D-028](D-028-provisioning-adapter.md)), письма пишутся в журнал.
2. Фаза 2 — Telegram: MiniApp, основной бот, связь аккаунтов.
3. Фаза 3 — реальные сервисы по очереди: ALTCHA, ЮKassa, отправка почты, Twenty, Chatwoot, Umami, выдача ключей через API. Последний этап — публичный запуск в prod.
4. Фаза 4 — звёзды Telegram, западные эквайринги, криптовалюта.
5. Этапы мелкие: у каждого — результат, который пользователь проверяет сам. Каждый этап делается сразу на 5 языках ([D-033](D-033-translations.md)).
6. Тексты описывают работающий продукт, а не ограничения текущего этапа: концепт проверяется закрыто, а к публичному запуску всё обещанное работает.
## Рассмотренные варианты
Прежний порядок: сайт, вход, биллинг, ключи, кабинет, рефералы, запуск, затем поддержка, Telegram, платёжные системы и автоматизация.
## Последствия
1. Prod появляется только на этапе 3h, до этого всё работает на dev.
2. ALTCHA и лимиты nginx — на этапе 3a. Формы до этапов 3d и 3e — только интерфейс, без отправки.
3. Кабинет делается по частям в этапах, которым нужны его страницы: вход (1c), ключи (1d), покупка и счёт (1e), продления (1g), рефералы (1h).
+20
View File
@@ -0,0 +1,20 @@
# D-027. Платёжная система «Демо»
Статус: принято, 22.10.2026.
## Контекст
Путь покупки и продления нужно проверить целиком до подключения эквайрингов. Ручной платёж из админки этого не даёт: пользователь не проходит оплату сам.
## Решение
1. Адаптер `demo` в `core/payments/` с тем же интерфейсом, что у настоящих провайдеров, и возможностями «сохранение карты» и «автосписание».
2. Оплата заказа и пополнение ведут на нашу страницу демо-оплаты с кнопками «Оплатить» и «Отклонить». Результат проводится через `processPayment`, как у настоящей системы.
3. Демо-привязка карты сохраняет способ оплаты «Демо-карта ···· 4242». Автопродление списывает с неё; неуспешное списание включается в админке — так проверяются повторы и льготный период.
4. Система видна только запросам с IP из списка в её настройках; пустой список — не видна никому. К пользователю не привязана: до регистрации пользователя ещё нет.
5. Работает в dev и в prod. `manual` остаётся для администраторов.
## Последствия
1. Покупка, пополнение, привязка карты и продления проверяются без эквайринга.
2. В prod демо-оплата доступна только с разрешённых IP: ошибка в списке IP дала бы ключи без оплаты, поэтому список проверяется при запуске (этап 3h).
@@ -0,0 +1,23 @@
# D-028. Выдача ключей через адаптер: ручная, демо, API
Статус: принято, 22.10.2026. Уточняет [D-020](D-020-key-models.md).
## Контекст
Настоящий API выдачи появится позже (этап 3g), а путь «оплатил — получил ключ» нужно проверить уже в концепте.
## Решение
1. Выдача ключа и подключений идёт через адаптер в `core/provisioning/` с единым интерфейсом: выдать ключ, создать WG-конфиг (для устройства, у mass — для страны), отключить подключения ключа.
2. `manual` — подключения добавляет администратор в админке, как в [D-020](D-020-key-models.md).
3. `demo` — эмулятор:
a. при оплате ключ выдаётся сам: ссылка Happ и подключение к RU-адресу;
b. WG-конфиг создаётся по запросу из кабинета;
c. данные правдоподобные, но фиктивные: адреса из тестовых диапазонов;
d. локация «Установим за 24 часа» выдаётся с задержкой, чтобы было видно состояние «готовится».
4. `api` — настоящий API выдачи (этап 3g) встаёт на место `demo` без переделки кабинета.
5. Режим выдачи — настройка сайта.
## Последствия
Администратор в любом режиме может создать ключ и подключения руками.
+24
View File
@@ -0,0 +1,24 @@
# D-029. Контент страниц сайта — в Payload, страницы из блоков
Статус: принято, 22.10.2026. Уточняет [D-006](D-006-localization.md): тексты страниц — контент, а не интерфейс.
## Контекст
По [06-i18n.md](../06-i18n.md), раздел 7.1, тексты макетов ложились бы в сообщения next-intl, и заголовок главной правился бы только выкладкой. Весь контент должен храниться в CMS.
## Решение
1. Коллекция `pages` (сайт): адрес, заголовок, SEO, блоки; черновики и версии Payload. Порядок и состав секций меняются в админке.
2. Блоки повторяют секции макетов и общие для обоих брендов. Блок, который показывает данные, рисуется по бренду: у dedicated — выбор локации, у mass — планы.
3. Тарифы, локации и FAQ остаются отдельными коллекциями. Числа в текстах блоков — подстановки из данных (число стран, устройств, цены), поэтому тексты не расходятся с данными.
4. В next-intl остаётся только интерфейс: навигация, кнопки, подписи полей и статусов, сообщения форм, страница 404.
5. Так устроен официальный шаблон Payload (website template).
## Рассмотренные варианты
1. Тексты страниц в next-intl — правка только выкладкой.
2. Фиксированные поля под каждую страницу — нельзя менять состав и порядок секций.
## Последствия
Правка текста страницы — в админке, страница пересобирается по событию ([D-030](D-030-revalidate-path.md)). Переводы текстов страниц хранятся в Payload.
+22
View File
@@ -0,0 +1,22 @@
# D-030. Пересборка маркетинговых страниц через `revalidatePath`
Статус: принято, 22.10.2026. Уточняет [D-017](D-017-static-pages.md), пункт 2: пересборка не по тегам.
## Контекст
Страницы читают Payload через Local API, а не через `fetch`, поэтому теги кэша им дала бы только `unstable_cache`. В Next 16 она заменена новой моделью Cache Components (`use cache`), которая меняет рендеринг всего приложения: кабинета, next-intl, оболочек из этапа 1a.
## Решение
1. Хуки Payload после изменения контента сайта (страницы, FAQ, тарифы, локации, страны, сайты, домены, валюты) вызывают `revalidatePath` для layout маркетинговых страниц. Все маркетинговые страницы помечаются устаревшими и пересобираются при следующем заходе.
2. Запасной вариант — обновление раз в 5 минут — остаётся.
3. Cache Components рассматриваем вместе с переходом на Payload 4 ([D-002](D-002-payload-version.md)).
## Рассмотренные варианты
1. Теги через `unstable_cache` — заменённый API.
2. Cache Components сейчас — переделка всего приложения ради точечной пересборки.
## Последствия
Правка в одном бренде пересобирает страницы обоих брендов: около 160 страниц (бренды × языки × валюты × страницы), лениво, при заходе. Нагрузка незаметна.
+13
View File
@@ -0,0 +1,13 @@
# D-031. RU-адрес в ключах mass
Статус: принято, 22.10.2026. Уточняет [D-020](D-020-key-models.md), пункт 2.
## Решение
1. В ключ mass, как и в ключ dedicated, входит RU-адрес: прямое соединение и мост в обе стороны.
2. RU-адрес — не локация и не страна тарифа: в число стран он не входит. На сайте mass — «30 стран и российский адрес».
3. Подключения к RU-адресу (`connections.isRu`) есть у обоих брендов; адаптер выдачи ([D-028](D-028-provisioning-adapter.md)) создаёт их для каждого ключа.
## Последствия
Тексты макетов mass про российский адрес остаются; «включая российскую локацию» заменяется на «и российский адрес».
+13
View File
@@ -0,0 +1,13 @@
# D-032. Счётчик свободных серверов на сайте
Статус: принято, 22.10.2026.
## Решение
1. Поле локации «Свободных серверов» показывается на сайте рядом со статусом, если оно заполнено: «Серверы в наличии · 12». Пусто — только статус.
2. До выдачи через API (этап 3g) число вводится вручную. Правка в админке пересобирает страницы за секунды ([D-030](D-030-revalidate-path.md)), поэтому запрос из браузера не нужен.
3. Когда числа начнут меняться автоматически и часто, добавим обновление из браузера: статичная страница плюс запрос свежих значений.
## Рассмотренные варианты
Показывать только статус — макеты сайта счётчика не показывают, а ручное число может устареть.
+12
View File
@@ -0,0 +1,12 @@
# D-033. Переводы на 5 языков в каждом этапе
Статус: принято, 22.10.2026. Заменяет пакетный перевод перед запуском ([06-i18n.md](../06-i18n.md), раздел 7).
## Решение
1. Каждый этап делает интерфейс и контент сразу на 5 языках: RU и EN — из макетов и словаря `i18n.js`, de, fr, es — перевод Claude с глоссарием ([06-i18n.md](../06-i18n.md), раздел 8).
2. Финальная проверка переводов и непереведённых ключей — на публичном запуске (этап 3h).
## Последствия
Глоссарий получает колонки de, fr, es на этапе 1b. Английский запасной вариант остаётся на случай, когда перевода нет.
+11 -3
View File
@@ -9,7 +9,7 @@
| [D-003](D-003-hosting.md) | Без Docker: всё на хосте, процессы под systemd | принято |
| [D-004](D-004-environments.md) | Dev и prod на одном сервере под разными пользователями | принято |
| [D-005](D-005-multitenancy.md) | Сайты — тенанты, домены в базе, маршрутизация по Host | принято, уточнено в D-022 |
| [D-006](D-006-localization.md) | Переводы: поля Payload и next-intl; 5 языков | принято, уточнено в D-023 |
| [D-006](D-006-localization.md) | Переводы: поля Payload и next-intl; 5 языков | принято, уточнено в D-023 и D-029 |
| [D-007](D-007-language-detection.md) | Определение языка; MaxMind через nginx | принято, уточнено в D-024 |
| [D-008](D-008-uuid.md) | UUID и случайные публичные коды | принято |
| [D-009](D-009-billing-model.md) | Заказы, платежи, движения по счёту; всё через баланс | принято |
@@ -20,12 +20,20 @@
| [D-014](D-014-email.md) | Почта: шаблоны в Payload, переключаемый транспорт, без listmonk | принято |
| [D-015](D-015-telegram-bots.md) | Боты на grammY без n8n; два бота на бренд | принято |
| [D-016](D-016-payments.md) | Платёжные системы по валютам; автосписания — Stripe | принято |
| [D-017](D-017-static-pages.md) | Статические маркетинговые страницы с пересборкой по событию | принято |
| [D-017](D-017-static-pages.md) | Статические маркетинговые страницы с пересборкой по событию | принято, уточнено в D-030 |
| [D-018](D-018-analytics.md) | Umami на этом сервере и баннер cookies | принято |
| [D-019](D-019-external-services.md) | Chatwoot и Twenty CRM на отдельном VPS | принято |
| [D-020](D-020-key-models.md) | Модели ключей dedicated и mass | принято |
| [D-020](D-020-key-models.md) | Модели ключей dedicated и mass | принято, уточнено в D-028 и D-031 |
| [D-021](D-021-admin-host.md) | Админка на plc.veilix.cc с доступом по IP | принято |
| [D-022](D-022-proxy-routing.md) | Proxy: внутренние маршруты по хосту, домены из внутреннего эндпоинта | принято |
| [D-023](D-023-site-locales.md) | Языки сайта — поле `sites.locales`, домены показывают их часть | принято |
| [D-024](D-024-locale-redirect.md) | Перенаправление на выбранный язык | принято |
| [D-025](D-025-referral-days.md) | Реферальный бонус — дни срока ключа, а не деньги | принято |
| [D-026](D-026-stage-order.md) | Порядок этапов: сначала концепт на dev с демо-режимами | принято |
| [D-027](D-027-demo-payments.md) | Платёжная система «Демо» | принято |
| [D-028](D-028-provisioning-adapter.md) | Выдача ключей через адаптер: ручная, демо, API | принято |
| [D-029](D-029-pages-blocks.md) | Контент страниц сайта — в Payload, страницы из блоков | принято |
| [D-030](D-030-revalidate-path.md) | Пересборка маркетинговых страниц через `revalidatePath` | принято |
| [D-031](D-031-mass-ru-address.md) | RU-адрес в ключах mass | принято |
| [D-032](D-032-free-servers.md) | Счётчик свободных серверов на сайте | принято |
| [D-033](D-033-translations.md) | Переводы на 5 языков в каждом этапе | принято |
+31 -17
View File
@@ -1,34 +1,48 @@
# Этап 1b. Маркетинговые страницы
# Этап 1b. Сайт
Статус: не начат.
Статус: в работе.
## 1. Цель
Сайты обоих брендов по макетам, с контентом из Payload, формами и SEO.
Сайты обоих брендов по макетам: весь контент — в Payload, 5 языков, SEO и пересборка по событию.
## 2. Входит
1. Страницы по макетам для обоих брендов: главная, цены, локации (карта, отрисованная на сервере), поддержка ([07-frontend.md](../07-frontend.md), раздел 2). Юридические страницы `/legal/*`, 404 и 500.
2. Коллекции `pages`, `faq` (с местами показа), `leads`; поля контактов в `sites`.
3. Контент из макетов на RU и EN: тексты, FAQ, локации, тарифы.
4. Черновики юридических текстов на RU и EN с заглушками вместо данных юрлица: условия, конфиденциальность, возвраты, cookies.
5. ALTCHA ([08-integrations.md](../08-integrations.md), раздел 2). Формы «Индивидуальные условия» и обратной связи с ALTCHA пишут в `leads`. Письмо администратору появится в 1c.
1. Страницы по макетам для обоих брендов: главная, цены, локации (карта и глобус, отрисованные на сервере), поддержка ([07-frontend.md](../07-frontend.md), раздел 2). Юридические страницы `/legal/*`, 404 и 500.
2. Контент в Payload ([D-029](../decisions/D-029-pages-blocks.md)): коллекция `pages` из блоков; `faq` с местами показа, включая вопросы кабинета для 1d; поля `sites` — почта и Telegram поддержки, часы работы, SEO по умолчанию.
3. Тексты на 5 языках ([D-033](../decisions/D-033-translations.md)): RU и EN — из макетов и `i18n.js`, de, fr, es — перевод с глоссарием. Тексты описывают работающий продукт ([07-frontend.md](../07-frontend.md), раздел 7).
4. Черновики юридических текстов на 5 языках с заглушками вместо данных юрлица (Q-13): условия, конфиденциальность, возвраты, cookies.
5. Формы «Индивидуальные условия», «Особые условия» и «Написать нам» — только интерфейс: проверка полей и состояние «отправлено», без отправки ([D-026](../decisions/D-026-stage-order.md)).
6. SEO: `<title>` и описания на каждом языке, `hreflang`, `canonical`, `sitemap.xml` и `robots.txt` на каждый домен, картинки для соцсетей.
7. Статическая сборка «язык × валюта» и пересборка по событию из Payload ([D-017](../decisions/D-017-static-pages.md)).
8. Решить, показывать ли количество свободных серверов.
7. Статическая сборка «язык × валюта» и пересборка по событию из Payload ([D-017](../decisions/D-017-static-pages.md), [D-030](../decisions/D-030-revalidate-path.md)).
8. Счётчик свободных серверов рядом со статусом, если поле заполнено ([D-032](../decisions/D-032-free-servers.md)).
## 3. Не входит
Оформление заказа (1d), кабинет (1f), переводы на de, fr, es (1h; до этого — английский запасной).
ALTCHA (3a), отправка заявок (3d, 3e), Umami и баннер cookies (3f), оформление заказа (1e).
## 4. Перед стартом
## 4. Решения при сверке плана (21–22.10.2026)
Открытых вопросов нет: Q-02, Q-08, Q-09 и Q-16 решены 21.10.2026 ([00-index.md](../00-index.md), раздел 4.1).
1. Цвета карт Вейликса: глобус в hero — как в `Main`, плоская карта на /locations — как в `Locations`.
2. Статусы локаций везде по [01-product.md](../01-product.md): «Серверы в наличии» / «Установим за 24 часа» и «Включено» / «Скоро» — в списках, карточках, на карте и во всплывающей карточке.
3. `--ink-3` подбирается в обеих темах до контраста 4,5:1 (WCAG AA); в макете — 3,9:1.
4. Карта: точки расположены как в макете; клик выбирает ближайшую точку (в Европе точки перекрываются); выбор синхронизируется между картой и сеткой, с клавиатуры — через сетку. На узком экране всплывающая карточка — HTML поверх карты.
5. FAQ главной и поддержки — отдельные записи: формулировки в макетах разные. Блок FAQ на /pricing появляется, только если есть вопросы с этим местом показа. Цен в ответах нет.
6. Seed создаёт страницы, FAQ и юридические тексты, только если их ещё нет: повторный `pnpm seed` не затирает правки из админки.
7. Под формами — строка о согласии с политикой конфиденциальности со ссылкой, без чекбокса. Обязательные поля: в «Написать нам» — почта и текст, в заявке — хотя бы один контакт.
8. Цена «в месяц» у годового тарифа mass округляется вниз до целых: 582 ₽, $5.82. Экономия считается точно.
9. «Купить» передаёт тариф, локацию и валюту; у mass по умолчанию выбран «Год».
10. Ошибки вёрстки макетов исправляются: переполнение сеток на 375 px, поля 15 px, `div role=button` вместо радиокнопок и ссылок, поля без подписей, кнопки меньше 44 px, нет `prefers-reduced-motion`.
11. Сверка с макетами по скриншотам и замеры Lighthouse — в headless Chromium (R-19).
## 5. Готово, когда
## 5. Перед стартом
1. Страницы обоих брендов совпадают с макетами: светлая и тёмная тема, десктоп и мобильный, RU и EN.
2. Правка цены, статуса локации или FAQ в админке видна на сайте в течение нескольких секунд.
Root: R-19 — сделано.
## 6. Готово, когда
1. Страницы обоих брендов совпадают с макетами: светлая и тёмная тема, десктоп и мобильный, 5 языков.
2. Правка цены, статуса локации, FAQ или текста страницы в админке видна на сайте в течение нескольких секунд.
3. Lighthouse mobile ≥ 90 на главной и странице цен обоих брендов.
4. Формы создают заявки, ALTCHA работает.
4. Формы проверяют поля и показывают состояние «отправлено».
5. `sitemap.xml` и `hreflang` проходят проверку.
+9 -10
View File
@@ -1,16 +1,16 @@
# Этап 1c. Вход по коду и почта
# Этап 1c. Вход по коду
Статус: не начат.
## 1. Цель
Регистрация и вход по коду из письма в кабинетах обоих брендов; почтовая подсистема с журналом.
Регистрация и вход по коду в кабинетах обоих брендов. Письма не отправляются, а пишутся в журнал: код виден в админке.
## 2. Входит
1. Почта ([08-integrations.md](../08-integrations.md), раздел 1): глобал «Почта» (транспорты `smtp`, `sendmail`, `log_only`), email-адаптер, `email-templates` с шапкой и подвалом бренда, `email-log`, задача `send-email`, тестовое письмо, флаг «Записывать коды входа в журнал».
2. Шаблоны на RU и EN: `login_code`, `admin_new_lead` (и подключить его к формам из 1b).
3. `customers` со своей стратегией, `customer-sessions`, `auth-codes`; запрос и проверка кода, лимиты, ALTCHA ([05-auth.md](../05-auth.md), разделы 2–4).
1. Почта ([08-integrations.md](../08-integrations.md), раздел 1): глобал «Почта» с транспортом `log_only`, email-адаптер, `email-templates` с шапкой и подвалом бренда, `email-log`, задача `send-email`, флаг «Записывать коды входа в журнал».
2. Шаблон `login_code` на 5 языках.
3. `customers` со своей стратегией, `customer-sessions`, `auth-codes`; запрос и проверка кода, лимиты по IP и email ([05-auth.md](../05-auth.md), разделы 2–4).
4. Страница `/login` по макету с состояниями: код отправлен, ошибка, истёк, повторная отправка через 60 секунд.
5. Выход, выход на всех устройствах.
6. Язык и валюта аккаунта при регистрации ([04-billing.md](../04-billing.md), раздел 2).
@@ -18,15 +18,14 @@
## 3. Не входит
Telegram (этап 3), реферальная привязка при регистрации (1g).
ALTCHA (3a), отправка писем через `sendmail` и `smtp` (3c), Telegram (2a–2c), реферальная привязка при регистрации (1h).
## 4. Перед стартом
Root: R-07 (Postfix, OpenDKIM, DNS) или данные SMTP-провайдера. Без них этап делается на транспорте `log_only`.
Этап 1b готов.
## 5. Готово, когда
1. Регистрация и вход работают на `dev.my.veilix.app` и `dev.my.veilixvpn.com`; аккаунты сайтов независимы.
2. С флагом коды видны в журнале; на `log_only` письма не уходят.
3. Через `sendmail` или `smtp` письмо доходит до Gmail не в спам; оценка mail-tester ≥ 9/10.
4. Лимиты и счётчик попыток работают; сессии отзываются.
2. Код входа виден в журнале писем в админке; письма никуда не уходят.
3. Лимиты и счётчик попыток работают; сессии отзываются.
-36
View File
@@ -1,36 +0,0 @@
# Этап 1d. Биллинг без эквайринга
Статус: не начат.
## 1. Цель
Деньги и заказы работают целиком: оформление заказа, оплата с баланса, ручные платежи, продления, льготный период — без внешних платёжных систем.
## 2. Входит
1. Коллекции `orders`, `payments`, `ledger-entries`, `payment-methods` (структура), `keys` (поля и статусы), `key-extensions`, `audit-log`.
2. `core/billing`: `processPayment`, оплата с баланса, задачи `renewals`, `expiry`, `reminders`, `reconcile`; блокировки и уникальные ограничения ([04-billing.md](../04-billing.md)).
3. `/order` по макетам обоих брендов: шаг «Почта» из 1c, шаг «Оплата» (с баланса; «Заказ создан, ожидает оплаты», когда платёжных систем нет), согласие с условиями, сводка из тарифа, локации и валюты.
4. `/buy` в кабинете: dedicated — сетка локаций с ценами, mass — «Месяц» и «Год».
5. Админка: ручной платёж, корректировка баланса, возврат на баланс, продление вручную (запись в `key-extensions`, [04-billing.md](../04-billing.md), раздел 6.4), блокировка, «Очередь выдачи»; всё — в журнал действий.
6. Шаблоны писем на RU и EN: `order_paid`, `key_provisioning`, `renewal_reminder`, `expiry_reminder`, `renewal_succeeded`, `renewal_failed`, `grace_started`, `key_expired`, `topup_succeeded`, `refund_issued`, `admin_new_order`, `admin_provisioning_needed`.
## 3. Не входит
Подключения и выдача ключа (1e), реальные платёжные системы (этап 4). Для проверок ключ переводится в `active` вручную в админке.
## 4. Перед стартом
Этап 1c готов.
## 5. Готово, когда
Автотесты `core/billing` проходят сценарии:
1. Ручное пополнение → оплата заказа с баланса → заказ оплачен → ключ `provisioning`.
2. Частичный баланс + ручной платёж на разницу → заказ оплачен.
3. Продление с баланса за 24 часа; денег нет → заказ ждёт → пополнение само оплачивает продление.
4. Переходы в льготный период и «истёк» с письмами.
5. Частичный и полный возврат на баланс, с отменой ключа и без.
6. Повторный `processPayment` и параллельные запуски задач не списывают дважды.
7. `reconcile` не находит расхождений.
+36
View File
@@ -0,0 +1,36 @@
# Этап 1d. Ключи и подключения
Статус: не начат.
## 1. Цель
Администратор создаёт ключи и подключения вручную; пользователь видит ключи в кабинете и получает конфиги и ссылки.
## 2. Входит
1. Коллекции `keys` (поля и статусы) и `connections` с шифрованием содержимого ([03-data-model.md](../03-data-model.md), раздел 5); журнал действий `audit-log`.
2. Админка:
a. ключ вручную: пользователь, тариф, локация (dedicated);
b. подключения: WG/AWG — файлом или текстом, ссылка Happ, ссылка Xray, RU-адрес, номер устройства, страна;
c. «Выдать ключ», «Очередь выдачи», «К отключению», блокировка ключа.
3. Кабинет по макетам `App` и `MassApp`:
a. главная: ключи, «Купить ключ», FAQ кабинета;
b. список ключей, бейдж «Истекает» ([04-billing.md](../04-billing.md), раздел 15);
c. страница ключа: срок, WG-конфиги (скачать, QR), Happ и Xray (копировать, QR), RU-адрес; у mass — WG по странам.
4. Состояния: готовится, активен, льготный период, истёк, заблокирован; нет ключей; нет подключений.
5. Содержимое конфигов отдаётся отдельным запросом только владельцу и в HTML страницы не попадает. QR строится в браузере.
6. Шаблон `key_ready` на 5 языках.
## 3. Не входит
Покупка и оплата (1e), автоматическая выдача (1f), автопродление и «Продлить сейчас» (1g).
## 4. Перед стартом
Этап 1c готов.
## 5. Готово, когда
1. Ключ, созданный и выданный в админке, виден в кабинете владельца активным; срок идёт с момента выдачи.
2. Скачанный `.conf` импортируется в WireGuard; QR сканируется в WireGuard и Happ.
3. Чужой пользователь получает 404 на конфиг (тест).
+39
View File
@@ -0,0 +1,39 @@
# Этап 1e. Счёт и оплата
Статус: не начат.
## 1. Цель
Покупка ключа и пополнение баланса работают целиком на демо-оплате, без эквайринга.
## 2. Входит
1. Коллекции `orders`, `payments`, `ledger-entries`, `payment-methods`.
2. `core/billing`: `processPayment`, оплата с баланса, блокировки и уникальные ограничения ([04-billing.md](../04-billing.md), разделы 1–5 и 14).
3. Платёжная система «Демо» ([D-027](../decisions/D-027-demo-payments.md)): страница демо-оплаты, демо-привязка карты, доступ по списку IP. `manual` — для администраторов.
4. `/order` по макетам обоих брендов: шаг «Почта» (вход из 1c), шаг «Оплата» (с баланса, демо-оплатой, демо-картой; «Заказ создан, ожидает оплаты», если платёжных систем нет), согласие с условиями, сводка из тарифа, локации и валюты.
5. Кабинет:
a. `/buy`: dedicated — сетка локаций с ценами, mass — «Месяц» и «Год»;
b. «Счёт и платежи»: баланс, пополнение (пресеты и своя сумма), привязанная карта и «Отвязать карту», история;
c. смена валюты аккаунта ([04-billing.md](../04-billing.md), раздел 2).
6. После оплаты ключ создаётся в статусе `provisioning` и выдаётся вручную (1d); автоматически — с 1f.
7. Админка: ручной платёж, корректировка баланса, возврат на баланс; всё — в журнал действий.
8. Шаблоны на 5 языках: `order_paid`, `key_provisioning`, `topup_succeeded`, `refund_issued`, `admin_new_order`, `admin_provisioning_needed`.
## 3. Не входит
Продления (1g), реальные платёжные системы (3b, 4a, 4b).
## 4. Перед стартом
Этап 1d готов.
## 5. Готово, когда
1. С разрешённого IP ключ покупается демо-оплатой и с баланса; отказ демо-оплаты виден пользователю.
2. Демо-карта привязывается и отвязывается.
3. Автотесты `core/billing` проходят сценарии:
a. пополнение → оплата заказа с баланса → заказ оплачен → ключ `provisioning`;
b. частичный баланс и оплата разницы → заказ оплачен;
c. частичный и полный возврат на баланс, с отменой ключа и без;
d. повторный `processPayment` не списывает дважды.
-26
View File
@@ -1,26 +0,0 @@
# Этап 1e. Ключи и подключения
Статус: не начат.
## 1. Цель
Администратор выдаёт ключи вручную; пользователь получает конфиги и ссылки на странице ключа.
## 2. Входит
1. Коллекция `connections` с шифрованием содержимого ([03-data-model.md](../03-data-model.md), 5.2).
2. Админка: на странице ключа — добавление подключений (WG/AWG — файлом или текстом, ссылка Happ, ссылка Xray, RU-адрес, номер устройства, страна), действие «Выдать ключ» (к сроку добавляются дни продлений без оплаты, ждавшие выдачи), список «К отключению».
3. Страница ключа в кабинете: срок, галочка автопродления, «Продлить сейчас», WG-конфиги (скачать, QR), Happ/Xray (копировать, QR); для mass — WG по странам: конфиги, которые добавил администратор; нужна другая страна — ссылка на поддержку.
4. Состояния: готовится, льготный период, истёк, нет подключений.
5. Содержимое конфигов отдаётся отдельным запросом только владельцу, в HTML страницы не попадает. QR строится в браузере из полученного содержимого.
6. Шаблон `key_ready` на RU и EN.
## 3. Перед стартом
Этап 1d готов.
## 4. Готово, когда
1. Администратор выдал ключ — пользователь видит его активным, срок пошёл с момента выдачи.
2. Скачанный `.conf` импортируется в WireGuard; QR сканируется в WireGuard и Happ.
3. Чужой пользователь получает 404 на конфиг (тест).
-24
View File
@@ -1,24 +0,0 @@
# Этап 1f. Веб-кабинеты
Статус: не начат.
## 1. Цель
Кабинеты обоих брендов по макетам `App` и `MassApp`.
## 2. Входит
1. Главная: ключи, «Купить ключ», FAQ.
2. Список ключей; бейдж «Истекает» по правилу [04-billing.md](../04-billing.md), раздел 15.
3. «Счёт и платежи»: баланс, пополнение (пресеты и своя сумма; пока платёжных систем нет — понятное сообщение), сохранённая карта и «Отвязать карту» (видно с этапа 4), ближайшие списания, история.
4. Настройки: язык, валюта (правило — [04-billing.md](../04-billing.md), раздел 2), тема; выход.
5. Мобильная навигация: вкладки «Главная, Ключи, Купить, Ещё».
6. Различия брендов: у mass «Список ключей» без «текущей/запасной локации».
## 3. Не входит
Реферальная страница (1g), MiniApp (этап 3).
## 4. Готово, когда
Кабинеты обоих брендов совпадают с макетами: светлая и тёмная тема, десктоп и мобильный, RU и EN. Все данные — реальные, из базы.
+24
View File
@@ -0,0 +1,24 @@
# Этап 1f. Выдача ключей «Демо»
Статус: не начат.
## 1. Цель
После оплаты ключ выдаётся сам через адаптер выдачи. Сейчас это эмулятор; на этапе 3g на его место встанет настоящий API.
## 2. Входит
1. Адаптер выдачи в `core/provisioning/` ([D-028](../decisions/D-028-provisioning-adapter.md)): выдать ключ, создать WG-конфиг (для устройства, у mass — для страны), отключить подключения ключа. Реализации `manual` и `demo`; режим — настройка сайта.
2. `demo`: при оплате ключ выдаётся сам — со ссылкой Happ и подключением к RU-адресу. Локация «24 часа» выдаётся с задержкой (по умолчанию минута), чтобы было видно состояние «готовится». Данные правдоподобные, но фиктивные: адреса из тестовых диапазонов.
3. Кабинет: «Получить конфиг WireGuard» на странице ключа — для устройства, у mass — для страны.
4. Истёкший или отменённый ключ: подключения отключаются через адаптер; у `manual` — по списку «К отключению».
## 3. Перед стартом
Этап 1e готов.
## 4. Готово, когда
1. После демо-оплаты ключ в локации «в наличии» сразу активен со ссылкой Happ; в локации «24 часа» — сначала «готовится», затем активен.
2. WG-конфиг создаётся по кнопке и импортируется в WireGuard (подключиться он не сможет: адреса фиктивные).
3. В режиме `manual` всё работает, как в 1d.
+29
View File
@@ -0,0 +1,29 @@
# Этап 1g. Продления
Статус: не начат.
## 1. Цель
Ключи продлеваются сами — с баланса, затем с демо-карты; льготный период, истечение и напоминания работают.
## 2. Входит
1. Задачи `renewals`, `expiry`, `reminders`, `reconcile` ([04-billing.md](../04-billing.md), разделы 6–7; [02-architecture.md](../02-architecture.md), раздел 7).
2. Автопродление: галочка на ключе, «Продлить сейчас»; списание с баланса, затем с демо-карты, повторы. Неуспешное списание с демо-карты включается в админке ([D-027](../decisions/D-027-demo-payments.md)).
3. Продления без оплаты: коллекция `key-extensions`, «Продлить вручную» в админке ([04-billing.md](../04-billing.md), раздел 6.4).
4. Кабинет: «Следующее списание», «Продлится автоматически через N дней» или «Осталось N дней», бейдж «Истекает».
5. Шаблоны на 5 языках: `renewal_reminder`, `expiry_reminder`, `renewal_succeeded`, `renewal_failed`, `grace_started`, `key_expired`.
## 3. Перед стартом
Этап 1f готов.
## 4. Готово, когда
Автотесты проходят сценарии:
1. Продление с баланса за 24 часа до окончания; денег нет → заказ ждёт → пополнение само оплачивает продление.
2. Продление с демо-карты; неуспешное списание → повторы → льготный период.
3. Переходы в льготный период и «истёк» с письмами в журнал.
4. Параллельные запуски задач не продлевают ключ дважды.
5. `reconcile` не находит расхождений.
-26
View File
@@ -1,26 +0,0 @@
# Этап 1h. Переводы, аналитика, запуск prod
Статус: не начат.
## 1. Цель
Сайты и кабинеты на 5 языках работают на основных доменах.
## 2. Входит
1. Переводы de, fr, es: интерфейс и контент Payload, машинный перевод LLM с глоссарием ([06-i18n.md](../06-i18n.md), раздел 7); проверка непереведённых ключей.
2. Umami на этом сервере ([D-018](../decisions/D-018-analytics.md)) с проксированием через домены брендов; баннер cookies ([08-integrations.md](../08-integrations.md), раздел 8).
3. Проверка производительности (Lighthouse mobile ≥ 90) и доступности.
4. Prod под пользователем vx_prod: `.env`, команда выкладки с папками релизов и откатом ([02-architecture.md](../02-architecture.md), раздел 5), первая выкладка, начальные данные prod, первый администратор, smoke-тесты.
5. Бэкапы базы и media с проверкой восстановления.
6. Юридические черновики на сайтах (Q-13 — пока с заглушками).
## 3. Перед стартом
Root: R-08…R-11, по желанию R-15. Решения: Q-14 (куда бэкапы), Q-18 (кто запускает выкладку).
## 4. Готово, когда
1. Основные домены работают по HTTPS, dev и prod разделены.
2. Выкладка и откат отрепетированы.
3. Восстановление из бэкапа проверено.
@@ -1,10 +1,10 @@
# Этап 1g. Реферальная программа
# Этап 1h. Реферальная программа
Статус: не начат.
## 1. Цель
«Приведите друга — вы оба получите по месяцу в подарок» по правилам [04-billing.md](../04-billing.md), раздел 11. Бонус — дни срока ключа, а не деньги ([D-025](../decisions/D-025-referral-days.md)).
«Приведите друга — вы оба получите по месяцу в подарок» по правилам [04-billing.md](../04-billing.md), раздел 11. Бонус — дни срока ключа, а не деньги ([D-025](../decisions/D-025-referral-days.md)). Этим этапом заканчивается концепт: дальше он проверяется на dev целиком.
## 2. Входит
@@ -14,9 +14,13 @@
4. Бонус обоим после первой оплаты заказа `new_key` приглашённого: дни к ключам через `key-extensions`; статус `review` при совпадении хэша IP.
5. Число дней бонуса в `sites` (`referralBonusDays`).
6. Страница `/referral` по макету: приглашено, начислено месяцев, ожидает; ссылка с копированием; приглашённые с замаскированной почтой. Условия под ссылкой — про дни, а не про списание ([07-frontend.md](../07-frontend.md), раздел 7).
7. Шаблон `referral_reward` на RU и EN; список приглашений в админке.
7. Шаблон `referral_reward` на 5 языках; список приглашений в админке.
## 3. Готово, когда
## 3. Перед стартом
Этап 1g готов.
## 4. Готово, когда
1. A делится ссылкой → B регистрируется → B оплачивает первый заказ → к ключу B и к последнему ключу A добавлено по 30 дней.
2. У A нет подходящего ключа — дни добавляются к следующему ключу A.
-19
View File
@@ -1,19 +0,0 @@
# Этап 2. Chatwoot и Twenty CRM
Статус: не начат.
## 1. Входит
1. Chatwoot ([08-integrations.md](../08-integrations.md), раздел 4): виджет на сайтах и в кабинетах, отдельные входящие каналы для каждого бренда; идентификация вошедших пользователей с HMAC; категория в баннере cookies.
2. Боты поддержки обоих брендов подключены к Chatwoot как Telegram-каналы.
3. Почта поддержки: email-каналы Chatwoot для ящиков `help@…` на почтовом хостинге — письма по IMAP, ответы через SMTP хостинга (Q-16).
4. Twenty ([08-integrations.md](../08-integrations.md), раздел 5): заявки уходят через API фоновой задачей с повторами, `leads.crmId`.
## 2. Перед стартом
Root: R-12 — VPS, Chatwoot, Twenty, ключи API, боты поддержки в BotFather. Ящики поддержки (R-18) и их данные IMAP и SMTP.
## 3. Готово, когда
1. Сообщения из виджетов и ботов поддержки приходят в Chatwoot с указанием бренда; вошедший пользователь опознан.
2. Заявки появляются в Twenty.
+27
View File
@@ -0,0 +1,27 @@
# Этап 2a. MiniApp в Telegram
Статус: не начат.
## 1. Цель
Кабинет внутри Telegram по макетам `AppTG` и `MassAppTG`: всё, что умеет веб-кабинет, на тех же демо-режимах.
## 2. Входит
1. MiniApp на `tg.*` с Telegram SDK: BackButton, MainButton, тема Telegram, отклик вибрацией ([07-frontend.md](../07-frontend.md), раздел 2).
2. Вход по `initData`, аккаунт по Telegram без почты ([05-auth.md](../05-auth.md), раздел 6.1).
3. Ключи, покупка, счёт, рефералы — на тех же `core/` и демо-режимах, что веб-кабинет ([D-027](../decisions/D-027-demo-payments.md), [D-028](../decisions/D-028-provisioning-adapter.md)).
4. Тестовые боты для dev; dev-MiniApp открывается только для Telegram-аккаунтов из списка.
## 3. Не входит
Команды и уведомления бота (2b), привязка и объединение аккаунтов (2c), звёзды Telegram (4a).
## 4. Перед стартом
1. Root: R-13 — основные и тестовые боты в BotFather, адреса MiniApp.
2. Решения: Q-10 (имена ботов), Q-11 (оплата в Telegram; до этапа 4a — демо-оплата и баланс).
## 5. Готово, когда
Из MiniApp можно зарегистрироваться, купить ключ демо-оплатой, получить конфиги, пополнить баланс и пригласить друга.
+21
View File
@@ -0,0 +1,21 @@
# Этап 2b. Основной бот
Статус: не начат.
## 1. Цель
Основные боты обоих брендов: команды, меню, кнопка MiniApp, уведомления.
## 2. Входит
1. Боты на grammY ([D-015](../decisions/D-015-telegram-bots.md)): вебхук `/svc/telegram/<сайт>/webhook` с секретным токеном, команды и меню ([08-integrations.md](../08-integrations.md), раздел 6). Тексты и кнопки — в Payload на 5 языках.
2. Уведомления из [04-billing.md](../04-billing.md), раздел 12, дублируются в бот, если Telegram привязан.
3. Реферальный код через `/start <код>`.
## 3. Перед стартом
Этап 2a готов.
## 4. Готово, когда
Команды работают на 5 языках; уведомления о выдаче ключа и продлениях приходят в бот.
+21
View File
@@ -0,0 +1,21 @@
# Этап 2c. Связь аккаунтов Telegram и сайта
Статус: не начат.
## 1. Цель
Человек с Telegram и почтой — один аккаунт на сайте бренда, откуда бы он ни вошёл.
## 2. Входит
1. Привязка почты из Telegram ([05-auth.md](../05-auth.md), раздел 6.2): код на почту, до этапа 3c — в журнал писем.
2. «Подключить Telegram» в кабинете и «Войти через Telegram» на сайте ([05-auth.md](../05-auth.md), раздел 6.3).
3. Объединение аккаунтов, автоматическое и ручное из админки ([05-auth.md](../05-auth.md), раздел 6.4).
## 3. Перед стартом
Этап 2b готов. Root: домен кабинета для Telegram Login в BotFather (R-13).
## 4. Готово, когда
Сценарии привязки и объединения аккаунтов проходят: автотесты и проверка вручную.
-23
View File
@@ -1,23 +0,0 @@
# Этап 3. Telegram
Статус: не начат.
## 1. Входит
1. Основные боты обоих брендов на grammY: вебхук, команды, меню, тексты в Payload на всех языках ([08-integrations.md](../08-integrations.md), раздел 6).
2. MiniApp по макетам `AppTG` и `MassAppTG` с Telegram SDK: BackButton, MainButton, тема Telegram, отклик вибрацией; вход по `initData`.
3. Привязка почты из Telegram, «Подключить Telegram» в кабинете, «Войти через Telegram» на сайте, объединение аккаунтов ([05-auth.md](../05-auth.md), раздел 6).
4. Уведомления в бот; реферальный код через `/start`.
5. Тестовые боты для dev с доступом по списку Telegram-аккаунтов.
6. Оплата в Telegram — по решению Q-11.
## 2. Перед стартом
1. Root: R-13 — основные и тестовые боты, домен для Telegram Login, адреса MiniApp.
2. Решения: Q-10 (имена ботов), Q-11 (оплата в Telegram).
## 3. Готово, когда
1. Из Telegram можно зарегистрироваться, купить ключ (по Q-11), получить конфиги, пополнить баланс, пригласить друга.
2. Уведомления приходят в бот.
3. Сценарии привязки и объединения аккаунтов проходят.
+22
View File
@@ -0,0 +1,22 @@
# Этап 3a. ALTCHA
Статус: не начат.
## 1. Цель
Защита запроса кода входа и форм от ботов без сторонних сервисов ([D-013](../decisions/D-013-captcha.md)).
## 2. Входит
1. ALTCHA ([08-integrations.md](../08-integrations.md), раздел 2): эндпоинт `/svc/altcha/challenge`, ключ подписи в `.env`, одноразовые решения; провайдер изолирован в `core/`.
2. Без видимого виджета: задача решается в фоне, пока человек заполняет форму. Скрипт грузится только на страницах с формами.
3. Запрос кода входа; формы — вместе с их отправкой (3d, 3e).
4. Root: `limit_req` в nginx на вход и формы ([09-infrastructure.md](../09-infrastructure.md), раздел 4).
## 3. Перед стартом
Фаза 2 готова.
## 4. Готово, когда
Запрос кода без решения или с уже использованным решением отклоняется; в браузере вход работает без видимой капчи.
+21
View File
@@ -0,0 +1,21 @@
# Этап 3b. ЮKassa
Статус: не начат.
## 1. Цель
Пополнение баланса в рублях через ЮKassa.
## 2. Входит
1. Адаптер `yookassa` ([08-integrations.md](../08-integrations.md), раздел 7): создание платежа, вебхук с проверкой, идемпотентная обработка ([04-billing.md](../04-billing.md), раздел 14). Только пополнение (`topup`).
2. Состояния пополнения: ожидание, отказ, успех.
3. Сначала тестовый магазин, затем боевой.
## 3. Перед стартом
Root: R-14 — аккаунт ЮKassa (сначала тестовый магазин), адрес вебхука. Для боевого магазина нужны данные юрлица (Q-13). Разные аккаунты для брендов — Q-17.
## 4. Готово, когда
Пополнение в тестовом режиме проходит путь от оплаты до зачисления, включая повторную доставку вебхуков.
+21
View File
@@ -0,0 +1,21 @@
# Этап 3c. Отправка почты
Статус: не начат.
## 1. Цель
Письма уходят на самом деле и не попадают в спам.
## 2. Входит
1. Транспорты `sendmail` (Postfix) и `smtp` в глобале «Почта», кнопка «Отправить тестовое письмо» ([08-integrations.md](../08-integrations.md), раздел 1).
2. Postfix, OpenDKIM, SPF, DKIM, DMARC для обоих доменов ([09-infrastructure.md](../09-infrastructure.md), раздел 6).
3. Письма администраторам уходят на почту поддержки.
## 3. Перед стартом
Root: R-07 (или данные SMTP-провайдера), R-18 (ящики поддержки).
## 4. Готово, когда
Письмо доходит до Gmail не в спам; оценка mail-tester ≥ 9/10.
+25
View File
@@ -0,0 +1,25 @@
# Этап 3d. Twenty CRM
Статус: не начат.
## 1. Цель
Заявки «Индивидуальные условия» и «Особые условия» с сайта и из кабинета попадают в Twenty.
## 2. Входит
1. Формы заявок отправляют данные: проверка полей, ALTCHA (3a), лимит по IP.
2. Twenty ([08-integrations.md](../08-integrations.md), раздел 5): человек и сделка с полями заявки, брендом и страницей. Нужен ли буфер в базе на случай, когда Twenty недоступен, — решаем на старте этапа.
3. Письмо `admin_new_lead` на почту поддержки.
## 3. Не входит
Форма «Написать нам» — это обращение в поддержку, она уходит в Chatwoot (3e).
## 4. Перед стартом
Root: R-12 — Twenty на VPS, ключ API.
## 5. Готово, когда
Заявки обоих брендов появляются в Twenty; при недоступности Twenty заявка не теряется молча.
+22
View File
@@ -0,0 +1,22 @@
# Этап 3e. Chatwoot
Статус: не начат.
## 1. Цель
Поддержка обоих брендов в одном Chatwoot: виджет, Telegram, почта.
## 2. Входит
1. Chatwoot ([08-integrations.md](../08-integrations.md), раздел 4): виджет на сайтах и в кабинетах, свои входящие каналы у каждого бренда; идентификация вошедших пользователей с HMAC.
2. Боты поддержки обоих брендов подключены к Chatwoot как Telegram-каналы; на сайтах они заменяют `@veilix_support`.
3. Почта поддержки: email-каналы Chatwoot для ящиков `help@…` на почтовом хостинге — письма по IMAP, ответы через SMTP хостинга (Q-16).
4. Форма «Написать нам» создаёт обращение в Chatwoot.
## 3. Перед стартом
Root: R-12 — Chatwoot на VPS, ключи API, боты поддержки в BotFather; ящики поддержки (R-18) и их данные IMAP и SMTP.
## 4. Готово, когда
Сообщения из виджетов, ботов поддержки, почты и формы приходят в Chatwoot с указанием бренда; вошедший пользователь опознан.
+20
View File
@@ -0,0 +1,20 @@
# Этап 3f. Umami и баннер cookies
Статус: не начат.
## 1. Цель
Своя аналитика без cookies и согласие на необязательные cookies.
## 2. Входит
1. Umami на этом сервере ([D-018](../decisions/D-018-analytics.md), [08-integrations.md](../08-integrations.md), раздел 8): пользователь `umami`, база `umami`, панель `umi.veilix.cc`; трекер — через домены брендов под нейтральными путями; поле `domains.umamiWebsiteId`.
2. Баннер cookies: обязательные (сессия, язык, валюта) и функциональные (Chatwoot). Решение хранится в cookie `vx_consent`; виджет Chatwoot загружается только после согласия.
## 3. Перед стартом
Root: R-10 — nginx и сертификат для `umi.veilix.cc`, проксирование путей трекера.
## 4. Готово, когда
Посещения видны в Umami; без согласия виджет Chatwoot не загружается.
+14
View File
@@ -0,0 +1,14 @@
# Этап 3g. Выдача ключей через API
Статус: обсуждение при старте этапа.
## 1. Что известно
1. Адаптер `api` встаёт на место `demo` ([D-028](../decisions/D-028-provisioning-adapter.md)): по тарифу (страны, теги) подбирается свободный сервер, бэкенд возвращает подключения для ключа.
2. Автоматика создаёт те же подключения, что администратор или демо-адаптер ([D-020](../decisions/D-020-key-models.md)), и отключает их, когда ключ истекает.
3. Наличие в локациях и счётчик свободных серверов обновляются автоматически. Сайты пересобираются по событию; если числа меняются часто — добавляем обновление из браузера ([D-032](../decisions/D-032-free-servers.md)).
4. VPN-серверы не ведут журналов ([10-security.md](../10-security.md), раздел 6).
## 2. Обсудить при старте
Источник серверов и подключений, способ интеграции, как получать WG-конфиги mass по странам, обработка ошибок выдачи.
+26
View File
@@ -0,0 +1,26 @@
# Этап 3h. Публичный запуск
Статус: не начат.
## 1. Цель
Сайты и кабинеты работают на основных доменах и открыты для всех.
## 2. Входит
1. Prod под пользователем vx_prod: `.env`, команда выкладки с папками релизов и откатом ([02-architecture.md](../02-architecture.md), раздел 5), начальная миграция, первая выкладка, начальные данные prod, первый администратор, smoke-тесты.
2. Бэкапы базы и media с проверкой восстановления.
3. Финальная проверка переводов на 5 языках и непереведённых ключей; юридические тексты после юриста (Q-13).
4. Проверка производительности (Lighthouse mobile ≥ 90) и доступности.
5. Демо-оплата в prod — только с разрешённых IP ([D-027](../decisions/D-027-demo-payments.md)).
6. Страница nginx на случай, когда приложение не отвечает.
## 3. Перед стартом
Root: R-11, по желанию R-15 и R-16. Решения: Q-13 (юрлицо), Q-14 (куда бэкапы), Q-18 (кто запускает выкладку).
## 4. Готово, когда
1. Основные домены работают по HTTPS, dev и prod разделены.
2. Выкладка и откат отрепетированы.
3. Восстановление из бэкапа проверено.
-26
View File
@@ -1,26 +0,0 @@
# Этап 4. Платёжные системы
Статус: не начат.
## 1. Входит
1. Адаптеры ([08-integrations.md](../08-integrations.md), раздел 7):
a. Stripe: Payment Element, сохранение карты, автосписания на переменную сумму, возвраты, отвязка карты, вебхуки;
b. RUB: процессинги для карт РФ — пополнения (провайдеров выбираем на старте, Q-12);
c. криптовалюта — пополнения, экран счёта с адресом, суммой и таймером курса;
d. ЮKassa — опционально, пополнения.
2. Состояния оформления и пополнения: 3-D Secure, отказ, ожидание подтверждения сети.
3. Повторы автосписаний ([04-billing.md](../04-billing.md), 6.1); возврат на карту (`refund` + `payout`).
4. Тексты согласия на автосписания в оформлении заказа и в юридических документах.
5. Настройка платёжных систем в админке: валюты, назначения, лимиты, тестовый или боевой режим. Если бренды получат разные аккаунты одного провайдера — Q-17.
## 2. Перед стартом
1. Root: R-14 — аккаунты провайдеров (сначала тестовые).
2. Решения: Q-12; для боевого Stripe нужны данные юрлица (Q-13).
## 3. Готово, когда
1. Каждый адаптер в тестовом режиме проходит путь от оплаты до зачисления, включая повторную доставку вебхуков.
2. Автопродление через Stripe работает на тестовых картах. Если карта требует 3-D Secure, пользователь получает письмо оплатить вручную.
3. Возвраты на карту работают.
+11
View File
@@ -0,0 +1,11 @@
# Этап 4a. Звёзды Telegram
Статус: обсуждение при старте этапа.
## 1. Что известно
По правилам Telegram цифровые товары в ботах и MiniApp оплачиваются звёздами (Telegram Stars), за нарушения ботов блокируют ([08-integrations.md](../08-integrations.md), раздел 6). Варианты: звёзды, внешняя страница оплаты, покупки в Telegram только с баланса (Q-11).
## 2. Обсудить при старте
Курс звёзд к ценам тарифов, зачисление на баланс, возвраты.
+21
View File
@@ -0,0 +1,21 @@
# Этап 4b. Западные эквайринги и криптовалюта
Статус: обсуждение при старте этапа.
## 1. Входит
1. Stripe, USD ([08-integrations.md](../08-integrations.md), раздел 7): Payment Element, сохранение карты, автосписания на переменную сумму, возвраты, отвязка карты, вебхуки.
2. Криптовалюта — пополнения, экран счёта с адресом, суммой и таймером курса; провайдера выбираем на этапе.
3. Состояния оформления и пополнения: 3-D Secure, отказ, ожидание подтверждения сети.
4. Повторы автосписаний ([04-billing.md](../04-billing.md), раздел 6.1); возврат на карту (`refund` + `payout`).
5. Тексты согласия на автосписания в оформлении заказа и в юридических документах.
## 2. Перед стартом
Root: R-14 — аккаунты провайдеров (сначала тестовые). Для боевого Stripe нужны данные юрлица (Q-13). Разные аккаунты одного провайдера для брендов — Q-17.
## 3. Готово, когда
1. Каждый адаптер в тестовом режиме проходит путь от оплаты до зачисления, включая повторную доставку вебхуков.
2. Автопродление через Stripe работает на тестовых картах. Если карта требует 3-D Secure, пользователь получает письмо оплатить вручную.
3. Возвраты на карту работают.
-13
View File
@@ -1,13 +0,0 @@
# Этап 5. Автоматизация выдачи ключей
Статус: обсуждение при старте этапа.
## 1. Что известно
1. По тарифу (страны, теги) подбирается свободный сервер, бэкенд возвращает подключения для ключа.
2. Автоматика создаёт те же подключения, что на этапе 1 добавляет администратор ([D-020](../decisions/D-020-key-models.md)), и отключает их, когда ключ истекает.
3. Наличие в локациях обновляется автоматически, сайты пересобираются по событию.
## 2. Обсудить при старте
Источник серверов и подключений, способ интеграции, как получать WG-конфиги mass по странам, обработка ошибок выдачи.