2026-10-21 03:30:38 +02:00
# 03. Модель данных
## 1. Соглашения
1. Все `id` — UUID (`idType: 'uuid'` в адаптере Postgres). Номера для людей (заказы, ключи, платежи, реферальные коды) — случайные коды, не последовательные.
2. Сайт — тенант плагина `@payloadcms/plugin-multi-tenant` . Поле тенанта называется `site` . Коллекции с пометкой «сайт» содержат его автоматически; в админке у них есть переключатель сайта.
3. «(L)» — локализованное поле Payload: значение хранится на каждом языке, если перевода нет — показывается EN.
4. Деньги — целое число в минимальных единицах (`amount` : 249900 = 2 499,00 ₽) плюс `currency` — код ISO 4217 (`RUB` , `USD` ). Код проверяется по справочнику «Валюты».
5. Даты — `timestamptz` , в UTC.
6. Секреты в полях (конфиги WG, ссылки подписок, SMTP-пароль, id сохранённых карт) шифруются приложением (AES-256-GCM, ключ в `.env` ).
2026-10-21 05:08:05 +02:00
7. Валюта везде хранится кодом ISO 4217 — и в деньгах, и в настройках (валюты домена и платёжной системы, строки цен). Код проверяется по справочнику, в админке это выпадающий список из «Валют».
8. Переводы полей Payload хранятся в таблицах `<коллекция>_l10n` (настройка адаптера `localesSuffix` ). Имя по умолчанию `<коллекция>_locales` совпало бы с таблицей поля `locales` у сайтов и доменов.
2026-10-21 03:30:38 +02:00
## 2. Схема связей
```mermaid
erDiagram
SITES ||--o{ DOMAINS : "домены"
SITES ||--o{ LOCATIONS : "локации"
SITES ||--o{ TARIFFS : "тарифы"
SITES ||--o{ CUSTOMERS : "пользователи"
COUNTRIES ||--o{ LOCATIONS : "страна"
TARIFFS }o--o{ COUNTRIES : "страны тарифа"
TARIFFS }o--o{ TAGS : "теги"
DOMAINS }o--o{ CURRENCIES : "валюты домена"
PAYMENT_SYSTEMS }o--o{ CURRENCIES : "валюты системы"
CUSTOMERS ||--o{ KEYS : "ключи"
TARIFFS ||--o{ KEYS : "тариф"
LOCATIONS ||--o{ KEYS : "локация (dedicated)"
KEYS ||--o{ CONNECTIONS : "подключения"
CUSTOMERS ||--o{ ORDERS : "заказы"
KEYS ||--o{ ORDERS : "продления"
ORDERS ||--o{ PAYMENTS : "оплаты"
CUSTOMERS ||--o{ PAYMENTS : "платежи"
PAYMENT_SYSTEMS ||--o{ PAYMENTS : "через"
CUSTOMERS ||--o{ LEDGER_ENTRIES : "движения"
PAYMENTS ||--o{ LEDGER_ENTRIES : "зачисление"
ORDERS ||--o{ LEDGER_ENTRIES : "списание, возврат"
CUSTOMERS ||--o{ PAYMENT_METHODS : "карты"
CUSTOMERS ||--o{ REFERRALS : "пригласил"
2026-10-21 16:00:32 +02:00
KEYS ||--o{ KEY_EXTENSIONS : "продления без оплаты"
REFERRALS ||--o{ KEY_EXTENSIONS : "бонус"
2026-10-21 03:30:38 +02:00
CUSTOMERS ||--o{ CUSTOMER_SESSIONS : "сессии"
```
## 3. Настройки и справочники
### 3.1 `sites` — Сайты (тенанты)
| Поле | Тип | Описание |
|---|---|---|
| code | select `dedicated` \| `mass` , уникальное | бренд: по нему выбираются тема и страницы |
| name | text (L) | «Вейликс» / «Veilix» |
| orderPrefix | text | префикс номеров: `VX` , `VV` |
2026-10-21 05:08:05 +02:00
| locales | multi-select из языков конфига | языки контента сайта; en обязателен; домены показывают часть этих языков ([D-023 ](decisions/D-023-site-locales.md )) |
2026-10-21 16:00:32 +02:00
| supportEmail | email | почта поддержки: `help@veilix.app` , `help@veilixvpn.com` |
2026-10-21 03:30:38 +02:00
| emailFrom | group: name, address | отправитель писем, напр. «Вейликс» <no-reply@veilix .app> |
2026-10-22 03:48:10 +02:00
| supportBot | text | Telegram поддержки — имя для ссылки `t.me/…` : пока `veilix_support` у обоих брендов, с этапа 3e — бот поддержки бренда |
| supportHours | text (L) | часы поддержки: «с 10 до 20 по московскому времени в рабочие дни» |
| mainBot | text | имя основного бота (этап 2a) |
2026-10-21 03:30:38 +02:00
| referralEnabled | checkbox | |
2026-10-21 16:00:32 +02:00
| referralBonusDays | number, по умолчанию 30 | бонус «месяц в подарок»: дни срока ключа обоим ([D-025 ](decisions/D-025-referral-days.md )) |
| topupPresets | array: currency, amounts[] | суммы пополнения в кабинете ([04-billing.md ](04-billing.md ), раздел 4) |
2026-10-21 03:30:38 +02:00
| graceDays | number, по умолчанию 3 | льготный период |
| reminderDays | number, по умолчанию 3 | за сколько дней напоминать |
| renewalLeadHours | number, по умолчанию 24 | за сколько часов до окончания пробовать продлить |
| expiringBadgeDays | number, по умолчанию 7 | когда показывать «Истекает» |
2026-10-22 03:48:10 +02:00
| provisioningMode | select `manual` \| `demo` \| `api` | режим выдачи ключей ([D-028 ](decisions/D-028-provisioning-adapter.md )): `demo` — с этапа 1f, `api` — с 3g |
2026-10-21 03:30:38 +02:00
| seo | group: titleTemplate (L), description (L), ogImage | значения по умолчанию |
2026-10-22 04:53:15 +02:00
На этапе 1a сделаны `code` (после создания не меняется), `name` , `orderPrefix` и `locales` , на этапе 1b — `supportEmail` , `supportBot` , `supportHours` и `seo` . Остальные поля добавляют этапы, которые ими пользуются: SEO, контакты и часы поддержки — 1b, отправитель писем — 1c, порог «Истекает» — 1d, пресеты пополнения — 1e, режим выдачи — 1f, сроки продлений и напоминаний — 1g, рефералы — 1h, основной бот — 2a.
2026-10-21 05:08:05 +02:00
2026-10-21 03:30:38 +02:00
### 3.2 `domains` — Домены (сайт)
| Поле | Тип | Описание |
|---|---|---|
| hostname | text, уникальное | `veilix.app` , `my.veilix.app` , … |
| app | select `marketing` \| `cabinet` \| `miniapp` | тип фронтенда |
2026-10-21 05:08:05 +02:00
| locales | multi-select из языков конфига | включённые языки — часть языков сайта |
| defaultLocale | select | обычно `en` ; открывается без префикса в адресе |
2026-10-21 03:30:38 +02:00
| currencies | multi-select валют | включённые валюты |
| defaultCurrency | select | валюта по умолчанию |
| localeCurrency | array: locale, currency | валюта по умолчанию для языка: ru → RUB |
2026-10-21 05:08:05 +02:00
| isPrimary | checkbox | основной домен этого типа (у сайта один на каждый тип); используется в ссылках и sitemap |
2026-10-21 03:30:38 +02:00
| indexable | checkbox | разрешена ли индексация (для кабинета и MiniApp — нет) |
2026-10-22 03:48:10 +02:00
| umamiWebsiteId | text | этап 3f |
2026-10-21 03:30:38 +02:00
| active | checkbox | |
2026-10-21 05:08:05 +02:00
Язык и валюта по умолчанию должны входить в списки домена, язык в правилах «язык → валюта» не повторяется — это проверяется при сохранении.
2026-10-21 03:30:38 +02:00
### 3.3 `currencies` — Валюты
| Поле | Тип | Описание |
|---|---|---|
| code | text, уникальное | ISO 4217: `RUB` , `USD` |
| symbol | text | `₽` , `$` |
| name | text (L) | |
| minorUnits | number | 2 |
| active, sort | | |
### 3.4 `payment-systems` — Платёжные системы
Платёжная система привязана только к валютам. Где она доступна, следует из цепочки: валюты → домены, на которых они включены → сайты. В оформлении заказа и пополнении показываются системы в валюте аккаунта.
| Поле | Тип | Описание |
|---|---|---|
| name | text | название в админке |
2026-10-22 03:48:10 +02:00
| adapter | select | реализация в коде: `manual` , `demo` (1e, [D-027 ](decisions/D-027-demo-payments.md )); `yookassa` (3b); `stripe` , `crypto_*` (4b) |
2026-10-21 03:30:38 +02:00
| title | text (L) | что видит пользователь: «Банковская карта», «Карта МИР», «СБП», «Криптовалюта» |
| description | text (L) | подсказка: «USDT, BTC, ETH, курс фиксируется на 15 минут» |
| icon | upload | |
| currencies | multi-select валют | в каких валютах доступна |
| purposes | multi-select `order` \| `topup` | оплата заказа, пополнение |
2026-10-21 05:08:05 +02:00
| visibleToCustomers | checkbox | у `manual` всегда выключено (проверяется при сохранении): ей пользуются только администраторы |
2026-10-22 03:48:10 +02:00
| allowedIps | text | для `demo` : IP и подсети, с которых система видна; пусто — не видна никому |
2026-10-21 03:30:38 +02:00
| mode | select `test` \| `live` | |
| limits | array: currency, min, max | |
2026-10-21 05:08:05 +02:00
| capabilities | только чтение, из адаптера | `recurring` , `refunds` , `saveMethod` ; объявлены в `src/core/payments/adapters.ts` , в базе не хранятся |
2026-10-21 03:30:38 +02:00
| active, sort | | |
Ключи доступа к провайдерам — только в `.env` (`PAYMENT_<КОД>_…` ), не в базе.
### 3.5 `countries` — Страны (общие)
| Поле | Тип | Описание |
|---|---|---|
| iso2 | text, уникальное | `NL` , `DE` , … |
| name | text (L) | |
| lat, lng | number | точка на карте по умолчанию |
| sort | number | |
### 3.6 `locations` — Локации (сайт)
| Поле | Тип | Описание |
|---|---|---|
| country | relationship → countries | уникальна в пределах сайта |
| city | text (L) | |
| lat, lng | number | точка города на карте |
2026-10-21 05:08:05 +02:00
| status | select `available` \| `on_demand` \| `soon` | dedicated: «Серверы в наличии» / «Установим за 24 часа»; mass: «Включено» / «Скоро». Чужой для бренда статус не сохранится |
2026-10-22 03:48:10 +02:00
| freeServers | number, необязательное | счётчик; на сайте показывается, если заполнен ([D-032 ](decisions/D-032-free-servers.md )) |
2026-10-21 03:30:38 +02:00
| visible, sort | | |
### 3.7 `tags` — Теги (общие)
`name` , `code` (уникальное). Для фильтрации тарифов и будущей автоматизации выдачи ключей.
### 3.8 `tariffs` — Тарифы (сайт)
| Поле | Тип | Описание |
|---|---|---|
| name | text (L) | |
| code | text, уникальное в сайте | |
| type | select `dedicated` \| `mass` | поведение ключа: dedicated — страна выбирается при покупке, mass — все страны тарифа |
| description | text (L) | |
| features | array of text (L) | пункты «что входит» |
| period | group: unit `month` \| `year` , count | |
| devicesLimit | number, по умолчанию 5 | |
| prices | array: currency, firstPeriodAmount, renewalAmount | строка на валюту; нет строки — тариф в этой валюте не продаётся |
| countries | relationship → countries, many | страны тарифа |
| tags | relationship → tags, many | |
| badge | text (L) | «выгоднее» |
| isDefault | checkbox | выбран по умолчанию на странице цен |
| active, sort | | |
## 4. Люди
### 4.1 `admins` — Администраторы
2026-10-21 05:08:05 +02:00
Стандартная авторизация Payload (email и пароль), `maxLoginAttempts: 5` , `lockTime: 15 мин` . Первый администратор окружения (экран первого входа) становится owner. Последнего owner нельзя лишить роли и удалить. Роли и сайты меняет только owner, остальные правят только своё имя и пароль.
2026-10-21 03:30:38 +02:00
| Поле | Тип | Описание |
|---|---|---|
| name | text | |
| roles | multi-select `owner` \| `admin` \| `support` \| `content` | см. раздел 8 |
2026-10-21 05:08:05 +02:00
| sites | доступ к тенантам | owner и admin видят все сайты, поэтому поле показывается только ролям support и content; на экране первого входа скрыто |
2026-10-21 03:30:38 +02:00
### 4.2 `customers` — Пользователи (сайт)
Коллекция авторизации Payload со своей стратегией (вход по коду, [05-auth.md ](05-auth.md )).
| Поле | Тип | Описание |
|---|---|---|
| email | email, null | уникален в пределах сайта, хранится в нижнем регистре |
| emailVerifiedAt | date | |
2026-10-22 03:48:10 +02:00
| telegramId | text, null | уникален в пределах сайта (этап 2a) |
| telegramUsername, telegramName | text | этап 2a |
2026-10-21 03:30:38 +02:00
| locale | select | язык писем и бота |
| currency | select | валюта аккаунта ([04-billing.md ](04-billing.md ), раздел 2) |
| balance | number, только чтение | кэш суммы движений по счёту |
| referralCode | text, уникальное в сайте | случайный |
| referredBy | relationship → customers | |
| status | select `active` \| `blocked` | |
| registeredVia | select `email` \| `telegram` \| `admin` | |
| registrationIpHash | text | HMAC от IP: только для сравнения при проверке самоприглашений |
| marketingConsent | checkbox | |
| lastLoginAt | date | |
| defaultPaymentMethod | relationship → payment-methods | |
| adminNotes | textarea | видят только администраторы |
### 4.3 `customer-sessions` — Сессии (служебная)
`customer` , `kind` (`web` \| `miniapp` ), `tokenHash` (SHA-256, уникальное), `createdAt` , `expiresAt` , `lastSeenAt` , `ipHash` , `userAgent` , `revokedAt` .
### 4.4 `auth-codes` — Коды входа (служебная)
`site` , `email` , `purpose` (`login` \| `link_email` ), `customer` (для привязки почты), `codeHash` , `expiresAt` , `attempts` , `consumedAt` , `requestIpHash` .
## 5. Ключи
### 5.1 `keys` — Ключи (сайт)
| Поле | Тип | Описание |
|---|---|---|
| code | text, уникальное | публичный код, напр. `K-7F2C9Q` |
| customer | relationship | |
| tariff | relationship | |
| type | select `dedicated` \| `mass` | копия из тарифа |
| location | relationship → locations | только dedicated |
| status | select | см. 5.3 |
| autoRenew | checkbox, по умолчанию да | |
| activatedAt, expiresAt, graceUntil, cancelledAt | date | |
| renewalAmount, currency | | цена продления, зафиксированная при покупке; администратор может изменить |
| period, devicesLimit | | копии из тарифа на момент покупки |
| ipAddress, ruIpAddress | text | для показа (dedicated) |
| adminNotes | textarea | |
### 5.2 `connections` — Подключения
| Поле | Тип | Описание |
|---|---|---|
| key | relationship | |
| kind | select `wireguard` \| `amneziawg` \| `happ` \| `xray` \| `other` | `happ` — ссылка подписки или crypt-ссылка Happ, `xray` — ссылка `vless://` и подобные |
| title | text | «Устройство 1», «Ноутбук» |
| deviceSlot | number | номер устройства для WG/AWG |
| country | relationship → countries | для WG у mass — страна конфига; для RU-адреса — RU |
2026-10-22 03:48:10 +02:00
| isRu | checkbox | подключение к RU-адресу; у обоих брендов ([D-031 ](decisions/D-031-mass-ru-address.md )) |
2026-10-21 03:30:38 +02:00
| payload | text, зашифрованное | содержимое конфига или URL |
| fileName | text | имя файла при скачивании |
| status | select `active` \| `revoked` | |
| source | select `manual` \| `auto` | |
| createdBy | relationship → admins | |
QR-коды строятся на лету из `payload` , не хранятся.
### 5.3 Статусы ключа
| Статус | Значение |
|---|---|
2026-10-22 03:48:10 +02:00
| `provisioning` | оплачен, готовится. Срок ещё не идёт. Подключения создаёт адаптер выдачи ([D-028 ](decisions/D-028-provisioning-adapter.md )) или администратор |
2026-10-21 03:30:38 +02:00
| `active` | работает, срок идёт с `activatedAt` |
| `grace` | срок истёк, оплата не прошла, ключ ещё работает до `graceUntil` |
| `expired` | истёк, подключения отключаются |
| `cancelled` | отменён (возврат) |
| `suspended` | заблокирован администратором |
Переходы — в [04-billing.md ](04-billing.md ).
2026-10-21 16:00:32 +02:00
### 5.4 `key-extensions` — Продления без оплаты (сайт)
Реферальный бонус и «Продлить вручную» ([04-billing.md ](04-billing.md ), раздел 6.4). Только создание, как у движений по счёту.
| Поле | Тип | Описание |
|---|---|---|
| key | relationship | |
| days | number | сколько дней добавлено |
| reason | select `referral` \| `compensation` | реферальный бонус или компенсация из админки |
| referral | relationship → referrals | для `referral` |
| appliedAt | date, null | когда сдвинут срок; пусто — ключ готовится, дни добавятся при выдаче |
| expiresAtBefore, expiresAtAfter | date | срок до и после |
| comment | text | обязателен для `compensation` |
| createdBy | relationship → admins, null | null — система |
Уникальность: (`referral` , `key` ) — бонус не начисляется дважды.
2026-10-21 03:30:38 +02:00
## 6. Деньги
### 6.1 `orders` — Заказы (сайт)
| Поле | Тип | Описание |
|---|---|---|
| number | text, уникальное | `VX-7K3M9Q` |
| customer | relationship | |
| type | select `new_key` \| `renewal` | |
| tariff | relationship | |
| location | relationship | для `new_key` у dedicated |
| key | relationship | для `renewal` ; для `new_key` заполняется после оплаты |
| renewalFor | date | `expiresAt` ключа, который продлеваем; уникально вместе с `key` |
| currency, amount | | полная стоимость |
| status | select `pending` \| `paid` \| `cancelled` \| `expired` \| `refunded` \| `partially_refunded` | |
| source | select `web` \| `miniapp` \| `bot` \| `admin` \| `auto_renewal` | |
| paidAt, cancelledAt, validUntil | date | `validUntil` — неоплаченный заказ истекает через 24 часа |
| refundedAmount | number | |
| adminNotes | textarea | |
### 6.2 `payments` — Платежи (сайт)
| Поле | Тип | Описание |
|---|---|---|
| number | text, уникальное | |
| customer | relationship | |
| paymentSystem | relationship | |
| adapter | text | копия из платёжной системы |
| purpose | select `order` \| `topup` | |
| order | relationship | для `order` |
| currency, amount | | |
| status | select `pending` \| `succeeded` \| `failed` \| `cancelled` \| `refunded` \| `partially_refunded` | |
| providerPaymentId | text | уникально вместе с `adapter` |
| providerStatus, providerData | text, json | только для администраторов |
| methodSummary | group: type, brand, last4 | «Карта ···· 4242», «USDT (TRC-20)» |
| savedPaymentMethod | relationship | если карта сохранена |
| idempotencyKey | text, уникальное | |
| succeededAt, processedAt, failedAt | date | `processedAt` — цепочка действий выполнена |
| failureReason | text | |
| createdBy | relationship → admins | для ручных |
| comment | textarea | |
### 6.3 `ledger-entries` — Движения по счёту (сайт)
Только создание. Изменять и удалять нельзя никому, ошибка исправляется встречной записью.
| Поле | Тип | Описание |
|---|---|---|
| customer | relationship | |
| currency | | валюта аккаунта |
| amount | number со знаком | `+` зачисление, `− ` списание |
2026-10-22 03:48:10 +02:00
| type | select `topup` \| `order_charge` \| `refund` \| `adjustment` \| `payout` | `payout` — возврат денег с баланса на карту (этап 4b). Реферальный бонус — не деньги, а дни (5.4) |
2026-10-21 16:00:32 +02:00
| payment, order, key | relationship | источник записи |
2026-10-21 03:30:38 +02:00
| balanceAfter | number | баланс после записи |
| comment | text | обязателен для `adjustment` |
| createdBy | relationship → admins, null | null — система |
2026-10-21 16:00:32 +02:00
Уникальность: (`payment` , `topup` ), (`order` , `order_charge` ). Это защищает от двойного проведения.
2026-10-21 03:30:38 +02:00
### 6.4 `payment-methods` — Сохранённые способы оплаты (сайт)
`customer` , `paymentSystem` , `providerMethodId` (зашифрованное), `type` , `brand` , `last4` , `expMonth` , `expYear` , `isDefault` , `status` (`active` \| `detached` ), `detachedAt` .
### 6.5 `referrals` — Приглашения (сайт)
2026-10-21 16:00:32 +02:00
`referrer` , `referee` (уникальное), `status` (`pending` \| `review` \| `rewarded` \| `rejected` ), `qualifyingOrder` , `days` (копия `sites.referralBonusDays` при начислении), `refereeKey` , `referrerKey` (пусто, пока у пригласившего нет подходящего ключа: дни ждут его следующего ключа), `rewardedAt` , `rejectReason` .
2026-10-21 03:30:38 +02:00
## 7. Контент и коммуникации
### 7.1 `pages` — Страницы (сайт)
2026-10-22 04:53:15 +02:00
Страницы сайта из блоков ([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/` ), поля блоков локализованы, в текстах — подстановки `{priceFirst}` , `{priceRenewal}` , `{priceMonth}` , `{priceYear}` , `{pricePerMonth}` , `{savings}` , `{countries}` , `{devices}` :
| Блок | Секция макета |
|---|---|
| `hero` | первый экран главной: плашки, H1, две кнопки, плашка под глобусом |
| `advantages` | «Что это даёт на практике»: большая карточка, малые карточки, карточка маршрутов |
| `pricing` | цены на главной: у dedicated — выбор локации и заявка, у mass — планы «Месяц» и «Год» |
| `crossLink` | ссылка на сайт другого бренда |
| `faq` | вопросы из мест показа: одно место — список, несколько — вкладки |
| `pricingHero` | верх страницы цен: крупная цена, «Что входит» |
| `locationGrid` | сетка локаций: у dedicated с ценами и «Купить», у mass — со статусами |
| `cards` | карточки внизу страниц: текст, ссылка на другой бренд, заявка |
| `mapHero` | верх страницы локаций: H1, карта, легенда |
| `contacts` | верх поддержки: H1, Telegram и почта из настроек сайта, часы |
| `contactForm` | «Написать нам» с темами обращения |
| `richText` | текст: юридические страницы |
2026-10-21 03:30:38 +02:00
### 7.2 `faq` — Вопросы и ответы (сайт)
`question` (L), `answer` (L, rich text), `placements` (multi: `home` , `pricing` , `support_connection` , `support_billing` , `support_locations` , `cabinet` , `miniapp` ), `sort` , `active` . Один вопрос можно показать в нескольких местах.
### 7.3 `email-templates` — Шаблоны писем (сайт)
`code` (уникальное в сайте), `subject` (L), `body` (L, rich text с переменными `{{code}}` , `{{keyTitle}}` , `{{expiresAt}}` , `{{amount}}` …), `active` . Шапка и подвал письма — в коде, для каждого бренда свои.
Коды шаблонов: `login_code` , `link_email_code` , `order_paid` , `key_provisioning` , `key_ready` , `renewal_reminder` , `expiry_reminder` , `renewal_succeeded` , `renewal_failed` , `grace_started` , `key_expired` , `topup_succeeded` , `referral_reward` , `refund_issued` , `admin_new_order` , `admin_provisioning_needed` , `admin_new_lead` .
### 7.4 `leads` — Заявки (сайт)
2026-10-22 03:48:10 +02:00
Этап 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` .
2026-10-21 03:30:38 +02:00
### 7.5 `media` — Файлы
Загрузки Payload: изображения для контента, иконки платёжных систем, картинки для соцсетей.
## 8. Журналы
### 8.1 `email-log` — Журнал писем
`site` , `to` , `templateCode` , `subject` , `transport` (`smtp` \| `sendmail` \| `log_only` ), `status` (`queued` \| `sent` \| `failed` ), `error` , `messageId` , `sentAt` , `customer` , `debugCode` .
`debugCode` — код входа открытым текстом. Заполняется, только если в настройках почты включено «Записывать коды входа в журнал». Видят роли owner и admin. Записи с кодом удаляются через сутки, остальные — через `logRetentionDays` .
### 8.2 `audit-log` — Журнал действий
`actor` (администратор или система), `action` (`payment.manual` , `ledger.adjustment` , `key.activate` , `order.refund` , `customer.merge` , …), `entityType` , `entityId` , `before` , `after` , `ipHash` , `createdAt` . Только создание.
## 9. Глобальные настройки
### 9.1 `email-settings` — Почта
| Поле | Описание |
|---|---|
| transport | `smtp` \| `sendmail` \| `log_only` (только журнал, без отправки) |
| smtp | host, port, secure, user, password (зашифрованный) |
| sendmailPath | по умолчанию `/usr/sbin/sendmail` |
| logLoginCodes | «Записывать коды входа в журнал». В prod по умолчанию выключено; когда включено, в админке висит предупреждение |
| logRetentionDays | по умолчанию 30 |
| Кнопка | «Отправить тестовое письмо» на указанный адрес |
## 10. Доступ
| Коллекция | owner, admin | support | content | пользователь (через приложение) |
|---|---|---|---|---|
2026-10-21 05:08:05 +02:00
| Настройки и справочники | всё (удаление сайта — только owner) | чтение | чтение | — |
| admins | owner — всё, admin — только себя | только себя | только себя | — |
| media | всё | чтение | всё | файлы открыты всем: их показывают сайты |
2026-10-21 03:30:38 +02:00
| pages, faq, email-templates, локализация | всё | чтение | всё | — |
| customers | всё | чтение, правка заметок, блокировка | — | только свой профиль |
| keys, connections | всё | всё | — | только свои, чтение |
| orders, payments | всё | чтение, ручной платёж | — | только свои, чтение |
2026-10-21 16:00:32 +02:00
| ledger-entries, key-extensions | создание корректировок и компенсаций, чтение | чтение | — | только свои, чтение |
2026-10-21 03:30:38 +02:00
| leads | всё | всё | — | — |
| email-log, audit-log | чтение | чтение без `debugCode` | — | — |
Пользователь никогда не ходит в REST Payload напрямую: кабинет читает данные на сервере через Local API с `overrideAccess: false` и `user` .