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

- заведён каталог 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,62 @@
# Node зовётся контейнером, а не ставится на машину разработчика
- **Дата:** 2026-08-15
- **Источник:** [../../openspec/changes/archive/2026-08-15-spa-skeleton/design.md](../../openspec/changes/archive/2026-08-15-spa-skeleton/design.md),
раздел «Node не ставится на машину, а зовётся контейнером»
## Решение
Шаг сборки приложения гоняет установщик пакетов и сборщик **внутри контейнера**,
а не вызывает их из `PATH`:
> Требованием к машине разработчика становится docker, которым и так собирается
> образ, — второго устанавливаемого окружения сверх `ffmpeg` не появляется
> вовсе.
Образ сборочного окружения берётся из ступени `Dockerfile`, а не объявляется
вторым числом в `Taskfile.yml`.
## Почему
Довод в дизайне назван прямо:
> Так снимается расхождение, которое иначе завелось бы молча: версия Node на
> машине разработчика и версия в образе — два разных числа, и собранное ими
> приложение различается ровно тогда, когда различаются они.
Отвергнуты два очевидных подхода, и оба с названной ценой. **Поставить Node на
машину** — вводит второе устанавливаемое окружение и разъезжается с версией в
образе. **Дать выбор — контейнер или локальный Node** — это второй способ делать
одно и то же, и собранное ими различалось бы в зависимости от того, у кого что
стоит.
## Почему это ADR
Запись проходит триггер **намеренным отказом** от очевидного подхода: поставить
Node на машину — ровно то, что делают по умолчанию, и отказ от этого надо
объяснить один раз, а не на каждом вопросе «почему у нас нельзя просто
`npm run build`».
## Что это меняет в прежнем решении
[ADR-2026-08-11-spa-on-vue](ADR-2026-08-11-spa-on-vue.md) записал последствием,
что «машина разработчика получает второе требуемое окружение сверх `ffmpeg`», и
подразумевал под ним Node. Окружением оказался **docker**. Сам выбор фреймворка и
наличие шага сборки это не пересматривает, поэтому статуса «заменено на» у той
записи нет: заменена не она, а толкование одного её последствия.
## Последствия
- `+` версия сборочного окружения живёт **одним** местом — ступенью
`Dockerfile`, — и своего шага сверки ей не нужно.
- `+` собранное в наборе проверок и собранное в образе совпадает, потому что
совпадает окружение сборки, а не потому что «обычно совпадает».
- `` **набор проверок перестаёт работать без docker**, и отказ этот приходит
кодом окружения. Тем же кодом приходит отказ реестра пакетов: сетезависимых
шагов в наборе становится два вместо одного.
- `` контейнер ходит под тем же пользователем, что и вызвавший, а кэш
установщика уводится наружу — обе частности обязательны: без них собранное
ляжет от `root`, а зависимости будут тянуться заново каждый прогон.
- `` **вес и время самой ступени в образе неизвестны**: финальный образ от неё
не растёт (ступень в рабочий слой не копируется), а время сборки решением
владельца от 2026-08-15 не замеряется вовсе.
+1
View File
@@ -35,6 +35,7 @@
| Дата | Запись | Статус |
| --- | --- | --- |
| 2026-08-15 | [Node зовётся контейнером, а не ставится на машину разработчика](ADR-2026-08-15-node-in-container-not-on-machine.md) | |
| 2026-08-15 | [Приложение живёт своим пространством адресов, а не общим с хранилищем](ADR-2026-08-15-app-namespace.md) | |
| 2026-08-15 | [Страница архива задаётся ключом, а не номером](ADR-2026-08-15-cursor-paging.md) | |
| 2026-08-15 | [Длительность и размер — снимок принятого колонками записи](ADR-2026-08-15-record-snapshot-columns.md) | |