Files
transcriber/openspec/changes/archive/2026-08-15-spa-skeleton/tasks.md
T
av 663021f712 приложение собрано каркасом и вшито в бинарник
- заведён каталог web/ — Vue 3, роутер пятой версии, сборка Vite; собранное
  вшивается через go:embed и раздаётся корневым маршрутом: разметка на
  неизвестном пути вне корней сервиса, отказ контракта внутри корня
- перечень корней сервиса стал единой точкой и порождает регистрацию маршрутов,
  а не описывает её; журнал раздачи пишет исход и длину пути, но не сам путь
- шаг front зовёт Node контейнером docker — Biome, юнит-тесты Vue и сборка
  входят в гейт, а в Dockerfile появилась ступень приложения
2026-08-15 18:51:05 +03:00

14 KiB
Raw Blame History

1. Каталог приложения и его сборка

  • 1.1 Завести web/ с package.json, файлом замка, настройкой Vite и index.html; выходной каталог сборщика — web/embed/dist
  • 1.2 Команда сборки приложения гоняет проверку типов и сборку одним вызовом (vue-tsc входит в команду сборки, а не стоит отдельным шагом)
  • 1.3 В git лежит web/embed/.gitkeep — этажом выше выходного каталога, чтобы очистка перед сборкой его не уносила; собранное и каталог зависимостей внесены в .gitignore
  • 1.4 Написан экран-заглушка: показывает имя вошедшего, на 401 ведёт ко входу, на прочий отказ показывает строку о неудаче; одна таблица маршрутов через createRouter, адреса обычные (createWebHistory)
  • 1.5 Обращение к API идёт через одну свою обёртку над fetch; она же единственное место, где читается код ответа
  • 1.6 Заведён Biome: форматирование и статический анализ кода приложения. Не покрывает разметку однофайловых компонентов — сказать строкой и остановиться, замена инструмента решается человеком
  • 1.7 Заведены юнит-тесты Vue: показ вошедшего, увод ко входу на 401, строка о неудаче на прочем отказе, учётная запись без имени

2. Раздача приложения из бинарника

  • 2.1 web/embed.go вшивает web/embed целиком (all:), включая метку пустого каталога
  • 2.2 Перечень корней сервиса заведён единой точкой в пакете транспорта: /api, /app, /auth, /_ и отдельные адреса /health, /metrics
  • 2.2.1 Наши маршруты вешаются из перечня: проба здоровья, метрики, группа приложения, группа входа. Корни библиотеки остаются её литералами и держатся своим тестом; второе перечисление адресов наблюдения в уровне журнала снято
  • 2.3 Принадлежность корню — точное совпадение либо префикс вместе с косой чертой; оба условия проверяются
  • 2.4 Обработчик приложения зарегистрирован маршрутом / (тем самым занимает место библиотечного отказа) и принимает файловую систему параметром
  • 2.5 Порядок обработчика: корень сервиса или адрес наблюдения — отказ формой библиотеки; метод не GET и не HEAD405; несовпавший путь под каталогом ресурсов — 404; совпавший файл — файл; прочее — разметка
  • 2.6 Заголовки кэширования назначены по каталогу: ресурсы сборщика — год и «неизменяемо», всё прочее, включая разметку, — спрашивать заново
  • 2.7 Отсутствие собранного приложения даёт 503 с честной страницей и строку в журнале при подъёме, а не 404 молча; проба здоровья остаётся зелёной
  • 2.8 При подъёме в журнал уходит отпечаток вшитой разметки
  • 2.9 Строка журнала корневого маршрута несёт исход и длину пути, но не сам путь
  • 2.10 Разметка и ресурсы отдаются без сессии; адреса данных под корнем приложения сессии по-прежнему требуют

3. Сборка и выкладка

  • 3.1 Шаг сборки приложения заведён в Taskfile.yml и стоит первым в наборе проверок, до сборки Go; рядом — шаги Biome и юнит-тестов приложения
  • 3.1.1 Проверки приложения гоняются тем же контейнером, что и сборка; второго окружения не заводится
  • 3.2 Шаг зовёт установщик и сборщик контейнером, а не из PATH: имя образа берётся из Dockerfile, контейнер ходит под вызвавшим пользователем, кэш установщика уведён в каталог под /tmp
  • 3.3 Зависимости ставятся из файла замка командой, которая его не правит; ту же команду зовёт ступень Dockerfile
  • 3.4 Недостающий docker и отказ сети или реестра — отказ окружения, код 3; красная сборка приложения — код 1
  • 3.5 В Dockerfile добавлена ступень сборки приложения перед сборкой бинарника; в рабочий слой Node не попадает
  • 3.6 Вес выяснен, время замера снято с задачи решением владельца 2026-08-15: финальный образ от ступени приложения не растёт вовсе (Node в него не копируется), вшитое добавляет к бинарнику 86 072 байта. Время сборки остаётся неизвестным сознательно
  • 3.7 Последствие ADR-2026-08-11-spa-on-vue поправлено: требованием к машине разработчика становится docker, а не Node

4. Проверки

  • 4.1 Тест: неизвестный путь вне корней отдаёт разметку с кодом 200
  • 4.2 Тест: неизвестный путь под каждым корнем сервиса разметки не отдаёт
  • 4.3 Тест: голый корень без косой черты разметки не отдаёт, а посторонний путь, начинающийся именем корня без косой черты, — отдаёт
  • 4.4 Тест: неизвестный путь под корнем приложения отвечает 404 с сессией и 401 без неё
  • 4.5 Тест: несуществующий файл под каталогом ресурсов отвечает 404
  • 4.6 Тест: проба здоровья и метрики приложением не подменяются
  • 4.7 Тест: чужой метод отвечает 405, а HEAD на разметку — 200
  • 4.8 Тест: разметка и ресурс отдаются без сессии, а список записей — нет
  • 4.9 Тест: у разметки стоит требование спрашивать заново, у ресурса из каталога сборщика — год и «неизменяемо»
  • 4.10 Тест: пустая сборка даёт 503, а не 404, и проба здоровья при этом зелёная
  • 4.11 Юнит-тесты приложения краснеют на сломанном экране: намеренная поломка показа вошедшего роняет набор проверок
  • 4.12 task gate зелёный целиком

5. Документы

  • 5.1 docs/conventions/web-ui.md — снята оговорка «кода приложения ещё нет»; дописаны правила: отпечаток в именах ресурсов, несовпавший ресурс отвечает 404, зависимости ставятся из файла замка
  • 5.2 docs/architecture.md — компонент приложения, внешняя зависимость сборки, новая capability и перечень корней в единых точках
  • 5.3 docs/database.md — срок хранения ресурсов в настройках с числовым значением
  • 5.4 CLAUDE.md — команды и требования к машине разработчика, состав гейта вместе с проверками приложения, второй сетезависимый шаг названный поимённо
  • 5.5 docs/review.md — заведён род узла «раздача собранной статики и шаг сборки приложения» в типовых узлах
  • 5.6 docs/conventions/go-linters.md либо соседняя запись — чем проверяется код приложения: Biome и юнит-тесты, что каждый ловит и где настроен

Критерии приёмки

Дословно из записи задачи spa-skeleton:

  • Статика собирается одной командой и вшивается в бинарник: запущенный бинарник отдаёт приложение без каталога рядом. Оракул — сборка, запуск бинарника из пустого каталога, запрос корня возвращает разметку приложения.
  • Образ собирается на чистой машине без предустановленного окружения фронтенда. Оракул — task image без локально установленных зависимостей фронтенда.
  • Приложение показывает, кто вошёл, и обращается к API живого сервера. Оракул — тест либо ручная проверка на запущенном сервере с сессией.
  • Шаг сборки статики входит в task gate и краснеет при ошибке сборки. Оракул — намеренно сломанный исходник роняет task gate.
  • Обновление страницы на любом маршруте приложения открывает тот же экран, а адрес внутри корня сервиса в приложение не проваливается. Оракул — тест на три запроса: неизвестный путь вне корней отдаёт разметку, неизвестный путь внутри /api/ и внутри /app/ отдаёт ошибку контракта.

Рубрика ревью дизайна, тем же списком:

  • Перечень корней живёт одной точкой, и добавление корня не требует правки в двух местах.
  • Запрос несуществующего файла под каталогом ресурсов отвечает 404, а не разметкой с 200.
  • После прогона сборки приложения git status чист по web/.
  • После task gate git status чист по файлу замка зависимостей.
  • Отсутствие сборки громкое: код ответа, страница и строка журнала; «сборки нет» отличается от «файла нет».
  • Долгий неотзываемый срок ставится только файлу из каталога ресурсов сборщика.
  • Разметка и ресурсы отдаются анонимно, данные под корнем приложения — нет; по анонимному ответу нельзя узнать, вошёл ли кто-то.
  • В бинарник попадает только собранное: ни карт исходников, ни каталога зависимостей, ни файлов вне выходного каталога.
  • Отпечаток вшитой сборки виден строкой журнала при подъёме.
  • Шаг сборки следует словарю кодов: недостающий инструмент и отказ сети — 3, красная сборка — 1; молчаливого пропуска нет.
  • Ступень сборки не протекает в рабочий слой образа, а версия сборочного окружения объявлена одним местом.
  • Файловая система строится один раз, а не на каждый запрос; поведение на HEAD определено.
  • Запрос на путь длиной в килобайт не добавляет значения ни метке метрики, ни строке журнала.