Files
veilix.app/docs/07-frontend.md
T
andreypr207andClaude Opus 5.5 7e331c2c9d Этап 1a: фундамент
- Next 16.4 и Payload 3.91 в одном приложении, PostgreSQL с UUID,
  TypeScript 6, ESLint 9, Prettier, Vitest
- Payload: администраторы с ролями, multi-tenant по сайтам, локализация
  en/ru/de/fr/es, интерфейс админки ru/en, языки сайта (sites.locales)
- Коллекции sites, domains, currencies, countries, locations, tags,
  tariffs, payment-systems (manual), media и начальные данные (pnpm seed)
- Proxy: хост → домен, язык и валюта, внутренние маршруты по хосту;
  /admin и /api закрыты на доменах брендов
- Токены и темы брендов, оболочки сайта и кабинета, переключатели языка,
  валюты и темы, заглушки страниц
- /svc/health, юнит systemd veilix-dev.service
- Документация: решения D-022…D-024, команды в CLAUDE.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 05:08:05 +02:00

113 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 07. Фронтенд
## 1. Макеты
1. Источник — [design/handoff/project/](../design/handoff/project/), экспорт Claude Design. Прототипы на HTML: разметка внутри `<x-dc>`, логика в `<script data-dc-script>`, стили — inline плюс CSS-переменные в `<style>`. `support.js` — среда выполнения прототипа, в продукт не переносится.
2. Задача — воспроизвести внешний вид точно, читая код макетов: отступы, размеры, цвета, состояния. Внутреннюю структуру прототипа не копируем.
3. Тексты макетов — на русском, английские версии — в `i18n.js` (словарь «русская строка → английская»).
4. Бриф дизайна — `design/handoff/project/uploads/` (файл «Дизайн VEILIX.md»). Где бриф расходится с прототипами или с [01-product.md](01-product.md), верны прототипы и 01-product.
## 2. Какой макет куда
| Макет | Вейликс | ВейликсВПН |
|---|---|---|
| `Main` / `MassMain` | veilix.app `/` | veilixvpn.com `/` |
| `Price` / `MassPrice` | `/pricing` | `/pricing` |
| `Locations` / `MassLocations` | `/locations` | `/locations` |
| `Support` / `MassSupport` | `/support` | `/support` |
| `Order` / `MassOrder` | my.veilix.app `/order` | my.veilixvpn.com `/order` |
| `App` / `MassApp` | my.veilix.app: `/login`, `/`, `/keys`, `/keys/[id]`, `/buy`, `/billing`, `/referral` | то же на my.veilixvpn.com |
| `AppTG` / `MassAppTG` | tg.veilix.app (этап 3) | tg.veilixvpn.com (этап 3) |
Плюс страницы без макета: `/legal/terms`, `/legal/privacy`, `/legal/refund`, `/legal/cookies`, 404 и 500 — в стиле сайта.
## 3. Маршруты кабинета
| Путь | Что |
|---|---|
| `/login` | вход по коду |
| `/` | главная: ключи, «Купить ключ», FAQ |
| `/keys`, `/keys/[id]` | список ключей, страница ключа: срок, автопродление, «Продлить сейчас», WG-конфиги (скачать, QR), ссылка Happ/Xray (копировать, QR) |
| `/buy` | покупка внутри кабинета: dedicated — сетка локаций с ценами, mass — «Месяц» и «Год» |
| `/order` | оформление заказа: шаги «Почта» и «Оплата», сводка |
| `/billing` | баланс, пополнение, карта, ближайшие списания, история |
| `/referral` | реферальная программа |
| `/more` | вкладка «Ещё» на узком экране: счёт, рефералы, поддержка, тема, язык |
| `/r/[код]` | реферальная ссылка: ставит cookie и ведёт на сайт бренда |
Навигация по макету: на широком экране — боковая панель, на узком — плавающая панель вкладок «Главная, Ключи, Купить, Ещё».
## 4. Темы и токены
1. Tailwind v4: токены макета — CSS-переменные, подключённые в `@theme`. Бренд задаёт атрибут `data-site="dedicated|mass"` на `<html>`, тему — `data-theme="light|dark"`. Режим «Как в системе» следует `prefers-color-scheme`.
2. Переключатель темы — 3 режима, как в макете. Выбор хранится в localStorage (ключ `vx_theme`), тема применяется скриптом в `<head>` до отрисовки. Новый посетитель видит «Как в системе». localStorage у каждого хоста свой: тема, выбранная на сайте, не переходит в кабинет.
3. Токены в OKLCH, как в макете. Ниже — для ориентира; точные значения — в `<style>` прототипов, при расхождении верен прототип.
| Токен | Вейликс светлая | Вейликс тёмная | ВейликсВПН светлая | ВейликсВПН тёмная |
|---|---|---|---|---|
| `--bg` | 99% .005 296 (#fcfbff) | 17% .022 296 (#100d18) | 99.6% .0015 215 | 23% .026 210 |
| `--surface` | 100% 0 0 | 21% .026 296 | 100% 0 0 | 26.5% .028 210 |
| `--surface-2` | 97.5% .01 296 | 24% .03 296 | 98.4% .003 215 | 30% .03 210 |
| `--ink` | 24% .04 296 (#211b30) | 96% .01 296 | 24% .04 204 | 96% .012 196 |
| `--ink-2` | 45% .03 296 | 79% .02 296 | 45% .03 204 | 80% .02 196 |
| `--ink-3` | 60% .025 296 | 63% .025 296 | 60% .025 204 | 65% .025 196 |
| `--border` | 92% .014 296 | 31% .032 296 | 92% .014 200 | 36% .04 204 |
| `--accent` | 45% .17 296 (#6137a6) | 74% .15 296 (#b495fe) | 48% .105 178 (#00705e) | 76% .105 190 (#52c6c0) |
| `--accent-hover` | 38% .17 296 | 80% .13 296 | 41% .1 178 | 83% .09 190 |
| `--accent-soft` | 95.5% .028 296 | 27% .05 296 | 95.5% .032 180 | 31% .05 190 |
| `--on-accent` | 99% .01 296 | 17% .03 296 | 99% .01 180 | 20% .04 204 |
| `--glow-1/2/3` | 86% .1 296 / 89% .09 266 / 91% .08 332 | 45% / 40% / 42% | 86% .085 190 / 88% .075 205 / 89% .07 172 | 52% .09 200 / 47% .085 215 / 50% .08 180 |
| `--sel` | — | — | 96.5% .016 190 | 30% .03 195 |
Общие для брендов: `--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.
## 5. Шрифты, иконки, логотип
1. Commissioner 300–600 — весь текст; Unbounded 600 — только надпись логотипа. Подключение через `next/font`: файлы скачиваются при сборке и отдаются с нашего домена, без запросов к Google Fonts. Наборы символов: latin, latin-ext, cyrillic.
2. Иконки, флаги и логотип в макете нарисованы CSS-фигурами. Переносим их React-компонентами, сохраняя вид.
3. Логотип — вариант «Слои». Фавиконы — `favicon.svg` и `favicon-mass.svg` из макета.
## 6. Карта мира
1. В макете карта строится в браузере через d3 и topojson с загрузкой данных с CDN. В продукте SVG-карта рендерится на сервере при сборке: d3-geo, проекция Natural Earth, данные `world-atlas` (countries-110m) из npm.
2. В браузере — только интерактив: подсветка, всплывающая карточка, синхронизация с сеткой локаций.
3. На узком экране карта прокручивается горизонтально, как в макете.
## 7. Решения по расхождениям в макетах
1. Устройств — 5, это поле тарифа. Цена продления dedicated — 2 499 ₽, цены задаются тарифами (3 уровня).
2. Оформление заказа получает тариф, локацию и валюту из ссылки. В макете там всегда Нидерланды и 4 900 ₽.
3. Поля номера карты из макета `Order` не делаем: карта вводится в виджете провайдера (этап 4). На этапе 1 платёжных систем для пользователя нет ([04-billing.md](04-billing.md), раздел 3.6).
4. Mass: в кабинете «Список ключей», без «текущей/запасной локации» и без экрана смены страны. Внутри ключа — ссылка Xray и WG-конфиги по странам.
5. Статус локации показываем везде одинаково: в списках, карточках и на карте.
6. Кнопка «Получить VPN» на главной ведёт к блоку цен на этой же странице, на остальных страницах — на `/pricing`.
7. FAQ — одна коллекция с местами показа: главная, цены, поддержка (3 раздела), кабинет, MiniApp.
8. Контакты поддержки берутся из настроек сайта, Telegram — ссылка на бота поддержки.
9. Плашки способов оплаты в подвале — по активным платёжным системам сайта.
10. Добавляем то, чего нет в макете: переключатель валюты, `<title>` и мета-описания, H1 на каждой странице, поддержку `prefers-reduced-motion` для анимаций.
11. Показывать ли на сайте количество свободных серверов (в MiniApp макет его показывает) — решаем на этапе 1b. По умолчанию — только статус.
12. Переключатели при 5 языках и с валютой (в макете только RU/EN, валюты нет). В шапке — выпадающие списки языка и валюты. В подвале, мобильном меню и кабинете — сегменты с кодами языков (EN RU DE FR ES) и символами валют (₽ $). В оболочке кабинета валюты нет: она появится в настройках (1f).
13. В подвале четыре документа: добавлена «Политика cookies». Плашек способов оплаты нет, пока нет видимых пользователю платёжных систем (пункт 9).
14. Кабинет mass: подписи навигации те же, что у dedicated («Список ключей», «Купить ключ», «Ключи»). Подписи макета MassApp («Подключения», «Выбрать страну», «Подписка») не используем (пункт 4).
15. Ширина надписи логотипа — по содержимому: в макете она подогнана под русское название.
16. 404. При `notFound()` Next 16 отдаёт пустую оболочку (`<html id="__next_error__">`), а страница 404 в оформлении бренда отрисовывается в браузере; статус ответа — 404. Серверную отрисовку 404 и 500 решаем на этапе 1b вместе с их оформлением: вариант — `global-not-found.js`.
## 8. Состояния, которых нет в макетах
Рисуем в стиле макета на соответствующих этапах:
1. Вход: ошибка кода, истёкший код, таймер повторной отправки, загрузка.
2. Ключ: готовится (до 24 часов), льготный период, истёк, заблокирован; пустой список ключей; ключ без подключений.
3. Заказ: «ожидает оплаты» (этап 1), не хватает баланса, оплата не прошла; 3-D Secure и счёт в криптовалюте — этап 4.
4. Счёт: своя сумма пополнения, подтверждение отвязки карты, результат пополнения.
5. Общие: уведомления (тосты), скелетоны загрузки, страницы 404 и 500, ошибки валидации форм.
## 9. Производительность и доступность
1. Маркетинговые страницы: Lighthouse mobile ≥ 90 (цель 95+), LCP ≤ 2 с, CLS ≤ 0.05, INP ≤ 200 мс.
2. JavaScript в браузере — только интерактивные островки: переключатели языка, валюты и темы, FAQ, выбор локации, формы, карта.
3. Сторонние скрипты при первой загрузке — только Umami (асинхронно). ALTCHA подгружается только на формах.
4. Доступность — WCAG 2.1 AA: контраст, видимый фокус, работа с клавиатуры для выпадающих списков, аккордеонов и шитов, области нажатия ≥ 44 px.