Документация: этапы по фазам, решения 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:
1 parent
0cad9bae18
commit
515acfb69d
53 files changed
+778
-348
No files matched your search
@@ -50,6 +50,6 @@
|
|||||||
| `pnpm generate:types` | типы Payload в `src/payload-types.ts` после изменения коллекций |
|
| `pnpm generate:types` | типы Payload в `src/payload-types.ts` после изменения коллекций |
|
||||||
| `pnpm generate:importmap` | карта импортов админки после добавления своих компонентов |
|
| `pnpm generate:importmap` | карта импортов админки после добавления своих компонентов |
|
||||||
| `pnpm db:reset` | очистить `veilix_dev` (только её), если push схемы задаёт вопросы (переименование, удаление): без терминала их некому подтвердить. Затем перезапуск dev-сервера и `pnpm seed` |
|
| `pnpm db:reset` | очистить `veilix_dev` (только её), если push схемы задаёт вопросы (переименование, удаление): без терминала их некому подтвердить. Затем перезапуск dev-сервера и `pnpm seed` |
|
||||||
| `pnpm payload migrate:create <имя>` | миграция для prod; до первой выкладки (1h) миграции не создаём |
|
| `pnpm payload migrate:create <имя>` | миграция для prod; до первой выкладки (3h) миграции не создаём |
|
||||||
|
|
||||||
Проверка без nginx: `curl -A 'Mozilla/5.0' -H 'Host: dev.veilix.app' http://127.0.0.1:3100/…`. Без браузерного User-Agent curl считается ботом и не перенаправляется; заголовок `X-Geo-Country` так можно подставить, через nginx — нет.
|
Проверка без nginx: `curl -A 'Mozilla/5.0' -H 'Host: dev.veilix.app' http://127.0.0.1:3100/…`. Без браузерного User-Agent curl считается ботом и не перенаправляется; заголовок `X-Geo-Country` так можно подставить, через nginx — нет.
|
||||||
+51
-20
@@ -21,21 +21,52 @@
|
|||||||
|
|
||||||
## 2. Этапы
|
## 2. Этапы
|
||||||
|
|
||||||
|
Фаза — цифра, этап — буква ([D-026](decisions/D-026-stage-order.md)). Каждый этап делается сразу на 5 языках; тексты описывают работающий продукт.
|
||||||
|
|
||||||
| Этап | Содержание | Статус |
|
| Этап | Содержание | Статус |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| [0](stages/stage-0-docs.md) | Документация | готово |
|
| [0](stages/stage-0-docs.md) | Документация | готово |
|
||||||
|
|
||||||
|
### 2.1 Фаза 1. Концепт без внешних сервисов, на dev
|
||||||
|
|
||||||
|
| Этап | Содержание | Статус |
|
||||||
|
|---|---|---|
|
||||||
| [1a](stages/stage-1a-foundation.md) | Фундамент: Next + Payload, сайты, домены, языки, валюты, темы | готово |
|
| [1a](stages/stage-1a-foundation.md) | Фундамент: Next + Payload, сайты, домены, языки, валюты, темы | готово |
|
||||||
| [1b](stages/stage-1b-marketing.md) | Маркетинговые страницы обоих брендов, контент, формы с ALTCHA, SEO, юр. тексты | не начат |
|
| [1b](stages/stage-1b-marketing.md) | Сайт: страницы обоих брендов из блоков Payload, FAQ, юридические черновики, SEO; формы — только интерфейс | в работе |
|
||||||
| [1c](stages/stage-1c-auth.md) | Вход по коду, почта, сессии | не начат |
|
| [1c](stages/stage-1c-auth.md) | Вход по коду, сессии; письма — в журнал | не начат |
|
||||||
| [1d](stages/stage-1d-billing.md) | Биллинг без эквайринга, оформление заказа, продления | не начат |
|
| [1d](stages/stage-1d-keys.md) | Ключи и подключения: ручное создание в админке, ключи в кабинете | не начат |
|
||||||
| [1e](stages/stage-1e-keys.md) | Ключи и подключения, ручная выдача | не начат |
|
| [1e](stages/stage-1e-billing.md) | Счёт и оплата: заказы, баланс, демо-оплата, оформление заказа | не начат |
|
||||||
| [1f](stages/stage-1f-cabinet.md) | Веб-кабинеты обоих брендов | не начат |
|
| [1f](stages/stage-1f-provisioning.md) | Выдача ключей «Демо» — эмулятор API выдачи | не начат |
|
||||||
| [1g](stages/stage-1g-referral.md) | Реферальная программа | не начат |
|
| [1g](stages/stage-1g-renewals.md) | Продления: автопродление, льготный период, напоминания | не начат |
|
||||||
| [1h](stages/stage-1h-launch.md) | Переводы, Umami и баннер cookies, PageSpeed, выкладка в prod | не начат |
|
| [1h](stages/stage-1h-referral.md) | Реферальная программа | не начат |
|
||||||
| [2](stages/stage-2-support-crm.md) | Chatwoot и Twenty CRM | не начат |
|
|
||||||
| [3](stages/stage-3-telegram.md) | Telegram: боты, MiniApp, вход и привязка | не начат |
|
### 2.2 Фаза 2. Telegram
|
||||||
| [4](stages/stage-4-payments.md) | Платёжные системы: Stripe, RUB-процессинг, крипта | не начат |
|
|
||||||
| [5](stages/stage-5-keys-automation.md) | Автоматизация выдачи ключей | обсуждение при старте |
|
| Этап | Содержание | Статус |
|
||||||
|
|---|---|---|
|
||||||
|
| [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. Как запускать этап в новой сессии
|
## 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-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-03 | Валюта по умолчанию для нового посетителя | По языку: ru → RUB, остальные → USD; настраивается у домена | [06-i18n.md](06-i18n.md), раздел 6 |
|
||||||
| Q-04 | Валюта аккаунта | Задаётся при регистрации из выбранной; меняется, пока баланс нулевой и нет ключей; дальше — через поддержку | [04-billing.md](04-billing.md), раздел 2 |
|
| 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-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-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-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-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-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 |
|
| Q-19 | Реферальный бонус днями: крайние случаи | Приглашённому тоже 30 дней; ключ готовится — дни добавятся при выдаче; «последний ключ» — купленный последним из неистёкших и неотменённых; такого нет — дни ждут следующего ключа; возврат заказа приглашённого бонус не отменяет | [D-025](decisions/D-025-referral-days.md); [04-billing.md](04-billing.md), раздел 11 |
|
||||||
|
|
||||||
### 4.2 Открытые
|
### 4.2 Открытые
|
||||||
@@ -69,10 +101,9 @@
|
|||||||
|
|
||||||
| № | Вопрос | Предложение | Нужно к этапу |
|
| № | Вопрос | Предложение | Нужно к этапу |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| Q-10 | Имена Telegram-ботов: 2 основных, 2 поддержки, тестовые | — | 3 |
|
| Q-10 | Имена Telegram-ботов: 2 основных, 2 поддержки, тестовые | — | 2a, 3e |
|
||||||
| Q-11 | Оплата в Telegram: Stars, внешняя страница или только с баланса | — | 3 |
|
| Q-11 | Оплата в Telegram: Stars, внешняя страница или только с баланса | До этапа 4a — демо-оплата и баланс | 2a, 4a |
|
||||||
| Q-12 | RUB-процессинг (KZ, TR) и криптопроцессинг: какие провайдеры | — | 4 |
|
| Q-13 | Юрлицо для юридических текстов | Пока заглушки | 3b, 3h |
|
||||||
| Q-13 | Юрлицо для юридических текстов | Пока заглушки | 1h |
|
| Q-14 | Куда складывать бэкапы prod-базы | — | 3h |
|
||||||
| Q-14 | Куда складывать бэкапы prod-базы | — | 1h |
|
| Q-17 | Нужны ли разные аккаунты одного провайдера для разных брендов | Пока нет. Если понадобятся — платёжной системе добавим поле «только для сайтов» | 3b, 4b |
|
||||||
| Q-17 | Нужны ли разные аккаунты одного провайдера для разных брендов | Пока нет. Если понадобятся — платёжной системе добавим поле «только для сайтов» | 4 |
|
| Q-18 | Кто запускает выкладку в prod | Пользователь одной командой; по желанию — sudo-правило, разрешающее vx_dev запускать только команду выкладки от имени vx_prod | 3h |
|
||||||
| Q-18 | Кто запускает выкладку в prod | Пользователь одной командой; по желанию — sudo-правило, разрешающее vx_dev запускать только команду выкладки от имени vx_prod | 1h |
|
|
||||||
+15
-13
@@ -30,8 +30,8 @@
|
|||||||
|
|
||||||
1. Сайт: главная, цены, локации, поддержка, юридические страницы.
|
1. Сайт: главная, цены, локации, поддержка, юридические страницы.
|
||||||
2. Веб-кабинет, в том числе оформление заказа (оформление живёт на my.*, а не на сайте).
|
2. Веб-кабинет, в том числе оформление заказа (оформление живёт на my.*, а не на сайте).
|
||||||
3. MiniApp в Telegram — этап 3.
|
3. MiniApp в Telegram — этап 2a.
|
||||||
4. Два Telegram-бота: основной (команды, MiniApp, уведомления) и бот поддержки, подключённый к Chatwoot. Этапы 2–3.
|
4. Два Telegram-бота: основной (команды, MiniApp, уведомления) и бот поддержки, подключённый к Chatwoot. Этапы 2b и 3e.
|
||||||
|
|
||||||
## 4. Термины
|
## 4. Термины
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
## 5. Dedicated (Вейликс)
|
## 5. Dedicated (Вейликс)
|
||||||
|
|
||||||
1. Ключ — это индивидуальный IP в выбранной стране. Страна выбирается при покупке и не меняется никогда. Нужна другая страна — пользователь покупает новый ключ в другой локации и отключает автопродление старого. Отдельного функционала смены страны нет.
|
1. Ключ — это индивидуальный IP в выбранной стране: выделенный адрес на общем сервере, а не отдельный сервер. Страна выбирается при покупке и не меняется никогда. Нужна другая страна — пользователь покупает новый ключ в другой локации и отключает автопродление старого. Отдельного функционала смены страны нет.
|
||||||
2. В каждый ключ входит выделенный RU-адрес: работает и как прямое соединение, и как мост в обе стороны.
|
2. В каждый ключ входит выделенный RU-адрес: работает и как прямое соединение, и как мост в обе стороны.
|
||||||
3. До 5 устройств на ключ (поле тарифа), все с одним IP. WireGuard — по конфигу на устройство. Xray — ссылка для Happ (обычная или зашифрованная crypt-ссылка Happ, которая скрывает адрес подписки).
|
3. До 5 устройств на ключ (поле тарифа), все с одним IP. WireGuard — по конфигу на устройство. Xray — ссылка для Happ (обычная или зашифрованная crypt-ссылка Happ, которая скрывает адрес подписки).
|
||||||
4. Тариф — ценовой уровень со своим набором стран:
|
4. Тариф — ценовой уровень со своим набором стран:
|
||||||
@@ -58,18 +58,19 @@
|
|||||||
| Дальние локации | AU, BR | 9 900 ₽ | 4 999 ₽ | $99 / $49 |
|
| Дальние локации | AU, BR | 9 900 ₽ | 4 999 ₽ | $99 / $49 |
|
||||||
|
|
||||||
5. Первый месяц дороже, потому что включает подготовку сервера: выделение адреса, настройку протоколов и маршрутизации. Период — месяц.
|
5. Первый месяц дороже, потому что включает подготовку сервера: выделение адреса, настройку протоколов и маршрутизации. Период — месяц.
|
||||||
6. Статусы локаций: «Серверы в наличии» и «Установим за 24 часа». Оплаченный период начинается с момента выдачи ключа. На этапе 1 ключи выдаёт администратор вручную, поэтому так работает для обоих статусов.
|
6. Статусы локаций: «Серверы в наличии» и «Установим за 24 часа». Оплаченный период начинается с момента выдачи ключа. Ключ выдаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)): администратор вручную, демо-эмулятор (этап 1f) или API (этап 3g).
|
||||||
7. Каждый ключ продлевается независимо, в свою дату.
|
7. Каждый ключ продлевается независимо, в свою дату.
|
||||||
|
|
||||||
## 6. Mass (ВейликсВПН)
|
## 6. Mass (ВейликсВПН)
|
||||||
|
|
||||||
1. Ключ включает все страны тарифа. Страна при покупке не выбирается: список стран на сайте только показывает, что входит в ключ.
|
1. Ключ включает все страны тарифа. Страна при покупке не выбирается: список стран на сайте только показывает, что входит в ключ.
|
||||||
2. Happ — одна ссылка со всеми странами. WireGuard — пользователь может получить конфиги любой страны тарифа. На этапе 1 это конфиги, которые добавил администратор, по странам; нужна другая страна — через поддержку. Автоматически — на этапе 5.
|
2. Happ — одна ссылка со всеми странами. WireGuard — пользователь может получить конфиги любой страны тарифа: их создаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)).
|
||||||
3. Тарифы: «Месяц» 699 ₽ и «Год» 6 990 ₽ («582 ₽ в месяц, экономия 1 398 ₽»). Платы за подключение и доплат за страну нет: первый период стоит столько же, сколько продление.
|
3. Тарифы: «Месяц» 699 ₽ и «Год» 6 990 ₽ («582 ₽ в месяц, экономия 1 398 ₽»). Платы за подключение и доплат за страну нет: первый период стоит столько же, сколько продление.
|
||||||
4. До 5 устройств на ключ (поле тарифа).
|
4. До 5 устройств на ключ (поле тарифа).
|
||||||
5. Статусы локаций: «Включено» и «Скоро». Локации «Скоро» показываются, но не работают.
|
5. Статусы локаций: «Включено» и «Скоро». Локации «Скоро» показываются, но не работают.
|
||||||
6. В кабинете — «Список ключей», как у dedicated; внутри ключа ссылка Xray и конфиги WG. Формулировки «текущая/запасная локация» из макета не используем.
|
6. В кабинете — «Список ключей», как у dedicated; внутри ключа ссылка Xray и конфиги WG. Формулировки «текущая/запасная локация» из макета не используем.
|
||||||
7. Цены в USD (в макете их нет, решение Q-02): «Месяц» $6.99, «Год» $69.90.
|
7. Цены в USD (в макете их нет, решение Q-02): «Месяц» $6.99, «Год» $69.90.
|
||||||
|
8. В каждый ключ входит RU-адрес, как у dedicated; страной тарифа он не считается ([D-031](decisions/D-031-mass-ru-address.md)).
|
||||||
|
|
||||||
## 7. Локации из макета
|
## 7. Локации из макета
|
||||||
|
|
||||||
@@ -108,21 +109,22 @@
|
|||||||
| AU | Австралия | Сидней | 24 часа | дальние |
|
| AU | Австралия | Сидней | 24 часа | дальние |
|
||||||
| BR | Бразилия | Сан-Паулу | 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. Пользователи
|
## 8. Пользователи
|
||||||
|
|
||||||
1. Аккаунты раздельные по сайтам: один email на veilix.app и на veilixvpn.com — два разных пользователя.
|
1. Аккаунты раздельные по сайтам: один email на veilix.app и на veilixvpn.com — два разных пользователя.
|
||||||
2. Регистрация и вход — одно поле email и одноразовый код. Отдельной регистрации нет.
|
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. Деньги
|
## 9. Деньги
|
||||||
|
|
||||||
1. У пользователя есть счёт (баланс) в валюте аккаунта.
|
1. У пользователя есть счёт (баланс) в валюте аккаунта.
|
||||||
2. Валюты — отдельный справочник: RUB и USD. Переключатель валюты не зависит от языка: из России часто заходят через VPN, поэтому страна по IP для выбора валюты не годится. По умолчанию валюта зависит от языка: ru → RUB, остальные → USD.
|
2. Валюты — отдельный справочник: RUB и USD. Переключатель валюты не зависит от языка: из России часто заходят через VPN, поэтому страна по IP для выбора валюты не годится. По умолчанию валюта зависит от языка: ru → RUB, остальные → USD.
|
||||||
3. Платёжные системы привязаны только к валютам. Где система доступна, следует из цепочки: валюты → домены, на которых они включены → сайты:
|
3. Платёжные системы привязаны только к валютам. Где система доступна, следует из цепочки: валюты → домены, на которых они включены → сайты:
|
||||||
a. RUB — процессинги, принимающие карты РФ (вероятно, из Казахстана и Турции), без автосписаний. ЮKassa — опционально, только для пополнений;
|
a. RUB — ЮKassa, только пополнения, без автосписаний (этап 3b);
|
||||||
b. USD — Stripe (карты, сохранение карты, автосписания) и криптовалюта.
|
b. USD — Stripe (карты, сохранение карты, автосписания) и криптовалюта (этап 4b);
|
||||||
|
c. для проверок — платёжная система «Демо», видна только с разрешённых IP ([D-027](decisions/D-027-demo-payments.md)).
|
||||||
4. Карта привязывается к аккаунту, а не к ключу (Stripe). Отвязать карту можно в аккаунте.
|
4. Карта привязывается к аккаунту, а не к ключу (Stripe). Отвязать карту можно в аккаунте.
|
||||||
5. Продление: у каждого ключа галочка автопродления и кнопка «Продлить сейчас». Сначала списывается баланс, нехватка — с карты.
|
5. Продление: у каждого ключа галочка автопродления и кнопка «Продлить сейчас». Сначала списывается баланс, нехватка — с карты.
|
||||||
6. Не хватило денег: льготный период 3 дня (ключ работает), затем ключ истекает. Напоминание за 3 дня до окончания.
|
6. Не хватило денег: льготный период 3 дня (ключ работает), затем ключ истекает. Напоминание за 3 дня до окончания.
|
||||||
@@ -143,10 +145,10 @@
|
|||||||
## 11. Поддержка и заявки
|
## 11. Поддержка и заявки
|
||||||
|
|
||||||
1. Страница поддержки: Telegram (бот поддержки бренда) и email, FAQ по разделам, форма связи.
|
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, коротко о задаче.
|
3. Заявка «Нужны индивидуальные условия» (dedicated) и «Нужны особые условия» (mass): имя, email, Telegram, WhatsApp, коротко о задаче.
|
||||||
4. Заявки и обращения сохраняются в Payload и приходят на почту поддержки (этап 1), затем уходят в Twenty CRM и Chatwoot (этап 2).
|
4. До этапов 3d и 3e формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)). Затем заявки уходят в Twenty CRM (3d), обращения — в Chatwoot (3e).
|
||||||
5. Часы поддержки из макета: с 10 до 20 по московскому времени в рабочие дни.
|
5. Часы поддержки: с 10 до 20 по московскому времени в рабочие дни. Сроки ответа на сайте не обещаем.
|
||||||
|
|
||||||
## 12. Языки
|
## 12. Языки
|
||||||
|
|
||||||
@@ -154,4 +156,4 @@ en (по умолчанию, без префикса в URL), ru, de, fr, es. П
|
|||||||
|
|
||||||
## 13. Юридические страницы
|
## 13. Юридические страницы
|
||||||
|
|
||||||
Условия использования, политика конфиденциальности, политика возвратов, политика cookies. Черновики на RU и EN готовятся в этапе 1b, с заглушками вместо данных юрлица (Q-13). Это черновики, не юридическая консультация: перед запуском — показать юристу. Stripe при подключении проверяет эти страницы.
|
Условия использования, политика конфиденциальности, политика возвратов, политика cookies. Черновики на 5 языках готовятся в этапе 1b, с заглушками вместо данных юрлица (Q-13). В политике конфиденциальности: VPN-серверы не ведут журналов ([10-security.md](10-security.md), раздел 6). Это черновики, не юридическая консультация: перед запуском — показать юристу. Stripe при подключении проверяет эти страницы.
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
| Vitest | 5.x | модульные тесты |
|
| Vitest | 5.x | модульные тесты |
|
||||||
| next-intl | 4.x | переводы интерфейса, префиксы языков в URL |
|
| next-intl | 4.x | переводы интерфейса, префиксы языков в URL |
|
||||||
| Nodemailer | через `@payloadcms/email-nodemailer` | транспорты SMTP, sendmail, «только журнал» |
|
| Nodemailer | через `@payloadcms/email-nodemailer` | транспорты SMTP, sendmail, «только журнал» |
|
||||||
| ALTCHA | 3.x | капча без третьих сторон |
|
| ALTCHA | 3.x | капча без третьих сторон, этап 3a |
|
||||||
| grammY | 1.x | Telegram-боты, этап 3 |
|
| grammY | 1.x | Telegram-боты, этапы 2a–2c |
|
||||||
| Stripe SDK | актуальный | этап 4 |
|
| 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 выключена.
|
Точные версии закреплены в `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)/m/[host]/[locale]/[currency]/(site)/… — маркетинговые сайты
|
||||||
(front)/c/[host]/[locale]/(shell)/… — кабинет с навигацией
|
(front)/c/[host]/[locale]/(shell)/… — кабинет с навигацией
|
||||||
(front)/c/[host]/[locale]/(plain)/… — вход и оформление заказа
|
(front)/c/[host]/[locale]/(plain)/… — вход и оформление заказа
|
||||||
(front)/t/[host]/… — MiniApp (этап 3)
|
(front)/t/[host]/… — MiniApp (этап 2a)
|
||||||
(front)/context.ts — домен, язык и валюта страницы, данные оболочек
|
(front)/context.ts — домен, язык и валюта страницы, данные оболочек
|
||||||
svc/… — свои эндпоинты: health, internal/domains; дальше ALTCHA, вебхуки
|
svc/… — свои эндпоинты: health, internal/domains; дальше ALTCHA, вебхуки
|
||||||
payload/
|
payload/
|
||||||
collections/ access/ fields/ hooks/ components/
|
collections/ access/ fields/ hooks/ components/
|
||||||
core/ — бизнес-логика без привязки к UI
|
core/ — бизнес-логика без привязки к UI
|
||||||
sites.ts domains/ routing/ currencies/ payments/ — этап 1a
|
sites.ts domains/ routing/ currencies/ payments/ — этап 1a
|
||||||
billing/ keys/ auth/ referral/ email/ geo/ — следующие этапы
|
billing/ keys/ provisioning/ auth/ referral/ email/ geo/ — следующие этапы
|
||||||
brands/
|
brands/
|
||||||
dedicated/ mass/ — различия брендов; страницы и компоненты — с этапа 1b
|
dedicated/ mass/ — различия брендов; страницы и компоненты — с этапа 1b
|
||||||
ui/ — общие компоненты: оболочки сайта и кабинета, переключатели, тема, логотип, иконки
|
ui/ — общие компоненты: оболочки сайта и кабинета, переключатели, тема, логотип, иконки
|
||||||
@@ -67,7 +67,7 @@ scripts/ — служебные скрипты (очистк
|
|||||||
|
|
||||||
Корневые layout сайта и кабинета дают только документ: `<html>` с `lang`, `data-site` и скриптом темы. Шапка, подвал и навигация — во вложенных группах `(site)`, `(shell)` и `(plain)`.
|
Корневые layout сайта и кабинета дают только документ: `<html>` с `lang`, `data-site` и скриптом темы. Шапка, подвал и навигация — во вложенных группах `(site)`, `(shell)` и `(plain)`.
|
||||||
|
|
||||||
Бизнес-логика живёт в `core/` и вызывается одинаково из хуков Payload, server actions, вебхуков, фоновых задач и (на этапе 3) бота.
|
Бизнес-логика живёт в `core/` и вызывается одинаково из хуков Payload, server actions, вебхуков, фоновых задач и (с этапа 2b) бота.
|
||||||
|
|
||||||
## 4. Окружения
|
## 4. Окружения
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ scripts/ — служебные скрипты (очистк
|
|||||||
|
|
||||||
## 5. Выкладка в prod
|
## 5. Выкладка в prod
|
||||||
|
|
||||||
1. В dev: изменения схемы оформляются миграцией (`payload migrate:create`), коммит, push в Gitea, тег релиза. До первой выкладки (этап 1h) миграции не накапливаем: перед ней создаём одну начальную по итоговой схеме. Механизм проверен на этапе 1a: миграция, применённая к пустой схеме, создаёт те же таблицы, что push в dev.
|
1. В dev: изменения схемы оформляются миграцией (`payload migrate:create`), коммит, push в Gitea, тег релиза. До первой выкладки (этап 3h) миграции не накапливаем: перед ней создаём одну начальную по итоговой схеме. Механизм проверен на этапе 1a: миграция, применённая к пустой схеме, создаёт те же таблицы, что push в dev.
|
||||||
2. Выкладка — команда `deploy <тег>` пользователя vx_prod, появится на этапе 1h. Запускает её пользователь; по желанию — sudo-правило, разрешающее vx_dev запускать только эту команду (Q-18). Шаги:
|
2. Выкладка — команда `deploy <тег>` пользователя vx_prod, появится на этапе 3h. Запускает её пользователь; по желанию — sudo-правило, разрешающее vx_dev запускать только эту команду (Q-18). Шаги:
|
||||||
a. взять тег из Gitea (у vx_prod ключ только на чтение) в новую папку `releases/<дата-тег>`;
|
a. взять тег из Gitea (у vx_prod ключ только на чтение) в новую папку `releases/<дата-тег>`;
|
||||||
b. `pnpm install --frozen-lockfile` и `pnpm build`; ссылки на `shared/.env` и `shared/media`;
|
b. `pnpm install --frozen-lockfile` и `pnpm build`; ссылки на `shared/.env` и `shared/media`;
|
||||||
c. применить миграции к `veilix_prod`;
|
c. применить миграции к `veilix_prod`;
|
||||||
@@ -102,7 +102,7 @@ scripts/ — служебные скрипты (очистк
|
|||||||
## 6. Рендеринг и кэширование
|
## 6. Рендеринг и кэширование
|
||||||
|
|
||||||
1. Маркетинговые страницы собираются статически в вариантах «домен × язык × валюта» при первом запросе (ISR) и кэшируются. Proxy выбирает вариант по префиксу языка и cookie валюты.
|
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. При оформлении заказа наличие и цена проверяются заново на сервере. Устаревшая страница не может продать то, чего нет.
|
3. При оформлении заказа наличие и цена проверяются заново на сервере. Устаревшая страница не может продать то, чего нет.
|
||||||
4. Кабинет рендерится на сервере (SSR) для каждого запроса, без кэша.
|
4. Кабинет рендерится на сервере (SSR) для каждого запроса, без кэша.
|
||||||
5. Маркетинговые домены не ставят cookies, кроме выбора языка, валюты и темы.
|
5. Маркетинговые домены не ставят cookies, кроме выбора языка, валюты и темы.
|
||||||
|
|||||||
+16
-12
@@ -55,7 +55,9 @@ erDiagram
|
|||||||
| locales | multi-select из языков конфига | языки контента сайта; en обязателен; домены показывают часть этих языков ([D-023](decisions/D-023-site-locales.md)) |
|
| locales | multi-select из языков конфига | языки контента сайта; en обязателен; домены показывают часть этих языков ([D-023](decisions/D-023-site-locales.md)) |
|
||||||
| supportEmail | email | почта поддержки: `help@veilix.app`, `help@veilixvpn.com` |
|
| supportEmail | email | почта поддержки: `help@veilix.app`, `help@veilixvpn.com` |
|
||||||
| emailFrom | group: name, address | отправитель писем, напр. «Вейликс» <no-reply@veilix.app> |
|
| 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 | |
|
| referralEnabled | checkbox | |
|
||||||
| referralBonusDays | number, по умолчанию 30 | бонус «месяц в подарок»: дни срока ключа обоим ([D-025](decisions/D-025-referral-days.md)) |
|
| referralBonusDays | number, по умолчанию 30 | бонус «месяц в подарок»: дни срока ключа обоим ([D-025](decisions/D-025-referral-days.md)) |
|
||||||
| topupPresets | array: currency, amounts[] | суммы пополнения в кабинете ([04-billing.md](04-billing.md), раздел 4) |
|
| topupPresets | array: currency, amounts[] | суммы пополнения в кабинете ([04-billing.md](04-billing.md), раздел 4) |
|
||||||
@@ -63,9 +65,10 @@ erDiagram
|
|||||||
| reminderDays | number, по умолчанию 3 | за сколько дней напоминать |
|
| reminderDays | number, по умолчанию 3 | за сколько дней напоминать |
|
||||||
| renewalLeadHours | number, по умолчанию 24 | за сколько часов до окончания пробовать продлить |
|
| renewalLeadHours | number, по умолчанию 24 | за сколько часов до окончания пробовать продлить |
|
||||||
| expiringBadgeDays | number, по умолчанию 7 | когда показывать «Истекает» |
|
| 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 | значения по умолчанию |
|
| 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` — Домены (сайт)
|
### 3.2 `domains` — Домены (сайт)
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ erDiagram
|
|||||||
| localeCurrency | array: locale, currency | валюта по умолчанию для языка: ru → RUB |
|
| localeCurrency | array: locale, currency | валюта по умолчанию для языка: ru → RUB |
|
||||||
| isPrimary | checkbox | основной домен этого типа (у сайта один на каждый тип); используется в ссылках и sitemap |
|
| isPrimary | checkbox | основной домен этого типа (у сайта один на каждый тип); используется в ссылках и sitemap |
|
||||||
| indexable | checkbox | разрешена ли индексация (для кабинета и MiniApp — нет) |
|
| indexable | checkbox | разрешена ли индексация (для кабинета и MiniApp — нет) |
|
||||||
| umamiWebsiteId | text | этап 1h |
|
| umamiWebsiteId | text | этап 3f |
|
||||||
| active | checkbox | |
|
| active | checkbox | |
|
||||||
|
|
||||||
Язык и валюта по умолчанию должны входить в списки домена, язык в правилах «язык → валюта» не повторяется — это проверяется при сохранении.
|
Язык и валюта по умолчанию должны входить в списки домена, язык в правилах «язык → валюта» не повторяется — это проверяется при сохранении.
|
||||||
@@ -102,13 +105,14 @@ erDiagram
|
|||||||
| Поле | Тип | Описание |
|
| Поле | Тип | Описание |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| name | text | название в админке |
|
| 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) | что видит пользователь: «Банковская карта», «Карта МИР», «СБП», «Криптовалюта» |
|
| title | text (L) | что видит пользователь: «Банковская карта», «Карта МИР», «СБП», «Криптовалюта» |
|
||||||
| description | text (L) | подсказка: «USDT, BTC, ETH, курс фиксируется на 15 минут» |
|
| description | text (L) | подсказка: «USDT, BTC, ETH, курс фиксируется на 15 минут» |
|
||||||
| icon | upload | |
|
| icon | upload | |
|
||||||
| currencies | multi-select валют | в каких валютах доступна |
|
| currencies | multi-select валют | в каких валютах доступна |
|
||||||
| purposes | multi-select `order` \| `topup` | оплата заказа, пополнение |
|
| purposes | multi-select `order` \| `topup` | оплата заказа, пополнение |
|
||||||
| visibleToCustomers | checkbox | у `manual` всегда выключено (проверяется при сохранении): ей пользуются только администраторы |
|
| visibleToCustomers | checkbox | у `manual` всегда выключено (проверяется при сохранении): ей пользуются только администраторы |
|
||||||
|
| allowedIps | text | для `demo`: IP и подсети, с которых система видна; пусто — не видна никому |
|
||||||
| mode | select `test` \| `live` | |
|
| mode | select `test` \| `live` | |
|
||||||
| limits | array: currency, min, max | |
|
| limits | array: currency, min, max | |
|
||||||
| capabilities | только чтение, из адаптера | `recurring`, `refunds`, `saveMethod`; объявлены в `src/core/payments/adapters.ts`, в базе не хранятся |
|
| capabilities | только чтение, из адаптера | `recurring`, `refunds`, `saveMethod`; объявлены в `src/core/payments/adapters.ts`, в базе не хранятся |
|
||||||
@@ -133,7 +137,7 @@ erDiagram
|
|||||||
| city | text (L) | |
|
| city | text (L) | |
|
||||||
| lat, lng | number | точка города на карте |
|
| lat, lng | number | точка города на карте |
|
||||||
| status | select `available` \| `on_demand` \| `soon` | dedicated: «Серверы в наличии» / «Установим за 24 часа»; mass: «Включено» / «Скоро». Чужой для бренда статус не сохранится |
|
| status | select `available` \| `on_demand` \| `soon` | dedicated: «Серверы в наличии» / «Установим за 24 часа»; mass: «Включено» / «Скоро». Чужой для бренда статус не сохранится |
|
||||||
| freeServers | number, необязательное | счётчик (решение о показе — этап 1b) |
|
| freeServers | number, необязательное | счётчик; на сайте показывается, если заполнен ([D-032](decisions/D-032-free-servers.md)) |
|
||||||
| visible, sort | | |
|
| visible, sort | | |
|
||||||
|
|
||||||
### 3.7 `tags` — Теги (общие)
|
### 3.7 `tags` — Теги (общие)
|
||||||
@@ -178,8 +182,8 @@ erDiagram
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| email | email, null | уникален в пределах сайта, хранится в нижнем регистре |
|
| email | email, null | уникален в пределах сайта, хранится в нижнем регистре |
|
||||||
| emailVerifiedAt | date | |
|
| emailVerifiedAt | date | |
|
||||||
| telegramId | text, null | уникален в пределах сайта (этап 3) |
|
| telegramId | text, null | уникален в пределах сайта (этап 2a) |
|
||||||
| telegramUsername, telegramName | text | этап 3 |
|
| telegramUsername, telegramName | text | этап 2a |
|
||||||
| locale | select | язык писем и бота |
|
| locale | select | язык писем и бота |
|
||||||
| currency | select | валюта аккаунта ([04-billing.md](04-billing.md), раздел 2) |
|
| currency | select | валюта аккаунта ([04-billing.md](04-billing.md), раздел 2) |
|
||||||
| balance | number, только чтение | кэш суммы движений по счёту |
|
| balance | number, только чтение | кэш суммы движений по счёту |
|
||||||
@@ -229,7 +233,7 @@ erDiagram
|
|||||||
| title | text | «Устройство 1», «Ноутбук» |
|
| title | text | «Устройство 1», «Ноутбук» |
|
||||||
| deviceSlot | number | номер устройства для WG/AWG |
|
| deviceSlot | number | номер устройства для WG/AWG |
|
||||||
| country | relationship → countries | для WG у mass — страна конфига; для RU-адреса — RU |
|
| 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 |
|
| payload | text, зашифрованное | содержимое конфига или URL |
|
||||||
| fileName | text | имя файла при скачивании |
|
| fileName | text | имя файла при скачивании |
|
||||||
| status | select `active` \| `revoked` | |
|
| status | select `active` \| `revoked` | |
|
||||||
@@ -242,7 +246,7 @@ QR-коды строятся на лету из `payload`, не хранятся
|
|||||||
|
|
||||||
| Статус | Значение |
|
| Статус | Значение |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `provisioning` | оплачен, готовится. Срок ещё не идёт. На этапе 1 так создаются все ключи: подключения добавляет администратор |
|
| `provisioning` | оплачен, готовится. Срок ещё не идёт. Подключения создаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)) или администратор |
|
||||||
| `active` | работает, срок идёт с `activatedAt` |
|
| `active` | работает, срок идёт с `activatedAt` |
|
||||||
| `grace` | срок истёк, оплата не прошла, ключ ещё работает до `graceUntil` |
|
| `grace` | срок истёк, оплата не прошла, ключ ещё работает до `graceUntil` |
|
||||||
| `expired` | истёк, подключения отключаются |
|
| `expired` | истёк, подключения отключаются |
|
||||||
@@ -319,7 +323,7 @@ QR-коды строятся на лету из `payload`, не хранятся
|
|||||||
| customer | relationship | |
|
| customer | relationship | |
|
||||||
| currency | | валюта аккаунта |
|
| currency | | валюта аккаунта |
|
||||||
| amount | number со знаком | `+` зачисление, `−` списание |
|
| 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 | источник записи |
|
| payment, order, key | relationship | источник записи |
|
||||||
| balanceAfter | number | баланс после записи |
|
| balanceAfter | number | баланс после записи |
|
||||||
| comment | text | обязателен для `adjustment` |
|
| comment | text | обязателен для `adjustment` |
|
||||||
@@ -339,7 +343,7 @@ QR-коды строятся на лету из `payload`, не хранятся
|
|||||||
|
|
||||||
### 7.1 `pages` — Страницы (сайт)
|
### 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` — Вопросы и ответы (сайт)
|
### 7.2 `faq` — Вопросы и ответы (сайт)
|
||||||
|
|
||||||
@@ -353,7 +357,7 @@ QR-коды строятся на лету из `payload`, не хранятся
|
|||||||
|
|
||||||
### 7.4 `leads` — Заявки (сайт)
|
### 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` — Файлы
|
### 7.5 `media` — Файлы
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -22,16 +22,16 @@
|
|||||||
4. Создаётся заказ `pending`: `new_key`, сумма — `firstPeriodAmount`, действует 24 часа. Если у пользователя уже есть такой же неоплаченный заказ, используется он.
|
4. Создаётся заказ `pending`: `new_key`, сумма — `firstPeriodAmount`, действует 24 часа. Если у пользователя уже есть такой же неоплаченный заказ, используется он.
|
||||||
5. Шаг «Оплата»: сводка заказа, согласие с условиями (обязательная галочка со ссылками на юридические страницы) и способ оплаты.
|
5. Шаг «Оплата»: сводка заказа, согласие с условиями (обязательная галочка со ссылками на юридические страницы) и способ оплаты.
|
||||||
a. Баланса хватает — кнопка «Оплатить с баланса», заказ оплачивается сразу.
|
a. Баланса хватает — кнопка «Оплатить с баланса», заказ оплачивается сразу.
|
||||||
b. Баланса не хватает — список платёжных систем: активные, в валюте аккаунта, с назначением `order`, видимые пользователю. Создаётся платёж `pending` на сумму «стоимость минус баланс» (показываем: «С баланса спишется X, к оплате Y»), дальше — страница или виджет провайдера (этап 4).
|
b. Баланса не хватает — список платёжных систем: активные, в валюте аккаунта, с назначением `order`, видимые пользователю. Создаётся платёж `pending` на сумму «стоимость минус баланс» (показываем: «С баланса спишется X, к оплате Y»), дальше — страница или виджет провайдера: демо-оплата (этап 1e), Stripe (4b).
|
||||||
6. На этапе 1 видимых платёжных систем нет. Заказ создаётся, пользователь видит «Заказ создан, ожидает оплаты». Оплату проводит администратор ручным платежом, либо пользователь оплачивает с баланса, который пополнил администратор. Так проверяется весь сценарий без эквайринга.
|
6. Если видимых платёжных систем нет, заказ создаётся, пользователь видит «Заказ создан, ожидает оплаты». Оплату проводит администратор ручным платежом, либо пользователь оплачивает с баланса, который пополнил администратор. В фазе 1 «Демо» видна только с разрешённых IP ([D-027](decisions/D-027-demo-payments.md)).
|
||||||
7. После оплаты: заказ `paid`, ключ создаётся в статусе `provisioning`, письма `order_paid` пользователю и `admin_provisioning_needed` на почту поддержки.
|
7. После оплаты: заказ `paid`, ключ создаётся в статусе `provisioning`, письма `order_paid` пользователю и `admin_provisioning_needed` на почту поддержки. Дальше ключ выдаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)).
|
||||||
|
|
||||||
## 4. Пополнение баланса
|
## 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).
|
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`.
|
2. После зачисления — письмо `topup_succeeded`.
|
||||||
3. После любого пополнения система сама оплачивает с баланса неоплаченные заказы на продление этого пользователя, начиная со старого. Неоплаченные заказы на новые ключи сама не оплачивает.
|
3. После любого пополнения система сама оплачивает с баланса неоплаченные заказы на продление этого пользователя, начиная со старого. Неоплаченные заказы на новые ключи сама не оплачивает.
|
||||||
4. Криптовалюта (этап 4): счёт в монете, курс фиксируется на 15 минут, зачисление в валюте аккаунта после подтверждения сети.
|
4. Криптовалюта (этап 4b): счёт в монете, курс фиксируется на 15 минут, зачисление в валюте аккаунта после подтверждения сети.
|
||||||
|
|
||||||
## 5. Проведение платежа: `processPayment`
|
## 5. Проведение платежа: `processPayment`
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
1. Найти или создать заказ `renewal`: `renewalFor = expiresAt`, сумма — `renewalAmount` ключа.
|
1. Найти или создать заказ `renewal`: `renewalFor = expiresAt`, сумма — `renewalAmount` ключа.
|
||||||
2. Баланса хватает — списание, заказ `paid`, `expiresAt = renewalFor + period`, статус `active`, письмо `renewal_succeeded`.
|
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) или кнопка «Продлить сейчас».
|
4. Нет ни денег, ни карты — заказ ждёт оплаты. Его оплатит пополнение (раздел 4.3) или кнопка «Продлить сейчас».
|
||||||
|
|
||||||
### 6.2 «Продлить сейчас»
|
### 6.2 «Продлить сейчас»
|
||||||
@@ -82,13 +82,13 @@
|
|||||||
|
|
||||||
1. `active`, срок истёк, продление не оплачено → `grace`, `graceUntil = expiresAt + graceDays`, письмо `grace_started`. Ключ работает.
|
1. `active`, срок истёк, продление не оплачено → `grace`, `graceUntil = expiresAt + graceDays`, письмо `grace_started`. Ключ работает.
|
||||||
2. Продление оплачено в льготный период → `active`, новый срок считается от старого `expiresAt`: бесплатных дней нет.
|
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. Правило одинаковое для ключей с автопродлением и без. Без автопродления пользователь сам решает, продлевать ли в льготный период.
|
4. Правило одинаковое для ключей с автопродлением и без. Без автопродления пользователь сам решает, продлевать ли в льготный период.
|
||||||
5. Истёкший ключ не продлевается: покупается новый. Администратор может вернуть ключ вручную.
|
5. Истёкший ключ не продлевается: покупается новый. Администратор может вернуть ключ вручную.
|
||||||
|
|
||||||
## 8. Выдача ключа
|
## 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`.
|
2. Нужно хотя бы одно активное подключение. Затем: `active`, `activatedAt = сейчас`, `expiresAt = сейчас + период` плюс дни продлений без оплаты, которые ждали выдачи (раздел 6.4), письмо `key_ready`.
|
||||||
3. Список «Очередь выдачи» в админке: ключи `provisioning` по времени создания; локации `on_demand` помечены сроком «24 часа».
|
3. Список «Очередь выдачи» в админке: ключи `provisioning` по времени создания; локации `on_demand` помечены сроком «24 часа».
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@
|
|||||||
## 10. Возвраты
|
## 10. Возвраты
|
||||||
|
|
||||||
1. Политика: если сервер не заработал по нашей вине — полностью в течение первых 7 дней; если пользователь передумал — остаток неиспользованного периода. Сумму считает администратор, система подсказывает остаток пропорционально дням.
|
1. Политика: если сервер не заработал по нашей вине — полностью в течение первых 7 дней; если пользователь передумал — остаток неиспользованного периода. Сумму считает администратор, система подсказывает остаток пропорционально дням.
|
||||||
2. Этап 1 — только возврат на баланс.
|
2. До этапа 4b — только возврат на баланс.
|
||||||
3. Этап 4 — возврат на исходный способ оплаты, если провайдер умеет. Запись `refund` (+) на баланс по заказу, затем `payout` (−) — деньги уходят на карту. Итог: баланс не меняется, деньги у пользователя на карте.
|
3. Этап 4b — возврат на исходный способ оплаты, если провайдер умеет. Запись `refund` (+) на баланс по заказу, затем `payout` (−) — деньги уходят на карту. Итог: баланс не меняется, деньги у пользователя на карте.
|
||||||
|
|
||||||
## 11. Реферальное вознаграждение
|
## 11. Реферальное вознаграждение
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
| Возврат | `refund_issued` | |
|
| Возврат | `refund_issued` | |
|
||||||
| Администраторам | `admin_new_order`, `admin_provisioning_needed`, `admin_new_lead` | на почту поддержки сайта |
|
| Администраторам | `admin_new_order`, `admin_provisioning_needed`, `admin_new_lead` | на почту поддержки сайта |
|
||||||
|
|
||||||
С этапа 3 те же уведомления дублируются в основного бота, если Telegram привязан.
|
С этапа 2b те же уведомления дублируются в основного бота, если Telegram привязан.
|
||||||
|
|
||||||
## 13. Статусы
|
## 13. Статусы
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
### 2.1 Запрос кода
|
### 2.1 Запрос кода
|
||||||
|
|
||||||
1. Пользователь вводит email и проходит ALTCHA.
|
1. Пользователь вводит email и проходит ALTCHA (с этапа 3a).
|
||||||
2. Сервер нормализует email (обрезает пробелы, переводит в нижний регистр) и проверяет лимиты:
|
2. Сервер нормализует email (обрезает пробелы, переводит в нижний регистр) и проверяет лимиты:
|
||||||
a. по email — не чаще раза в 60 секунд и не больше 5 кодов в час;
|
a. по email — не чаще раза в 60 секунд и не больше 5 кодов в час;
|
||||||
b. по IP — не больше 20 запросов в час.
|
b. по IP — не больше 20 запросов в час.
|
||||||
@@ -51,14 +51,14 @@
|
|||||||
|
|
||||||
Шаг «Почта» на странице заказа — тот же вход по коду. После подтверждения пользователь остаётся на шаге «Оплата».
|
Шаг «Почта» на странице заказа — тот же вход по коду. После подтверждения пользователь остаётся на шаге «Оплата».
|
||||||
|
|
||||||
## 6. Telegram (этап 3)
|
## 6. Telegram (этапы 2a–2c)
|
||||||
|
|
||||||
### 6.1 Вход из MiniApp
|
### 6.1 Вход из MiniApp
|
||||||
|
|
||||||
1. MiniApp передаёт серверу `initData` от Telegram.
|
1. MiniApp передаёт серверу `initData` от Telegram.
|
||||||
2. Сервер проверяет подпись: HMAC-SHA256 с ключом `HMAC_SHA256("WebAppData", токен основного бота)`, `auth_date` не старше суток.
|
2. Сервер проверяет подпись: HMAC-SHA256 с ключом `HMAC_SHA256("WebAppData", токен основного бота)`, `auth_date` не старше суток.
|
||||||
3. Ищем пользователя (сайт, telegramId). Нет — создаём: `registeredVia = telegram`, язык — из `language_code` Telegram (если он среди включённых), валюта — по умолчанию домена.
|
3. Ищем пользователя (сайт, telegramId). Нет — создаём: `registeredVia = telegram`, язык — из `language_code` Telegram (если он среди включённых), валюта — по умолчанию домена.
|
||||||
4. Сессия `kind = miniapp`. Как её хранить (cookie внутри WebView Telegram или токен в памяти) — решаем на этапе 3.
|
4. Сессия `kind = miniapp`. Как её хранить (cookie внутри WebView Telegram или токен в памяти) — решаем на этапе 2a.
|
||||||
|
|
||||||
### 6.2 Привязка почты из Telegram
|
### 6.2 Привязка почты из Telegram
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
| `vx_ref` | хост кабинета | 60 дней | реферальный код |
|
| `vx_ref` | хост кабинета | 60 дней | реферальный код |
|
||||||
| `NEXT_LOCALE` | каждый хост | 1 год | выбранный язык |
|
| `NEXT_LOCALE` | каждый хост | 1 год | выбранный язык |
|
||||||
| `vx_currency` | хост сайта и кабинета | 1 год | выбранная валюта (у вошедшего — валюта аккаунта) |
|
| `vx_currency` | хост сайта и кабинета | 1 год | выбранная валюта (у вошедшего — валюта аккаунта) |
|
||||||
| `vx_consent` | хост сайта и кабинета | 1 год | согласие на cookies (этап 1h) |
|
| `vx_consent` | хост сайта и кабинета | 1 год | согласие на cookies (этап 3f) |
|
||||||
| `payload-token` | хост админки | сессия админки | вход администратора |
|
| `payload-token` | хост админки | сессия админки | вход администратора |
|
||||||
|
|
||||||
Тема (светлая, тёмная, как в системе) хранится в localStorage, как в макете, и применяется скриптом до отрисовки, без мигания.
|
Тема (светлая, тёмная, как в системе) хранится в localStorage, как в макете, и применяется скриптом до отрисовки, без мигания.
|
||||||
+4
-4
@@ -52,10 +52,10 @@
|
|||||||
|
|
||||||
## 7. Как переводим
|
## 7. Как переводим
|
||||||
|
|
||||||
1. Источник: русские тексты макетов и английские из словаря макета `design/handoff/project/i18n.js` (около 515 строк). Они ложатся в `ru.json` и `en.json` и в контент Payload.
|
1. Источник: русские тексты макетов и английские из словаря макета `design/handoff/project/i18n.js` (около 515 строк). Интерфейс ложится в `messages/*.json`, тексты страниц и остальной контент — в Payload ([D-029](decisions/D-029-pages-blocks.md)).
|
||||||
2. Немецкий, французский, испанский — машинный перевод LLM с глоссарием на этапе 1h. Вычитки носителями нет, поэтому глоссарий и контекст обязательны.
|
2. Немецкий, французский, испанский переводит Claude с глоссарием в каждом этапе, вместе с RU и EN ([D-033](decisions/D-033-translations.md)). Вычитки носителями нет, поэтому глоссарий и контекст обязательны. Финальная проверка — на публичном запуске (этап 3h).
|
||||||
3. В юридических текстах пункт: «При расхождениях между версиями действует английская».
|
3. В юридических текстах пункт: «При расхождениях между версиями действует английская».
|
||||||
4. Новая строка интерфейса: разработчик добавляет ключ в `en.json` и `ru.json`; de, fr, es переводятся пакетно перед выкладкой.
|
4. Новая строка интерфейса или контента сразу появляется на 5 языках.
|
||||||
|
|
||||||
## 8. Глоссарий
|
## 8. Глоссарий
|
||||||
|
|
||||||
@@ -76,4 +76,4 @@
|
|||||||
| реферальная программа | referral program | |
|
| реферальная программа | referral program | |
|
||||||
| установим за 24 часа | ready within 24 hours | статус локации dedicated |
|
| установим за 24 часа | ready within 24 hours | статус локации dedicated |
|
||||||
|
|
||||||
Колонки для de, fr, es добавляются на этапе 1h.
|
Колонки для de, fr, es добавляются на этапе 1b.
|
||||||
+12
-6
@@ -17,7 +17,7 @@
|
|||||||
| `Support` / `MassSupport` | `/support` | `/support` |
|
| `Support` / `MassSupport` | `/support` | `/support` |
|
||||||
| `Order` / `MassOrder` | my.veilix.app `/order` | my.veilixvpn.com `/order` |
|
| `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 |
|
| `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 — в стиле сайта.
|
Плюс страницы без макета: `/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`.
|
Общие для брендов: `--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. Шрифты, иконки, логотип
|
## 5. Шрифты, иконки, логотип
|
||||||
|
|
||||||
@@ -74,12 +74,13 @@
|
|||||||
1. В макете карта строится в браузере через d3 и topojson с загрузкой данных с CDN. В продукте SVG-карта рендерится на сервере при сборке: d3-geo, проекция Natural Earth, данные `world-atlas` (countries-110m) из npm.
|
1. В макете карта строится в браузере через d3 и topojson с загрузкой данных с CDN. В продукте SVG-карта рендерится на сервере при сборке: d3-geo, проекция Natural Earth, данные `world-atlas` (countries-110m) из npm.
|
||||||
2. В браузере — только интерактив: подсветка, всплывающая карточка, синхронизация с сеткой локаций.
|
2. В браузере — только интерактив: подсветка, всплывающая карточка, синхронизация с сеткой локаций.
|
||||||
3. На узком экране карта прокручивается горизонтально, как в макете.
|
3. На узком экране карта прокручивается горизонтально, как в макете.
|
||||||
|
4. Глобус в hero главной (`Main`, `MassMain`) — ортографическая проекция, тоже рисуется на сервере, без интерактива.
|
||||||
|
|
||||||
## 7. Решения по расхождениям в макетах
|
## 7. Решения по расхождениям в макетах
|
||||||
|
|
||||||
1. Устройств — 5, это поле тарифа. Цена продления dedicated — 2 499 ₽, цены задаются тарифами (3 уровня).
|
1. Устройств — 5, это поле тарифа. Цена продления dedicated — 2 499 ₽, цены задаются тарифами (3 уровня).
|
||||||
2. Оформление заказа получает тариф, локацию и валюту из ссылки. В макете там всегда Нидерланды и 4 900 ₽.
|
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-конфиги по странам.
|
4. Mass: в кабинете «Список ключей», без «текущей/запасной локации» и без экрана смены страны. Внутри ключа — ссылка Xray и WG-конфиги по странам.
|
||||||
5. Статус локации показываем везде одинаково: в списках, карточках и на карте.
|
5. Статус локации показываем везде одинаково: в списках, карточках и на карте.
|
||||||
6. Кнопка «Получить VPN» на главной ведёт к блоку цен на этой же странице, на остальных страницах — на `/pricing`.
|
6. Кнопка «Получить VPN» на главной ведёт к блоку цен на этой же странице, на остальных страницах — на `/pricing`.
|
||||||
@@ -87,13 +88,18 @@
|
|||||||
8. Контакты поддержки берутся из настроек сайта, Telegram — ссылка на бота поддержки.
|
8. Контакты поддержки берутся из настроек сайта, Telegram — ссылка на бота поддержки.
|
||||||
9. Плашки способов оплаты в подвале — по активным платёжным системам сайта.
|
9. Плашки способов оплаты в подвале — по активным платёжным системам сайта.
|
||||||
10. Добавляем то, чего нет в макете: переключатель валюты, `<title>` и мета-описания, H1 на каждой странице, поддержку `prefers-reduced-motion` для анимаций.
|
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).
|
12. Переключатели при 5 языках и с валютой (в макете только RU/EN, валюты нет). В шапке — выпадающие списки языка и валюты. В подвале, мобильном меню и кабинете — сегменты с кодами языков (EN RU DE FR ES) и символами валют (₽ $). В оболочке кабинета валюты нет: она появится в настройках (1f).
|
||||||
13. В подвале четыре документа: добавлена «Политика cookies». Плашек способов оплаты нет, пока нет видимых пользователю платёжных систем (пункт 9).
|
13. В подвале четыре документа: добавлена «Политика cookies». Плашек способов оплаты нет, пока нет видимых пользователю платёжных систем (пункт 9).
|
||||||
14. Кабинет mass: подписи навигации те же, что у dedicated («Список ключей», «Купить ключ», «Ключи»). Подписи макета MassApp («Подключения», «Выбрать страну», «Подписка») не используем (пункт 4).
|
14. Кабинет mass: подписи навигации те же, что у dedicated («Список ключей», «Купить ключ», «Ключи»). Подписи макета MassApp («Подключения», «Выбрать страну», «Подписка») не используем (пункт 4).
|
||||||
15. Ширина надписи логотипа — по содержимому: в макете она подогнана под русское название.
|
15. Ширина надписи логотипа — по содержимому: в макете она подогнана под русское название.
|
||||||
16. 404. При `notFound()` Next 16 отдаёт пустую оболочку (`<html id="__next_error__">`), а страница 404 в оформлении бренда отрисовывается в браузере; статус ответа — 404. Серверную отрисовку 404 и 500 решаем на этапе 1b вместе с их оформлением: вариант — `global-not-found.js`.
|
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. Состояния, которых нет в макетах
|
## 8. Состояния, которых нет в макетах
|
||||||
|
|
||||||
@@ -101,7 +107,7 @@
|
|||||||
|
|
||||||
1. Вход: ошибка кода, истёкший код, таймер повторной отправки, загрузка.
|
1. Вход: ошибка кода, истёкший код, таймер повторной отправки, загрузка.
|
||||||
2. Ключ: готовится (до 24 часов), льготный период, истёк, заблокирован; пустой список ключей; ключ без подключений.
|
2. Ключ: готовится (до 24 часов), льготный период, истёк, заблокирован; пустой список ключей; ключ без подключений.
|
||||||
3. Заказ: «ожидает оплаты» (этап 1), не хватает баланса, оплата не прошла; 3-D Secure и счёт в криптовалюте — этап 4.
|
3. Заказ: «ожидает оплаты», не хватает баланса, оплата не прошла (этап 1e); 3-D Secure и счёт в криптовалюте — этап 4b.
|
||||||
4. Счёт: своя сумма пополнения, подтверждение отвязки карты, результат пополнения.
|
4. Счёт: своя сумма пополнения, подтверждение отвязки карты, результат пополнения.
|
||||||
5. Общие: уведомления (тосты), скелетоны загрузки, страницы 404 и 500, ошибки валидации форм.
|
5. Общие: уведомления (тосты), скелетоны загрузки, страницы 404 и 500, ошибки валидации форм.
|
||||||
|
|
||||||
|
|||||||
+18
-18
@@ -1,12 +1,12 @@
|
|||||||
# 08. Интеграции
|
# 08. Интеграции
|
||||||
|
|
||||||
## 1. Почта (этап 1c)
|
## 1. Почта (этапы 1c и 3c)
|
||||||
|
|
||||||
1. Шаблоны — в Payload (`email-templates`): тема и текст на каждом языке, для каждого сайта свои. Шапка (логотип) и подвал (контакты, юридические ссылки) — в коде, у каждого бренда свои.
|
1. Шаблоны — в Payload (`email-templates`): тема и текст на каждом языке, для каждого сайта свои. Шапка (логотип) и подвал (контакты, юридические ссылки) — в коде, у каждого бренда свои.
|
||||||
2. Отправка — через email-адаптер Payload на Nodemailer. Транспорт переключается в админке (глобал «Почта»):
|
2. Отправка — через email-адаптер Payload на Nodemailer. Транспорт переключается в админке (глобал «Почта»):
|
||||||
a. `smtp` — внешний SMTP-провайдер (данные в настройках, пароль зашифрован);
|
a. `smtp` — внешний SMTP-провайдер (данные в настройках, пароль зашифрован);
|
||||||
b. `sendmail` — локальный Postfix (`/usr/sbin/sendmail`);
|
b. `sendmail` — локальный Postfix (`/usr/sbin/sendmail`);
|
||||||
c. `log_only` — не отправлять, только записать в журнал (для разработки).
|
c. `log_only` — не отправлять, только записать в журнал. До этапа 3c работает только он.
|
||||||
3. Письма уходят через фоновую задачу `send-email` с повторами при ошибке. Каждое письмо пишется в журнал писем; коды входа — по флагу ([05-auth.md](05-auth.md), раздел 4).
|
3. Письма уходят через фоновую задачу `send-email` с повторами при ошибке. Каждое письмо пишется в журнал писем; коды входа — по флагу ([05-auth.md](05-auth.md), раздел 4).
|
||||||
4. Кнопка «Отправить тестовое письмо» проверяет текущий транспорт.
|
4. Кнопка «Отправить тестовое письмо» проверяет текущий транспорт.
|
||||||
5. Чтобы письма через Postfix не попадали в спам (root, [09-infrastructure.md](09-infrastructure.md), раздел 6):
|
5. Чтобы письма через Postfix не попадали в спам (root, [09-infrastructure.md](09-infrastructure.md), раздел 6):
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
c. проверить, что исходящий порт 25 открыт и IP нет в чёрных списках.
|
c. проверить, что исходящий порт 25 открыт и IP нет в чёрных списках.
|
||||||
6. Новые IP почтовые сервисы поначалу принимают настороженно, поэтому SMTP-провайдер держим запасным вариантом.
|
6. Новые IP почтовые сервисы поначалу принимают настороженно, поэтому SMTP-провайдер держим запасным вариантом.
|
||||||
|
|
||||||
## 2. ALTCHA (этап 1c)
|
## 2. ALTCHA (этап 3a)
|
||||||
|
|
||||||
1. Капча на proof-of-work без сторонних сервисов: браузер решает небольшую вычислительную задачу, сервер проверяет подпись.
|
1. Капча на proof-of-work без сторонних сервисов: браузер решает небольшую вычислительную задачу, сервер проверяет подпись.
|
||||||
2. Эндпоинт выдачи задачи — `/svc/altcha/challenge`, ключ подписи — в `.env`.
|
2. Эндпоинт выдачи задачи — `/svc/altcha/challenge`, ключ подписи — в `.env`.
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
3. Страна используется только для выбора языка по умолчанию, не для валюты.
|
3. Страна используется только для выбора языка по умолчанию, не для валюты.
|
||||||
4. Если понадобится страна произвольного IP (антифрод), приложение читает тот же `.mmdb` библиотекой `maxmind`.
|
4. Если понадобится страна произвольного IP (антифрод), приложение читает тот же `.mmdb` библиотекой `maxmind`.
|
||||||
|
|
||||||
## 4. Chatwoot (этап 2)
|
## 4. Chatwoot (этап 3e)
|
||||||
|
|
||||||
1. Один экземпляр на отдельном VPS обслуживает оба бренда. У каждого бренда свои входящие каналы:
|
1. Один экземпляр на отдельном VPS обслуживает оба бренда. У каждого бренда свои входящие каналы:
|
||||||
a. виджет на сайте и в кабинете;
|
a. виджет на сайте и в кабинете;
|
||||||
@@ -38,12 +38,12 @@
|
|||||||
2. Для вошедших пользователей виджет получает идентификацию с HMAC-подписью: оператор видит, кто пишет, а подделать её нельзя. Передаём атрибуты: сайт, id пользователя, email, число ключей.
|
2. Для вошедших пользователей виджет получает идентификацию с HMAC-подписью: оператор видит, кто пишет, а подделать её нельзя. Передаём атрибуты: сайт, id пользователя, email, число ключей.
|
||||||
3. Почему бот поддержки отдельный: Telegram отдаёт обновления одного бота только одному получателю. Основной бот принадлежит нашему приложению, бот поддержки — Chatwoot.
|
3. Почему бот поддержки отдельный: Telegram отдаёт обновления одного бота только одному получателю. Основной бот принадлежит нашему приложению, бот поддержки — Chatwoot.
|
||||||
|
|
||||||
## 5. Twenty CRM (этап 2)
|
## 5. Twenty CRM (этап 3d)
|
||||||
|
|
||||||
1. Заявки из `leads` уходят в Twenty через API: человек и сделка с полями заявки, брендом и страницей. Отправка — фоновой задачей с повторами; id в Twenty сохраняется в `leads.crmId`.
|
1. Заявки с форм уходят в Twenty через API: человек и сделка с полями заявки, брендом и страницей. Нужен ли буфер в базе (`leads` с отправкой фоновой задачей и повторами) — решаем на этапе 3d.
|
||||||
2. До этапа 2 заявки видны в админке Payload и приходят письмом `admin_new_lead` на почту поддержки.
|
2. До этапа 3d формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)). С 3d — письмо `admin_new_lead` на почту поддержки.
|
||||||
|
|
||||||
## 6. Telegram (этап 3)
|
## 6. Telegram (этапы 2a–2c)
|
||||||
|
|
||||||
1. Боты для каждого бренда:
|
1. Боты для каждого бренда:
|
||||||
a. основной: команды, кнопка MiniApp, уведомления. Код — grammY в нашем приложении, вебхук `/svc/telegram/<сайт>/webhook` с секретным токеном;
|
a. основной: команды, кнопка MiniApp, уведомления. Код — grammY в нашем приложении, вебхук `/svc/telegram/<сайт>/webhook` с секретным токеном;
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
2. MiniApp — на tg.*, вход по `initData` ([05-auth.md](05-auth.md), раздел 6). Dev-MiniApp доступна только Telegram-аккаунтам из списка разрешённых.
|
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, локализованные.
|
3. Черновик команд основного бота: `/start` (в том числе с реферальным кодом или токеном привязки), `/keys`, `/buy`, `/balance`, `/topup`, `/referral`, `/language`, `/support` (ссылка на бота поддержки), `/help`. Тексты и кнопки — в Payload, локализованные.
|
||||||
4. Уведомления из [04-billing.md](04-billing.md) (раздел 12) дублируются в бот, если Telegram привязан.
|
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. Платёжные системы
|
## 7. Платёжные системы
|
||||||
|
|
||||||
@@ -61,15 +61,15 @@
|
|||||||
b. `handleWebhook` — проверить подпись и вернуть новый статус платежа;
|
b. `handleWebhook` — проверить подпись и вернуть новый статус платежа;
|
||||||
c. по возможностям: `chargeSavedMethod` (автосписание), `refund`, `detachMethod`.
|
c. по возможностям: `chargeSavedMethod` (автосписание), `refund`, `detachMethod`.
|
||||||
2. Запись в коллекции `payment-systems` включает адаптер в валютах и для назначений ([03-data-model.md](03-data-model.md), 3.4). На каком сайте система доступна, следует из валют его доменов. Ключи доступа — в `.env`.
|
2. Запись в коллекции `payment-systems` включает адаптер в валютах и для назначений ([03-data-model.md](03-data-model.md), 3.4). На каком сайте система доступна, следует из валют его доменов. Ключи доступа — в `.env`.
|
||||||
3. Этап 1: только `manual` — для администраторов.
|
3. Фаза 1: `manual` — для администраторов, `demo` — для проверок ([D-027](decisions/D-027-demo-payments.md)).
|
||||||
4. Этап 4:
|
4. Реальные провайдеры:
|
||||||
a. Stripe — USD: карты, сохранение карты, автосписания без участия пользователя на переменную сумму («цена минус баланс»), без Stripe Subscriptions. Сначала тестовый режим;
|
a. ЮKassa — пополнения в RUB (этап 3b);
|
||||||
b. RUB — процессинги, принимающие карты РФ (вероятно, KZ и TR), только пополнения. Провайдеров выбираем на этапе (Q-12);
|
b. Stripe — USD: карты, сохранение карты, автосписания без участия пользователя на переменную сумму («цена минус баланс»), без Stripe Subscriptions; сначала тестовый режим (этап 4b);
|
||||||
c. криптовалюта — пополнения в RUB и USD, провайдер выбирается на этапе;
|
c. криптовалюта — пополнения в RUB и USD, провайдер выбирается на этапе 4b;
|
||||||
d. ЮKassa — опционально, только пополнения, если примет категорию.
|
d. звёзды Telegram — этап 4a.
|
||||||
5. Вебхуки — `/svc/payments/<адаптер>/webhook`; обработка идемпотентная ([04-billing.md](04-billing.md), раздел 14).
|
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)).
|
1. Umami — своя аналитика без cookies, данные не уходят третьим лицам ([D-018](decisions/D-018-analytics.md)).
|
||||||
a. Ставится на этот сервер из исходников, без Docker: Node.js и PostgreSQL здесь уже есть. Umami 3.x поддерживает только PostgreSQL.
|
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`).
|
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 или своя лёгкая реализация.
|
3. Баннер cookies: обязательные (сессия, язык, валюта) и функциональные (чат Chatwoot). Решение пользователя хранится в cookie `vx_consent`, необязательные скрипты загружаются только после согласия. Библиотека — vanilla-cookieconsent или своя лёгкая реализация.
|
||||||
|
|
||||||
## 9. Автоматизация ключей (этап 5)
|
## 9. Выдача ключей через API (этап 3g)
|
||||||
|
|
||||||
Подбор свободного сервера по тарифу (страны, теги) и автоматическая выдача подключений. Обсуждаем при старте этапа.
|
Адаптер `api` на месте демо-эмулятора ([D-028](decisions/D-028-provisioning-adapter.md)): подбор свободного сервера по тарифу (страны, теги) и автоматическая выдача подключений. Обсуждаем при старте этапа.
|
||||||
+15
-14
@@ -56,7 +56,7 @@ vx — личный пользователь администратора, к п
|
|||||||
b. `dev.tg.*` — отдельный `server` без ограничения по IP, с `X-Robots-Tag: noindex`.
|
b. `dev.tg.*` — отдельный `server` без ограничения по IP, с `X-Robots-Tag: noindex`.
|
||||||
c. На порту 80 — `location / { return 301 https://$host$request_uri; }`. Именно внутри `location`, а не на уровне `server`: так certbot при продлении может вставить свой `location` для проверки домена.
|
c. На порту 80 — `location / { return 301 https://$host$request_uri; }`. Именно внутри `location`, а не на уровне `server`: так certbot при продлении может вставить свой `location` для проверки домена.
|
||||||
7. Лимиты запросов (`limit_req`) на эндпоинты входа и формы.
|
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).
|
9. Пути трекера Umami на доменах брендов проксируются на 127.0.0.1:3300 ([08-integrations.md](08-integrations.md), раздел 8).
|
||||||
10. Конфигурацию готовит Claude текстом на согласование, применяет root.
|
10. Конфигурацию готовит Claude текстом на согласование, применяет root.
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ vx — личный пользователь администратора, к п
|
|||||||
b. DKIM: TXT `mail._domainkey.<домен>` с открытым ключом;
|
b. DKIM: TXT `mail._domainkey.<домен>` с открытым ключом;
|
||||||
c. DMARC: `_dmarc.<домен>` — сначала `v=DMARC1; p=none; rua=mailto:…`, после проверки — `p=quarantine`.
|
c. DMARC: `_dmarc.<домен>` — сначала `v=DMARC1; p=none; rua=mailto:…`, после проверки — `p=quarantine`.
|
||||||
4. Проверить, что хостер не закрывает исходящий порт 25 и что 169.58.76.183 нет в чёрных списках.
|
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. Бэкапы
|
## 7. Бэкапы
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ vx — личный пользователь администратора, к п
|
|||||||
|
|
||||||
## 8. Задачи для root по этапам
|
## 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-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 |
|
| 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-04 | 1a | Пользователи vx_dev, vx_prod, umami; `loginctl enable-linger` для них | сделано |
|
||||||
| R-05 | 1a | nginx и сертификаты для всех хостов (раздел 4) | сделано: опечатка исправлена, `X-Robots-Tag` на всех dev-хостах |
|
| 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-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-07 | 3c | Postfix, OpenDKIM, DNS-записи SPF, DKIM, DMARC — или данные SMTP-провайдера | |
|
||||||
| R-08 | 1h | PostgreSQL для prod — если не сделано вместе с R-02 | сделано в R-02 |
|
| R-08 | 3h | PostgreSQL для prod — если не сделано вместе с R-02 | сделано в R-02 |
|
||||||
| R-09 | 1h | nginx и сертификаты для prod-хостов | сделано вместе с R-05 |
|
| R-09 | 3h | nginx и сертификаты для prod-хостов | сделано вместе с R-05 |
|
||||||
| R-10 | 1h | Umami: nginx и сертификат для `umi.veilix.cc` (DNS уже есть; база — в R-02) | |
|
| R-10 | 3f | Umami: nginx и сертификат для `umi.veilix.cc` (DNS уже есть; база — в R-02) | |
|
||||||
| R-11 | 1h | Бэкапы prod-базы и media на внешний сервер (Q-14) | |
|
| R-11 | 3h | Бэкапы prod-базы и media на внешний сервер (Q-14) | |
|
||||||
| R-12 | 2 | VPS с Chatwoot и Twenty, ключи API; 2 бота поддержки в BotFather | |
|
| R-12 | 3d, 3e | VPS с Chatwoot и Twenty, ключи API; 2 бота поддержки в BotFather | |
|
||||||
| R-13 | 3 | Боты в BotFather: 2 основных и тестовые; домен для Telegram Login; адреса MiniApp | |
|
| R-13 | 2a | Боты в BotFather: 2 основных и тестовые; домен для Telegram Login; адреса MiniApp | |
|
||||||
| R-14 | 4 | Аккаунты платёжных систем (сначала тестовые), адреса вебхуков | |
|
| R-14 | 3b, 4b | Аккаунты платёжных систем (сначала тестовые), адреса вебхуков | |
|
||||||
| R-15 | 1h | По желанию (Q-18): sudo-правило, разрешающее vx_dev запускать от имени vx_prod только команду выкладки | |
|
| R-15 | 3h | По желанию (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-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-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
@@ -23,7 +23,7 @@
|
|||||||
## 4. Пользователи
|
## 4. Пользователи
|
||||||
|
|
||||||
1. Коды входа хранятся только как HMAC, проверяются за постоянное время, 5 попыток, 10 минут жизни.
|
1. Коды входа хранятся только как HMAC, проверяются за постоянное время, 5 попыток, 10 минут жизни.
|
||||||
2. ALTCHA и лимиты по IP и email на запрос кода.
|
2. Лимиты по IP и email на запрос кода; ALTCHA — с этапа 3a.
|
||||||
3. Ответ на запрос кода не выдаёт, есть ли аккаунт.
|
3. Ответ на запрос кода не выдаёт, есть ли аккаунт.
|
||||||
4. Токены сессий в базе — только SHA-256. Cookie — `HttpOnly`, `Secure`, `SameSite=Lax`, привязаны к хосту.
|
4. Токены сессий в базе — только SHA-256. Cookie — `HttpOnly`, `Secure`, `SameSite=Lax`, привязаны к хосту.
|
||||||
5. CSRF: `SameSite=Lax`, проверка Origin в server actions и своих POST-эндпоинтах.
|
5. CSRF: `SameSite=Lax`, проверка Origin в server actions и своих POST-эндпоинтах.
|
||||||
@@ -42,7 +42,8 @@
|
|||||||
2. IP пользователей в базе не храним в открытом виде — только HMAC для сравнения (самоприглашения, лимиты). Логи nginx — ротация 14 дней.
|
2. IP пользователей в базе не храним в открытом виде — только HMAC для сравнения (самоприглашения, лимиты). Логи nginx — ротация 14 дней.
|
||||||
3. В списке приглашённых почта замаскирована: `m···@gmail.com`.
|
3. В списке приглашённых почта замаскирована: `m···@gmail.com`.
|
||||||
4. Аналитика — Umami без cookies, данные не уходят третьим лицам.
|
4. Аналитика — Umami без cookies, данные не уходят третьим лицам.
|
||||||
5. Что и зачем храним — в политике конфиденциальности (этап 1b).
|
5. VPN-серверы не ведут журналов трафика и подключений: так сказано в политике конфиденциальности, и выдача через API (этап 3g) это соблюдает.
|
||||||
|
6. Что и зачем храним — в политике конфиденциальности (этап 1b).
|
||||||
|
|
||||||
## 7. Окружения
|
## 7. Окружения
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# D-016. Платёжные системы по валютам; автосписания — Stripe
|
# 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) и криптовалюта.
|
2. USD — Stripe (карты, сохранение карты, автосписания на переменную сумму, без Stripe Subscriptions) и криптовалюта.
|
||||||
3. RUB — процессинги, принимающие карты РФ (вероятно, KZ и TR), только пополнения, без автосписаний. ЮKassa — опционально, только пополнения.
|
3. RUB — процессинги, принимающие карты РФ (вероятно, KZ и TR), только пополнения, без автосписаний. ЮKassa — опционально, только пополнения.
|
||||||
4. Пользователи с картами РФ продлевают ключи с баланса; напоминание — за 3 дня.
|
4. Пользователи с картами РФ продлевают ключи с баланса; напоминание — за 3 дня.
|
||||||
5. Оплата внутри Telegram (Stars) — решаем на этапе 3.
|
5. Оплата внутри Telegram (Stars) — решаем на этапе 4a.
|
||||||
|
|
||||||
## Последствия
|
## Последствия
|
||||||
|
|
||||||
На этапе 1 работает только `manual`. Модель данных готова к любому набору провайдеров.
|
В фазе 1 работают `manual` и `demo` ([D-027](D-027-demo-payments.md)). Модель данных готова к любому набору провайдеров.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# D-017. Статические маркетинговые страницы с пересборкой по событию
|
# D-017. Статические маркетинговые страницы с пересборкой по событию
|
||||||
|
|
||||||
Статус: принято, 20.10.2026.
|
Статус: принято, 20.10.2026. Пункт 2 уточнён в [D-030](D-030-revalidate-path.md).
|
||||||
|
|
||||||
## Решение
|
## Решение
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,4 @@
|
|||||||
|
|
||||||
## Последствия
|
## Последствия
|
||||||
|
|
||||||
До этапа 2 заявки видны в админке Payload и приходят письмом на почту поддержки.
|
Подключаются на этапах 3d (Twenty) и 3e (Chatwoot); до них формы — только интерфейс ([D-026](D-026-stage-order.md)).
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# D-020. Модели ключей dedicated и mass
|
# 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` тарифа.
|
3. Тип ключа определяется полем `type` тарифа.
|
||||||
4. Подключения гибкие: у ключа любой набор подключений разных видов, поэтому ручная выдача на этапе 1 покрывает любой вариант.
|
4. Подключения гибкие: у ключа любой набор подключений разных видов, поэтому ручная выдача на этапе 1 покрывает любой вариант.
|
||||||
5. Оплаченный период начинается с момента выдачи ключа.
|
5. Оплаченный период начинается с момента выдачи ключа.
|
||||||
6. На этапе 1 WG-конфиги mass — те, что добавил администратор, по странам. Нужна другая страна — через поддержку. Автоматически — на этапе 5.
|
6. На этапе 1 WG-конфиги mass — те, что добавил администратор, по странам. Нужна другая страна — через поддержку. Автоматически — на этапе 3g.
|
||||||
|
|
||||||
## Последствия
|
## Последствия
|
||||||
|
|
||||||
Автоматическая выдача (этап 5) создаёт те же подключения, что сейчас добавляет администратор.
|
Автоматическая выдача (этап 3g) создаёт те же подключения, что сейчас добавляет администратор.
|
||||||
@@ -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).
|
||||||
@@ -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. Режим выдачи — настройка сайта.
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
|
||||||
|
Администратор в любом режиме может создать ключ и подключения руками.
|
||||||
@@ -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.
|
||||||
@@ -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 страниц (бренды × языки × валюты × страницы), лениво, при заходе. Нагрузка незаметна.
|
||||||
@@ -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 про российский адрес остаются; «включая российскую локацию» заменяется на «и российский адрес».
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# D-032. Счётчик свободных серверов на сайте
|
||||||
|
|
||||||
|
Статус: принято, 22.10.2026.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
1. Поле локации «Свободных серверов» показывается на сайте рядом со статусом, если оно заполнено: «Серверы в наличии · 12». Пусто — только статус.
|
||||||
|
2. До выдачи через API (этап 3g) число вводится вручную. Правка в админке пересобирает страницы за секунды ([D-030](D-030-revalidate-path.md)), поэтому запрос из браузера не нужен.
|
||||||
|
3. Когда числа начнут меняться автоматически и часто, добавим обновление из браузера: статичная страница плюс запрос свежих значений.
|
||||||
|
|
||||||
|
## Рассмотренные варианты
|
||||||
|
|
||||||
|
Показывать только статус — макеты сайта счётчика не показывают, а ручное число может устареть.
|
||||||
@@ -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. Английский запасной вариант остаётся на случай, когда перевода нет.
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
| [D-003](D-003-hosting.md) | Без Docker: всё на хосте, процессы под systemd | принято |
|
| [D-003](D-003-hosting.md) | Без Docker: всё на хосте, процессы под systemd | принято |
|
||||||
| [D-004](D-004-environments.md) | Dev и prod на одном сервере под разными пользователями | принято |
|
| [D-004](D-004-environments.md) | Dev и prod на одном сервере под разными пользователями | принято |
|
||||||
| [D-005](D-005-multitenancy.md) | Сайты — тенанты, домены в базе, маршрутизация по Host | принято, уточнено в D-022 |
|
| [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-007](D-007-language-detection.md) | Определение языка; MaxMind через nginx | принято, уточнено в D-024 |
|
||||||
| [D-008](D-008-uuid.md) | UUID и случайные публичные коды | принято |
|
| [D-008](D-008-uuid.md) | UUID и случайные публичные коды | принято |
|
||||||
| [D-009](D-009-billing-model.md) | Заказы, платежи, движения по счёту; всё через баланс | принято |
|
| [D-009](D-009-billing-model.md) | Заказы, платежи, движения по счёту; всё через баланс | принято |
|
||||||
@@ -20,12 +20,20 @@
|
|||||||
| [D-014](D-014-email.md) | Почта: шаблоны в Payload, переключаемый транспорт, без listmonk | принято |
|
| [D-014](D-014-email.md) | Почта: шаблоны в Payload, переключаемый транспорт, без listmonk | принято |
|
||||||
| [D-015](D-015-telegram-bots.md) | Боты на grammY без n8n; два бота на бренд | принято |
|
| [D-015](D-015-telegram-bots.md) | Боты на grammY без n8n; два бота на бренд | принято |
|
||||||
| [D-016](D-016-payments.md) | Платёжные системы по валютам; автосписания — Stripe | принято |
|
| [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-018](D-018-analytics.md) | Umami на этом сервере и баннер cookies | принято |
|
||||||
| [D-019](D-019-external-services.md) | Chatwoot и Twenty CRM на отдельном VPS | принято |
|
| [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-021](D-021-admin-host.md) | Админка на plc.veilix.cc с доступом по IP | принято |
|
||||||
| [D-022](D-022-proxy-routing.md) | Proxy: внутренние маршруты по хосту, домены из внутреннего эндпоинта | принято |
|
| [D-022](D-022-proxy-routing.md) | Proxy: внутренние маршруты по хосту, домены из внутреннего эндпоинта | принято |
|
||||||
| [D-023](D-023-site-locales.md) | Языки сайта — поле `sites.locales`, домены показывают их часть | принято |
|
| [D-023](D-023-site-locales.md) | Языки сайта — поле `sites.locales`, домены показывают их часть | принято |
|
||||||
| [D-024](D-024-locale-redirect.md) | Перенаправление на выбранный язык | принято |
|
| [D-024](D-024-locale-redirect.md) | Перенаправление на выбранный язык | принято |
|
||||||
| [D-025](D-025-referral-days.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 языков в каждом этапе | принято |
|
||||||
@@ -1,34 +1,48 @@
|
|||||||
# Этап 1b. Маркетинговые страницы
|
# Этап 1b. Сайт
|
||||||
|
|
||||||
Статус: не начат.
|
Статус: в работе.
|
||||||
|
|
||||||
## 1. Цель
|
## 1. Цель
|
||||||
|
|
||||||
Сайты обоих брендов по макетам, с контентом из Payload, формами и SEO.
|
Сайты обоих брендов по макетам: весь контент — в Payload, 5 языков, SEO и пересборка по событию.
|
||||||
|
|
||||||
## 2. Входит
|
## 2. Входит
|
||||||
|
|
||||||
1. Страницы по макетам для обоих брендов: главная, цены, локации (карта, отрисованная на сервере), поддержка ([07-frontend.md](../07-frontend.md), раздел 2). Юридические страницы `/legal/*`, 404 и 500.
|
1. Страницы по макетам для обоих брендов: главная, цены, локации (карта и глобус, отрисованные на сервере), поддержка ([07-frontend.md](../07-frontend.md), раздел 2). Юридические страницы `/legal/*`, 404 и 500.
|
||||||
2. Коллекции `pages`, `faq` (с местами показа), `leads`; поля контактов в `sites`.
|
2. Контент в Payload ([D-029](../decisions/D-029-pages-blocks.md)): коллекция `pages` из блоков; `faq` с местами показа, включая вопросы кабинета для 1d; поля `sites` — почта и Telegram поддержки, часы работы, SEO по умолчанию.
|
||||||
3. Контент из макетов на RU и EN: тексты, FAQ, локации, тарифы.
|
3. Тексты на 5 языках ([D-033](../decisions/D-033-translations.md)): RU и EN — из макетов и `i18n.js`, de, fr, es — перевод с глоссарием. Тексты описывают работающий продукт ([07-frontend.md](../07-frontend.md), раздел 7).
|
||||||
4. Черновики юридических текстов на RU и EN с заглушками вместо данных юрлица: условия, конфиденциальность, возвраты, cookies.
|
4. Черновики юридических текстов на 5 языках с заглушками вместо данных юрлица (Q-13): условия, конфиденциальность, возвраты, cookies.
|
||||||
5. ALTCHA ([08-integrations.md](../08-integrations.md), раздел 2). Формы «Индивидуальные условия» и обратной связи с ALTCHA пишут в `leads`. Письмо администратору появится в 1c.
|
5. Формы «Индивидуальные условия», «Особые условия» и «Написать нам» — только интерфейс: проверка полей и состояние «отправлено», без отправки ([D-026](../decisions/D-026-stage-order.md)).
|
||||||
6. SEO: `<title>` и описания на каждом языке, `hreflang`, `canonical`, `sitemap.xml` и `robots.txt` на каждый домен, картинки для соцсетей.
|
6. SEO: `<title>` и описания на каждом языке, `hreflang`, `canonical`, `sitemap.xml` и `robots.txt` на каждый домен, картинки для соцсетей.
|
||||||
7. Статическая сборка «язык × валюта» и пересборка по событию из Payload ([D-017](../decisions/D-017-static-pages.md)).
|
7. Статическая сборка «язык × валюта» и пересборка по событию из Payload ([D-017](../decisions/D-017-static-pages.md), [D-030](../decisions/D-030-revalidate-path.md)).
|
||||||
8. Решить, показывать ли количество свободных серверов.
|
8. Счётчик свободных серверов рядом со статусом, если поле заполнено ([D-032](../decisions/D-032-free-servers.md)).
|
||||||
|
|
||||||
## 3. Не входит
|
## 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.
|
Root: R-19 — сделано.
|
||||||
2. Правка цены, статуса локации или FAQ в админке видна на сайте в течение нескольких секунд.
|
|
||||||
|
## 6. Готово, когда
|
||||||
|
|
||||||
|
1. Страницы обоих брендов совпадают с макетами: светлая и тёмная тема, десктоп и мобильный, 5 языков.
|
||||||
|
2. Правка цены, статуса локации, FAQ или текста страницы в админке видна на сайте в течение нескольких секунд.
|
||||||
3. Lighthouse mobile ≥ 90 на главной и странице цен обоих брендов.
|
3. Lighthouse mobile ≥ 90 на главной и странице цен обоих брендов.
|
||||||
4. Формы создают заявки, ALTCHA работает.
|
4. Формы проверяют поля и показывают состояние «отправлено».
|
||||||
5. `sitemap.xml` и `hreflang` проходят проверку.
|
5. `sitemap.xml` и `hreflang` проходят проверку.
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
# Этап 1c. Вход по коду и почта
|
# Этап 1c. Вход по коду
|
||||||
|
|
||||||
Статус: не начат.
|
Статус: не начат.
|
||||||
|
|
||||||
## 1. Цель
|
## 1. Цель
|
||||||
|
|
||||||
Регистрация и вход по коду из письма в кабинетах обоих брендов; почтовая подсистема с журналом.
|
Регистрация и вход по коду в кабинетах обоих брендов. Письма не отправляются, а пишутся в журнал: код виден в админке.
|
||||||
|
|
||||||
## 2. Входит
|
## 2. Входит
|
||||||
|
|
||||||
1. Почта ([08-integrations.md](../08-integrations.md), раздел 1): глобал «Почта» (транспорты `smtp`, `sendmail`, `log_only`), email-адаптер, `email-templates` с шапкой и подвалом бренда, `email-log`, задача `send-email`, тестовое письмо, флаг «Записывать коды входа в журнал».
|
1. Почта ([08-integrations.md](../08-integrations.md), раздел 1): глобал «Почта» с транспортом `log_only`, email-адаптер, `email-templates` с шапкой и подвалом бренда, `email-log`, задача `send-email`, флаг «Записывать коды входа в журнал».
|
||||||
2. Шаблоны на RU и EN: `login_code`, `admin_new_lead` (и подключить его к формам из 1b).
|
2. Шаблон `login_code` на 5 языках.
|
||||||
3. `customers` со своей стратегией, `customer-sessions`, `auth-codes`; запрос и проверка кода, лимиты, ALTCHA ([05-auth.md](../05-auth.md), разделы 2–4).
|
3. `customers` со своей стратегией, `customer-sessions`, `auth-codes`; запрос и проверка кода, лимиты по IP и email ([05-auth.md](../05-auth.md), разделы 2–4).
|
||||||
4. Страница `/login` по макету с состояниями: код отправлен, ошибка, истёк, повторная отправка через 60 секунд.
|
4. Страница `/login` по макету с состояниями: код отправлен, ошибка, истёк, повторная отправка через 60 секунд.
|
||||||
5. Выход, выход на всех устройствах.
|
5. Выход, выход на всех устройствах.
|
||||||
6. Язык и валюта аккаунта при регистрации ([04-billing.md](../04-billing.md), раздел 2).
|
6. Язык и валюта аккаунта при регистрации ([04-billing.md](../04-billing.md), раздел 2).
|
||||||
@@ -18,15 +18,14 @@
|
|||||||
|
|
||||||
## 3. Не входит
|
## 3. Не входит
|
||||||
|
|
||||||
Telegram (этап 3), реферальная привязка при регистрации (1g).
|
ALTCHA (3a), отправка писем через `sendmail` и `smtp` (3c), Telegram (2a–2c), реферальная привязка при регистрации (1h).
|
||||||
|
|
||||||
## 4. Перед стартом
|
## 4. Перед стартом
|
||||||
|
|
||||||
Root: R-07 (Postfix, OpenDKIM, DNS) или данные SMTP-провайдера. Без них этап делается на транспорте `log_only`.
|
Этап 1b готов.
|
||||||
|
|
||||||
## 5. Готово, когда
|
## 5. Готово, когда
|
||||||
|
|
||||||
1. Регистрация и вход работают на `dev.my.veilix.app` и `dev.my.veilixvpn.com`; аккаунты сайтов независимы.
|
1. Регистрация и вход работают на `dev.my.veilix.app` и `dev.my.veilixvpn.com`; аккаунты сайтов независимы.
|
||||||
2. С флагом коды видны в журнале; на `log_only` письма не уходят.
|
2. Код входа виден в журнале писем в админке; письма никуда не уходят.
|
||||||
3. Через `sendmail` или `smtp` письмо доходит до Gmail не в спам; оценка mail-tester ≥ 9/10.
|
3. Лимиты и счётчик попыток работают; сессии отзываются.
|
||||||
4. Лимиты и счётчик попыток работают; сессии отзываются.
|
|
||||||
@@ -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` не находит расхождений.
|
|
||||||
@@ -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 на конфиг (тест).
|
||||||
@@ -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` не списывает дважды.
|
||||||
@@ -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 на конфиг (тест).
|
|
||||||
@@ -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. Все данные — реальные, из базы.
|
|
||||||
@@ -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.
|
||||||
@@ -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` не находит расхождений.
|
||||||
@@ -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. Цель
|
## 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. Входит
|
## 2. Входит
|
||||||
|
|
||||||
@@ -14,9 +14,13 @@
|
|||||||
4. Бонус обоим после первой оплаты заказа `new_key` приглашённого: дни к ключам через `key-extensions`; статус `review` при совпадении хэша IP.
|
4. Бонус обоим после первой оплаты заказа `new_key` приглашённого: дни к ключам через `key-extensions`; статус `review` при совпадении хэша IP.
|
||||||
5. Число дней бонуса в `sites` (`referralBonusDays`).
|
5. Число дней бонуса в `sites` (`referralBonusDays`).
|
||||||
6. Страница `/referral` по макету: приглашено, начислено месяцев, ожидает; ссылка с копированием; приглашённые с замаскированной почтой. Условия под ссылкой — про дни, а не про списание ([07-frontend.md](../07-frontend.md), раздел 7).
|
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 дней.
|
1. A делится ссылкой → B регистрируется → B оплачивает первый заказ → к ключу B и к последнему ключу A добавлено по 30 дней.
|
||||||
2. У A нет подходящего ключа — дни добавляются к следующему ключу A.
|
2. У A нет подходящего ключа — дни добавляются к следующему ключу A.
|
||||||
@@ -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.
|
|
||||||
@@ -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 можно зарегистрироваться, купить ключ демо-оплатой, получить конфиги, пополнить баланс и пригласить друга.
|
||||||
@@ -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 языках; уведомления о выдаче ключа и продлениях приходят в бот.
|
||||||
@@ -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. Готово, когда
|
||||||
|
|
||||||
|
Сценарии привязки и объединения аккаунтов проходят: автотесты и проверка вручную.
|
||||||
@@ -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. Сценарии привязки и объединения аккаунтов проходят.
|
|
||||||
@@ -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. Готово, когда
|
||||||
|
|
||||||
|
Запрос кода без решения или с уже использованным решением отклоняется; в браузере вход работает без видимой капчи.
|
||||||
@@ -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. Готово, когда
|
||||||
|
|
||||||
|
Пополнение в тестовом режиме проходит путь от оплаты до зачисления, включая повторную доставку вебхуков.
|
||||||
@@ -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.
|
||||||
@@ -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 заявка не теряется молча.
|
||||||
@@ -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 с указанием бренда; вошедший пользователь опознан.
|
||||||
@@ -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 не загружается.
|
||||||
@@ -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 по странам, обработка ошибок выдачи.
|
||||||
@@ -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. Восстановление из бэкапа проверено.
|
||||||
@@ -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. Возвраты на карту работают.
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Этап 4a. Звёзды Telegram
|
||||||
|
|
||||||
|
Статус: обсуждение при старте этапа.
|
||||||
|
|
||||||
|
## 1. Что известно
|
||||||
|
|
||||||
|
По правилам Telegram цифровые товары в ботах и MiniApp оплачиваются звёздами (Telegram Stars), за нарушения ботов блокируют ([08-integrations.md](../08-integrations.md), раздел 6). Варианты: звёзды, внешняя страница оплаты, покупки в Telegram только с баланса (Q-11).
|
||||||
|
|
||||||
|
## 2. Обсудить при старте
|
||||||
|
|
||||||
|
Курс звёзд к ценам тарифов, зачисление на баланс, возвраты.
|
||||||
@@ -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. Возвраты на карту работают.
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Этап 5. Автоматизация выдачи ключей
|
|
||||||
|
|
||||||
Статус: обсуждение при старте этапа.
|
|
||||||
|
|
||||||
## 1. Что известно
|
|
||||||
|
|
||||||
1. По тарифу (страны, теги) подбирается свободный сервер, бэкенд возвращает подключения для ключа.
|
|
||||||
2. Автоматика создаёт те же подключения, что на этапе 1 добавляет администратор ([D-020](../decisions/D-020-key-models.md)), и отключает их, когда ключ истекает.
|
|
||||||
3. Наличие в локациях обновляется автоматически, сайты пересобираются по событию.
|
|
||||||
|
|
||||||
## 2. Обсудить при старте
|
|
||||||
|
|
||||||
Источник серверов и подключений, способ интеграции, как получать WG-конфиги mass по странам, обработка ошибок выдачи.
|
|
||||||
Reference in new issue
Block a user