приложение собрано каркасом и вшито в бинарник

- заведён каталог web/ — Vue 3, роутер пятой версии, сборка Vite; собранное
  вшивается через go:embed и раздаётся корневым маршрутом: разметка на
  неизвестном пути вне корней сервиса, отказ контракта внутри корня
- перечень корней сервиса стал единой точкой и порождает регистрацию маршрутов,
  а не описывает её; журнал раздачи пишет исход и длину пути, но не сам путь
- шаг front зовёт Node контейнером docker — Biome, юнит-тесты Vue и сборка
  входят в гейт, а в Dockerfile появилась ступень приложения
This commit is contained in:
av
2026-08-15 18:51:05 +03:00
parent c6ffda9aac
commit 663021f712
46 changed files with 5958 additions and 43 deletions
@@ -0,0 +1,56 @@
## Why
Сервис отдаёт данные, но человеку их показать нечем: экранов нет вовсе, а
браузер, открывший адрес сервиса, получает поверхность хранилища вместо
приложения. Два основных сценария паспорта — «семейный архив» и «возвращение к
записи» — не работают ни один, и упираются они в одно: приложения не существует.
Каркас сам по себе экранов не приносит. Он приносит то, на чём они стоят:
собранное приложение, которое сервис отдаёт браузером, открывается по любому
своему адресу и показывает вошедшего, спросив об этом сервис.
## What Changes
- Сервис начинает отдавать браузеру **приложение**: разметку и её ресурсы. Они
лежат внутри самого бинарника, отдельного каталога рядом с ним не требуется, и
внешнего веб-сервера под них не заводится.
- Неизвестный адрес **вне корней сервиса** отдаёт разметку приложения, а не
отказ. Так обновление страницы посреди приложения открывает тот же экран, а не
ошибку. Корни перечислены поимённо, и адрес **внутри** корня в приложение не
проваливается никогда: отказ контракта остаётся отказом контракта.
- Разметка и её ресурсы отдаются **без сессии**: приложение само спрашивает
сервис, кто вошёл, и уводит ко входу, когда не вошёл никто. Требование сессии
на самой разметке отдавало бы отказ вместо экрана входа.
- Открытое приложение показывает **вошедшего** — то, что сервис ответил о нём, —
и это единственное, что оно сегодня показывает.
- В сборку приходит **шаг сборки приложения**: он входит в набор проверок и в
сборку образа. Спеками это не нормируется — у сборки другой потребитель, тот,
кто собирает.
## Capabilities
### New Capabilities
- `webapp`: приложение в браузере — чем сервис его отдаёт, каким адресом оно
открывается, что делает обновление страницы посреди приложения и что человек
видит, открыв его.
### Modified Capabilities
- `access`: разметка приложения и её ресурсы пополняют перечень адресов,
открытых без сессии; сегодня в нём только проба здоровья и метрики.
## Impact
- новый каталог приложения: исходники, зависимости, настройка сборки;
- `internal/controller/http` — маршрут, отдающий разметку на неизвестном пути вне
корней, и раздача ресурсов приложения из бинарника;
- `Taskfile.yml` — шаг сборки приложения, его место в наборе проверок и в сборке
образа;
- `Dockerfile` — приложение собирается внутри образа, чтобы выкладка не зависела
от машины разработчика;
- `.gitignore` — каталог зависимостей и собранное приложение;
- новая внешняя зависимость сборки: Node и его установщик пакетов. На машину
разработчика они не ставятся — шаг сборки зовёт их контейнером, поэтому
требованием к машине становится docker, которым и так собирается образ;
- `docs/conventions/web-ui.md` и `docs/architecture.md` — правила кода
приложения перестают быть выведенными из выбора, а компонент и зависимость
сборки появляются в описании устройства.