Files
HY2XS_flamy/docs/architecture/01-architecture-baseline.md
founder c0a43ae915 fix(admin): закрыть обещания панели, которые продукт не выполнял
Девятый проход, по итогам приёмки v1.0.0-rc1 на живом Debian 13. Общая тема:
интерфейс обещал оператору то, что продукт умел, но до чего не доходило
управление.

Секрет пира. Подпись под полем предлагала оставить его пустым, сервер умел его
сгенерировать, и генерация была недостижима: в go-playground/validator тег
omitempty НЕ пропускает правило, если поле объявлено указателем и указатель не
nil — hasValue считает указатель на пустую строку «значением». Правило min=6
применялось к пустой строке и отказывало. Ловушка закрыта общим шагом
нормализации DTO, а не тегом на одном поле: та же ловушка ломала фильтр списка
пиров, где очищенный крестиком el-input отправляет `?name=`. Граница проходит по
каждому полю отдельно — у remark пустая строка означает «убрать пометку», у
disabled ноль означает «включён».

Отказы. Любая ошибка любого поля превращалась в слово `invalid`, а слой vo
определял код ответа СРАВНЕНИЕМ текста сообщения — тот же антипаттерн, который
запрещён панели, только на сервере. Ответ несёт errors[{code, field, message,
params}]; панель выбирает фразу по коду и подставляет причины под поля.

Сессия. Ветка «войдите заново» была недостижима дважды: сервер отвечает HTTP 200
на любой отказ, поэтому обработчик ошибок axios не вызывался, а условие в нём
проверяло code === "A0230" и поле msg, которых в этом API никогда не было.
Истёкший токен вдобавок уезжал с кодом системной ошибки.

Иконки. Контракт currentColor был объявлен в двух местах и не действовал: восемь
ассетов несли литеральный fill="#000000" на <path>, а атрибут представления
перебивает унаследованное CSS-свойство. Под это попадали все семь иконок
бокового меню на фоне #181818.

Имя пира. Два правила на одном поле противоречили друг другу (min=1 против
6-32), а копия набора символов в слое контроллеров несла неэкранированный дефис
и впускала `, - . / : ; <` — через панель проходило имя peer/name, которое
импорт того же пира отклонял. Набор символов ЛОГИНА сознательно не сужен и
закреплён тестом: он приходит из HY2XS_ADMIN_USER и оркестратором не
ограничивается.

Добавлены подпись «Разработано во Flamy» с адресом, принадлежащим приложению, и
контрактные тесты панели как обязательный шаг сборки. Их исполняет Bun, а не
vitest: jsdom не вычисляет currentColor и визуальной корректности не доказал бы,
зато vitest привёл бы в граф pnpm audit сотню транзитивных зависимостей.

docs/ разложена по слоям, 11-testing-and-acceptance.md (117 КБ) разбит на пять
частей, добавлен docs/acceptance/ с отчётом о прогоне rc1 и перечнем дефектов.
Обход документации в приёмке стал рекурсивным: плоский docs/*.md после
разнесения по каталогам совпадал бы ровно с одним файлом.
2026-09-01 07:27:15 +05:00

139 lines
6.2 KiB
Markdown
Raw Permalink 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.
# Architecture baseline
## Цель
Зафиксировать одну непротиворечивую схему без смешивания локальной сборки, серверной установки и внешнего access layer.
## Два слоя системы
### 1. Builder layer
Запускается **только локально**, на отдельной машине разработчика / оператора.
Функции:
- хранение исходников проекта
- хранение и сопровождение исходного кода **HY2XS admin**
- хранение исходников оркестратора на **Bun + TypeScript**
- компиляция install-артефакта оркестратора
- подготовка install package
- упаковка unit-файлов, шаблонов конфигов и документации
- контроль версии проекта как целого
Builder layer **не разворачивается на сервере**.
### 2. Runtime / target layer
Запускается **только на чистом Debian 13**.
Функции:
- установка системных зависимостей
- разворачивание файлов пакета
- скачивание **свежей Hysteria2 из официального upstream**
- создание server config
- установка и запуск **встроенного HY2XS admin**
- создание systemd unit-файлов
- применение nftables baseline
- создание `post-install.env`
Target layer **не содержит сборщика** и **не выполняет target-side build**.
## Компоненты baseline
### Серверный транспорт
- **Hysteria2**
- QUIC/UDP
- один фиксированный UDP-порт
- `Gecko` включён по умолчанию, `Salamander` доступен как режим совместимости
- IPv4-only
- лимит по умолчанию: 50/50 Mbps на клиента
- fallback congestion controller: BBR (профиль `standard`)
### UI слой
- **HY2XS admin** — штатный компонент проекта
- поставляется внутри проекта
- устанавливается локально из итогового пакета
- не скачивается с upstream на сервере
### Orchestrator слой
- **Bun + TypeScript**
- собирается локально builder layer'ом
- попадает на target как готовый install-артефакт
- не требует `npm/pnpm/yarn/bun install` на сервере
### Server ops слой
- systemd
- nftables
- `post-install.env`
## Принципы
### 1. Ядро, UI и оркестратор ведут себя по-разному
- Hysteria2: последнюю стабильную upstream-версию выбирает **сборка пакета**, установка ставит уже замороженный артефакт
- HY2XS admin: разрабатываем **внутри проекта** и поставляем его сами
- Оркестратор: пишем на **Bun + TypeScript**, но собираем **локально**, а не на target
### 2. Builder и target не смешиваются
Сборка — локально.
Установка — на сервере.
На сервере не должно быть логики «собери мне UI» или «собери мне TypeScript оркестратор».
### 3. Оркестратор install/reconfigure-only
Оркестратор умеет только:
- установить
- применить явную реконфигурацию из runtime env
- разложить файлы
- создать базовую конфигурацию
- подготовить сервер к работе
Он **не** умеет:
- обновлять уже установленную систему
- откатывать версии
- удалять установку
- чинить неизвестные поломанные старые состояния
### 4. Access layer вынесен за рамки baseline
Telegram-бот, backend выдачи ключей, remote profile publishing, billing и похожие пользовательские контуры не входят в этот baseline.
## Что входит в baseline
1. local builder
2. install package
3. vanilla Hysteria2 from upstream
4. bundled HY2XS admin
5. Bun/TypeScript install-only orchestrator
6. systemd + nftables
7. post-install env
8. install-only flow под чистый Debian 13
## Что не входит в baseline
- target-side builder
- target-side git clone нашего UI
- target-side `bun install` / transpile / compile
- Telegram-бот
- backend выдачи remote profiles
- standalone update / rollback / uninstall subcommands
При этом в install/reconfigure допускается bounded rollback для failure-сценариев firewall/systemd/config/smoke.
- Docker как основной способ поставки
- multi-node deployment
- сложный control plane
## Финальный результат
Правильный baseline-результат выглядит так:
1. На локальной машине собирается install package.
2. В пакет уже встроены наш HY2XS admin и install-артефакт оркестратора.
3. Пакет переносится на чистый Debian 13.
4. На сервере запускается только install-only orchestration.
5. Сервер скачивает свежую Hysteria2 из official upstream.
6. Сервер разворачивает bundled UI из пакета.
7. Создаются systemd unit-файлы, firewall baseline и `post-install.env`.
8. Сервер готов как базовое рабочее окружение HY2XS.
## Runtime policy
- editable слой: `/etc/hy2xs/hy2xs.env` (0600)
- snapshot слой: `/etc/hysteria/post-install.env` (0600)
- изменения runtime применяются только через явный `reconfigure --dry-run/--apply`
- IPv6 out of scope: все bind/listen только IPv4