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

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

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

No files matched your search

+16 -12
View File
@@ -55,7 +55,9 @@ erDiagram
| locales | multi-select из языков конфига | языки контента сайта; en обязателен; домены показывают часть этих языков ([D-023](decisions/D-023-site-locales.md)) |
| supportEmail | email | почта поддержки: `help@veilix.app`, `help@veilixvpn.com` |
| emailFrom | group: name, address | отправитель писем, напр. «Вейликс» <no-reply@veilix.app> |
| supportBot, mainBot | text | имена ботов (этап 3) |
| supportBot | text | Telegram поддержки — имя для ссылки `t.me/…`: пока `veilix_support` у обоих брендов, с этапа 3e — бот поддержки бренда |
| supportHours | text (L) | часы поддержки: «с 10 до 20 по московскому времени в рабочие дни» |
| mainBot | text | имя основного бота (этап 2a) |
| referralEnabled | checkbox | |
| referralBonusDays | number, по умолчанию 30 | бонус «месяц в подарок»: дни срока ключа обоим ([D-025](decisions/D-025-referral-days.md)) |
| topupPresets | array: currency, amounts[] | суммы пополнения в кабинете ([04-billing.md](04-billing.md), раздел 4) |
@@ -63,9 +65,10 @@ erDiagram
| reminderDays | number, по умолчанию 3 | за сколько дней напоминать |
| renewalLeadHours | number, по умолчанию 24 | за сколько часов до окончания пробовать продлить |
| expiringBadgeDays | number, по умолчанию 7 | когда показывать «Истекает» |
| provisioningMode | select `manual` \| `demo` \| `api` | режим выдачи ключей ([D-028](decisions/D-028-provisioning-adapter.md)): `demo` — с этапа 1f, `api` — с 3g |
| seo | group: titleTemplate (L), description (L), ogImage | значения по умолчанию |
На этапе 1a сделаны `code` (после создания не меняется), `name`, `orderPrefix` и `locales`. Остальные поля добавляют этапы, которые ими пользуются: SEO и контакты — 1b, отправитель писем — 1c, сроки и пресеты — 1d и 1f, рефералы — 1g, боты — 3.
На этапе 1a сделаны `code` (после создания не меняется), `name`, `orderPrefix` и `locales`. Остальные поля добавляют этапы, которые ими пользуются: SEO, контакты и часы поддержки — 1b, отправитель писем — 1c, порог «Истекает» — 1d, пресеты пополнения — 1e, режим выдачи — 1f, сроки продлений и напоминаний — 1g, рефералы — 1h, основной бот — 2a.
### 3.2 `domains` — Домены (сайт)
@@ -80,7 +83,7 @@ erDiagram
| localeCurrency | array: locale, currency | валюта по умолчанию для языка: ru → RUB |
| isPrimary | checkbox | основной домен этого типа (у сайта один на каждый тип); используется в ссылках и sitemap |
| indexable | checkbox | разрешена ли индексация (для кабинета и MiniApp — нет) |
| umamiWebsiteId | text | этап 1h |
| umamiWebsiteId | text | этап 3f |
| active | checkbox | |
Язык и валюта по умолчанию должны входить в списки домена, язык в правилах «язык → валюта» не повторяется — это проверяется при сохранении.
@@ -102,13 +105,14 @@ erDiagram
| Поле | Тип | Описание |
|---|---|---|
| name | text | название в админке |
| adapter | select | реализация в коде: `manual`; на этапе 4 — `stripe`, `yookassa`, `crypto_*`, `rucard_*` |
| adapter | select | реализация в коде: `manual`, `demo` (1e, [D-027](decisions/D-027-demo-payments.md)); `yookassa` (3b); `stripe`, `crypto_*` (4b) |
| title | text (L) | что видит пользователь: «Банковская карта», «Карта МИР», «СБП», «Криптовалюта» |
| description | text (L) | подсказка: «USDT, BTC, ETH, курс фиксируется на 15 минут» |
| icon | upload | |
| currencies | multi-select валют | в каких валютах доступна |
| purposes | multi-select `order` \| `topup` | оплата заказа, пополнение |
| visibleToCustomers | checkbox | у `manual` всегда выключено (проверяется при сохранении): ей пользуются только администраторы |
| allowedIps | text | для `demo`: IP и подсети, с которых система видна; пусто — не видна никому |
| mode | select `test` \| `live` | |
| limits | array: currency, min, max | |
| capabilities | только чтение, из адаптера | `recurring`, `refunds`, `saveMethod`; объявлены в `src/core/payments/adapters.ts`, в базе не хранятся |
@@ -133,7 +137,7 @@ erDiagram
| city | text (L) | |
| lat, lng | number | точка города на карте |
| status | select `available` \| `on_demand` \| `soon` | dedicated: «Серверы в наличии» / «Установим за 24 часа»; mass: «Включено» / «Скоро». Чужой для бренда статус не сохранится |
| freeServers | number, необязательное | счётчик (решение о показе — этап 1b) |
| freeServers | number, необязательное | счётчик; на сайте показывается, если заполнен ([D-032](decisions/D-032-free-servers.md)) |
| visible, sort | | |
### 3.7 `tags` — Теги (общие)
@@ -178,8 +182,8 @@ erDiagram
|---|---|---|
| email | email, null | уникален в пределах сайта, хранится в нижнем регистре |
| emailVerifiedAt | date | |
| telegramId | text, null | уникален в пределах сайта (этап 3) |
| telegramUsername, telegramName | text | этап 3 |
| telegramId | text, null | уникален в пределах сайта (этап 2a) |
| telegramUsername, telegramName | text | этап 2a |
| locale | select | язык писем и бота |
| currency | select | валюта аккаунта ([04-billing.md](04-billing.md), раздел 2) |
| balance | number, только чтение | кэш суммы движений по счёту |
@@ -229,7 +233,7 @@ erDiagram
| title | text | «Устройство 1», «Ноутбук» |
| deviceSlot | number | номер устройства для WG/AWG |
| country | relationship → countries | для WG у mass — страна конфига; для RU-адреса — RU |
| isRu | checkbox | подключение к RU-адресу (dedicated) |
| isRu | checkbox | подключение к RU-адресу; у обоих брендов ([D-031](decisions/D-031-mass-ru-address.md)) |
| payload | text, зашифрованное | содержимое конфига или URL |
| fileName | text | имя файла при скачивании |
| status | select `active` \| `revoked` | |
@@ -242,7 +246,7 @@ QR-коды строятся на лету из `payload`, не хранятся
| Статус | Значение |
|---|---|
| `provisioning` | оплачен, готовится. Срок ещё не идёт. На этапе 1 так создаются все ключи: подключения добавляет администратор |
| `provisioning` | оплачен, готовится. Срок ещё не идёт. Подключения создаёт адаптер выдачи ([D-028](decisions/D-028-provisioning-adapter.md)) или администратор |
| `active` | работает, срок идёт с `activatedAt` |
| `grace` | срок истёк, оплата не прошла, ключ ещё работает до `graceUntil` |
| `expired` | истёк, подключения отключаются |
@@ -319,7 +323,7 @@ QR-коды строятся на лету из `payload`, не хранятся
| customer | relationship | |
| currency | | валюта аккаунта |
| amount | number со знаком | `+` зачисление, `−` списание |
| type | select `topup` \| `order_charge` \| `refund` \| `adjustment` \| `payout` | `payout` — возврат денег с баланса на карту (этап 4). Реферальный бонус — не деньги, а дни (5.4) |
| type | select `topup` \| `order_charge` \| `refund` \| `adjustment` \| `payout` | `payout` — возврат денег с баланса на карту (этап 4b). Реферальный бонус — не деньги, а дни (5.4) |
| payment, order, key | relationship | источник записи |
| balanceAfter | number | баланс после записи |
| comment | text | обязателен для `adjustment` |
@@ -339,7 +343,7 @@ QR-коды строятся на лету из `payload`, не хранятся
### 7.1 `pages` — Страницы (сайт)
`slug` (уникальное в сайте: `terms`, `privacy`, `refund`, `cookies`), `title` (L), `content` (L, Lexical), `seo` (title (L), description (L)). Черновики и версии Payload включены.
Страницы сайта из блоков ([D-029](decisions/D-029-pages-blocks.md)): `slug` (уникальное в сайте: `home`, `pricing`, `locations`, `support`, `terms`, `privacy`, `refund`, `cookies`), `title` (L), `layout` (блоки, поля блоков локализованы), `seo` (title (L), description (L), image). Черновики и версии Payload включены. Набор блоков — в `src/payload/blocks/`, описание — по итогам этапа 1b.
### 7.2 `faq` — Вопросы и ответы (сайт)
@@ -353,7 +357,7 @@ QR-коды строятся на лету из `payload`, не хранятся
### 7.4 `leads` — Заявки (сайт)
`type` (`individual_terms` \| `contact`), `name`, `email`, `telegram`, `whatsapp`, `topic`, `message`, `locale`, `pageUrl`, `customer`, `status` (`new` \| `in_progress` \| `done` \| `spam`), `crmId` и `chatwootId` (этап 2), `ipHash`.
Этап 3d. До него формы — только интерфейс ([D-026](decisions/D-026-stage-order.md)); нужна ли коллекция как буфер перед Twenty — решаем на этапе. Поля: `type` (`individual_terms` \| `contact`), `name`, `email`, `telegram`, `whatsapp`, `topic`, `message`, `locale`, `pageUrl`, `customer`, `status` (`new` \| `in_progress` \| `done` \| `spam`), `crmId` (3d) и `chatwootId` (3e), `ipHash`.
### 7.5 `media` — Файлы