From f9ac83bef8741b6a5dc9b33686bb93f245c90d62 Mon Sep 17 00:00:00 2001 From: Yuriy Mayatnikov Date: Mon, 24 Aug 2026 11:23:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D0=B2=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=BE=D0=BC=D0=B5=D1=80=D0=B0=20ADR:=20064/065/?= =?UTF-8?q?066=20=D1=8D=D1=82=D0=BE=D0=B9=20=D0=B2=D0=B5=D1=82=D0=BA=D0=B8?= =?UTF-8?q?=20=E2=86=92=20073/074/075?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ветка отведена от 522ba89, где последним был ADR-063, и заняла 064–072. Тем временем в main через #3 и #4 пришли свои 064 (строка ввода — div вместо form), 065 (стороны сообщений) и 066 (серверного перца нет). Переезжают три ADR этой ветки, 067–072 остаются на месте: их номера свободны, а внутренние ссылки менять незачем. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QR8uS3zGkybzWRW4GEY1oz --- cmd/bare/main.go | 2 +- docs/decisions/022-deploy-nginx-systemd.md | 2 +- docs/decisions/024-identity-and-ui.md | 2 +- docs/decisions/047-push-endpoint.md | 2 +- docs/decisions/057-version-marks-dirty-tree.md | 2 +- docs/decisions/067-version-in-sidebar-foot.md | 8 ++++---- docs/decisions/069-message-input-is-editable-block.md | 4 ++-- ...son-in-log.md => 073-push-failure-reason-in-log.md} | 2 +- ...d-commit-time.md => 074-version-and-commit-time.md} | 2 +- ...066-no-zoom-app-feel.md => 075-no-zoom-app-feel.md} | 2 +- docs/deploy.md | 4 ++-- docs/identity/brief.md | 4 ++-- docs/plan.md | 4 ++-- docs/protocol.md | 2 +- docs/ui.md | 4 ++-- internal/api/account.go | 2 +- internal/api/account_test.go | 2 +- internal/build/build.go | 2 +- internal/build/build_test.go | 2 +- internal/push/push.go | 8 ++++---- internal/push/push_test.go | 4 ++-- web/app.css | 10 +++++----- web/js/main.js | 2 +- web/js/ui/shell.js | 2 +- web/js/zoom.js | 2 +- 25 files changed, 41 insertions(+), 41 deletions(-) rename docs/decisions/{064-push-failure-reason-in-log.md => 073-push-failure-reason-in-log.md} (98%) rename docs/decisions/{065-version-and-commit-time.md => 074-version-and-commit-time.md} (98%) rename docs/decisions/{066-no-zoom-app-feel.md => 075-no-zoom-app-feel.md} (99%) diff --git a/cmd/bare/main.go b/cmd/bare/main.go index d328a0c..95e6577 100644 --- a/cmd/bare/main.go +++ b/cmd/bare/main.go @@ -162,7 +162,7 @@ func vapid() error { // version печатает, какой код собран в этот бинарь: короткую ревизию // и время коммита. Время коммита, а не компиляции: штамп момента сборки // делал бы каждую пересборку одного коммита новым файлом, и сверка хеша -// со сборкой из тега перестала бы что-либо значить (ADR-022, ADR-065). +// со сборкой из тега перестала бы что-либо значить (ADR-022, ADR-074). // Ревизию, которой нет, и время, которого нет, бинарь не выдумывает // (ADR-057). func version() { diff --git a/docs/decisions/022-deploy-nginx-systemd.md b/docs/decisions/022-deploy-nginx-systemd.md index a62b8d5..1f8e300 100644 --- a/docs/decisions/022-deploy-nginx-systemd.md +++ b/docs/decisions/022-deploy-nginx-systemd.md @@ -1,6 +1,6 @@ # ADR-022: Деплой — nginx, systemd, кросс-сборка -Уточнён [ADR-032](032-state-permissions.md) (`StateDirectoryMode` и `UMask` в юните), [ADR-056](056-nginx-access-log-off.md) (`access_log off`), [ADR-057](057-version-marks-dirty-tree.md) (`bare version` помечает сборку из изменённого дерева) и [ADR-065](065-version-and-commit-time.md) (версия и время коммита в `GET /api/config`, времени компиляции в бинаре нет). +Уточнён [ADR-032](032-state-permissions.md) (`StateDirectoryMode` и `UMask` в юните), [ADR-056](056-nginx-access-log-off.md) (`access_log off`), [ADR-057](057-version-marks-dirty-tree.md) (`bare version` помечает сборку из изменённого дерева) и [ADR-074](074-version-and-commit-time.md) (версия и время коммита в `GET /api/config`, времени компиляции в бинаре нет). ## Контекст diff --git a/docs/decisions/024-identity-and-ui.md b/docs/decisions/024-identity-and-ui.md index 8574216..036f93e 100644 --- a/docs/decisions/024-identity-and-ui.md +++ b/docs/decisions/024-identity-and-ui.md @@ -1,6 +1,6 @@ # ADR-024: Айдентика «Скобы», интерфейс и язык -Уточнён [ADR-066](066-no-zoom-app-feel.md) (масштабирование запрещено, размеры шрифтов прежние), [ADR-067](067-version-in-sidebar-foot.md) (версия и время коммита в подвале сайдбара) и [ADR-069](069-message-input-is-editable-block.md) (строка сообщения — редактируемый блок). +Уточнён [ADR-075](075-no-zoom-app-feel.md) (масштабирование запрещено, размеры шрифтов прежние), [ADR-067](067-version-in-sidebar-foot.md) (версия и время коммита в подвале сайдбара) и [ADR-069](069-message-input-is-editable-block.md) (строка сообщения — редактируемый блок). ## Контекст diff --git a/docs/decisions/047-push-endpoint.md b/docs/decisions/047-push-endpoint.md index 20878ab..351b563 100644 --- a/docs/decisions/047-push-endpoint.md +++ b/docs/decisions/047-push-endpoint.md @@ -1,6 +1,6 @@ # ADR-047: Исходящий запрос к push-сервису -Уточняет [ADR-011](011-web-push.md) и [ADR-023](023-push-and-service-worker.md). Код причины из ответа push-сервиса в журнале — [ADR-064](064-push-failure-reason-in-log.md). +Уточняет [ADR-011](011-web-push.md) и [ADR-023](023-push-and-service-worker.md). Код причины из ответа push-сервиса в журнале — [ADR-073](073-push-failure-reason-in-log.md). ## Контекст diff --git a/docs/decisions/057-version-marks-dirty-tree.md b/docs/decisions/057-version-marks-dirty-tree.md index 491a41c..d9a88a8 100644 --- a/docs/decisions/057-version-marks-dirty-tree.md +++ b/docs/decisions/057-version-marks-dirty-tree.md @@ -2,7 +2,7 @@ Уточняет [ADR-022](022-deploy-nginx-systemd.md): проверка подлинности бинаря опирается на ревизию, значит ревизия обязана быть честной. -Уточнён [ADR-065](065-version-and-commit-time.md): чтение build info переехало в `internal/build`, ревизия печатается короткой и рядом с временем коммита; `+dirty` и `unknown` — как здесь. Формат стал проверяемым тестом — разбор build info отделён от `debug.ReadBuildInfo`; сама простановка `vcs.*` по-прежнему проверяется руками. +Уточнён [ADR-074](074-version-and-commit-time.md): чтение build info переехало в `internal/build`, ревизия печатается короткой и рядом с временем коммита; `+dirty` и `unknown` — как здесь. Формат стал проверяемым тестом — разбор build info отделён от `debug.ReadBuildInfo`; сама простановка `vcs.*` по-прежнему проверяется руками. ## Контекст diff --git a/docs/decisions/067-version-in-sidebar-foot.md b/docs/decisions/067-version-in-sidebar-foot.md index 4fd4017..59b2bfd 100644 --- a/docs/decisions/067-version-in-sidebar-foot.md +++ b/docs/decisions/067-version-in-sidebar-foot.md @@ -1,10 +1,10 @@ # ADR-067: Версия и время коммита в подвале сайдбара -Доводит до интерфейса [ADR-065](065-version-and-commit-time.md): сервер отдаёт `version` и `commitAt`, а где их показывать, там не решено. +Доводит до интерфейса [ADR-074](074-version-and-commit-time.md): сервер отдаёт `version` и `commitAt`, а где их показывать, там не решено. ## Контекст -`GET /api/config` называет работающую версию и время коммита (ADR-065). Клиент читает конфигурацию при запуске и так — ради `kdfIterations` и `vapidPublicKey`. Показать их негде: `docs/ui.md` такого элемента не знает. +`GET /api/config` называет работающую версию и время коммита (ADR-074). Клиент читает конфигурацию при запуске и так — ради `kdfIterations` и `vapidPublicKey`. Показать их негде: `docs/ui.md` такого элемента не знает. Спрашивают об этом при каждой поломке: обновилось ли то, что человек видит. В установленном на «Домой» приложении вопрос острее — там нет ни адресной строки, ни консоли, и другого способа узнать версию у человека нет. @@ -13,7 +13,7 @@ - Версия стоит в подвале сайдбара, рядом с «ты: @nick»: это единственное постоянное место интерфейса, где уже написано, кто и где мы. - Текст — `версия · дд.мм чч:мм`, время коммита в местной зоне. Год не показывается: вопрос «что сейчас работает», а не летопись. Времени нет (`commitAt = 0`) — остаётся одна версия; конфигурации нет вовсе — строки нет. - Цвет `stone`, размер подписи 11 px, без рамок и фона. Акцентом версия не бывает: `mark` — один смысловой элемент на экран (ADR-024), и это непрочитанные, а не служебная строка. -- Не кнопка и не ссылка: нажимать в ней нечего. Стоит рядом с кнопкой «ты: @nick», а не внутри неё — иначе экранный диктор зачитывал бы хеш как часть названия кнопки. Выделяется, в отличие от остального сайдбара (ADR-066): на iPhone скопировать её иначе нечем. +- Не кнопка и не ссылка: нажимать в ней нечего. Стоит рядом с кнопкой «ты: @nick», а не внутри неё — иначе экранный диктор зачитывал бы хеш как часть названия кнопки. Выделяется, в отличие от остального сайдбара (ADR-075): на iPhone скопировать её иначе нечем. - В сайдбаре 224 px строка и версия рядом не помещаются никогда: `версия · дд.мм чч:мм` — это 179 px при внутренней ширине 184, а «ты: @nick» просит ещё восемьдесят с лишним. Значит, на десктопе версия всегда занимает вторую строку и стоит справа; на мобильном, где сайдбар во всю ширину, обе стоят в одной строке. Ник, которому не хватило и целой строки, обрезается многоточием; версия — никогда: половина хеша бесполезна. - Текст ради одной строки не режется: вариант «в подвале ревизия, время в `title`» отклонён — `title` не показывается на телефоне, а телефон и есть место, ради которого строка заведена. @@ -23,4 +23,4 @@ - Разговор о поломке начинается с версии, а не с «попробуйте обновиться». - Подвал сайдбара стал двухстрочным и вырос с 47 px мока до 76. Это принятое отклонение от `docs/identity/screens.html`, блок 2a: там подвал — одна строка «ты: @nick» без версии и без 44 px цели нажатия. Мок остаётся снимком айдентики на момент ADR-024 и за интерфейсом не идёт: в нём нет и строки `+ новый чат`, и баннера установки. - Названа версия сервера, а не оболочки, которую исполняет браузер: `version` приезжает с `GET /api/config`, а страница и её модули — из кэша service worker. После релиза первое открытие показывает новую версию под старой оболочкой; расходятся они до применения обновления (ADR-068), а с недописанным сообщением в поле — сколь угодно долго. Показывать рядом версию кэша — отдельное решение, здесь его нет. -- Записано в `docs/ui.md`, «Список чатов (сайдбар)». Отдельного запроса ради этого нет: поля приезжают с конфигурацией (ADR-065). +- Записано в `docs/ui.md`, «Список чатов (сайдбар)». Отдельного запроса ради этого нет: поля приезжают с конфигурацией (ADR-074). diff --git a/docs/decisions/069-message-input-is-editable-block.md b/docs/decisions/069-message-input-is-editable-block.md index 1936712..e8e8688 100644 --- a/docs/decisions/069-message-input-is-editable-block.md +++ b/docs/decisions/069-message-input-is-editable-block.md @@ -1,12 +1,12 @@ # ADR-069: Строка сообщения — редактируемый блок, а не поле формы -Уточняет [ADR-024](024-identity-and-ui.md) («Чат» и «Доступность» в `docs/ui.md`) и [ADR-066](066-no-zoom-app-feel.md): в перечне элементов управления, по которым второй тап не гасится, прибавился редактируемый блок. +Уточняет [ADR-024](024-identity-and-ui.md) («Чат» и «Доступность» в `docs/ui.md`) и [ADR-075](075-no-zoom-app-feel.md): в перечне элементов управления, по которым второй тап не гасится, прибавился редактируемый блок. Уточнён [ADR-071](071-input-limit-cuts-what-arrives.md): предел держится до вставки и режет приходящее, а не хвост блока. ## Контекст -На iPhone при фокусе в строке сообщения над клавиатурой висит системная полоса помощника форм: две стрелки перехода между полями и «готово». Стрелки неактивны — поле на экране одно, переходить некуда, — а полоса занимает место и ломает ощущение приложения, ради которого принят ADR-066. +На iPhone при фокусе в строке сообщения над клавиатурой висит системная полоса помощника форм: две стрелки перехода между полями и «готово». Стрелки неактивны — поле на экране одно, переходить некуда, — а полоса занимает место и ломает ощущение приложения, ради которого принят ADR-075. Убрать её со страницы нечем: полосу рисует система, и для `input` и `textarea` она бывает всегда. Единственный работающий приём — перестать быть полем формы: у редактируемого блока (`contenteditable`) iOS полосы не показывает. diff --git a/docs/decisions/064-push-failure-reason-in-log.md b/docs/decisions/073-push-failure-reason-in-log.md similarity index 98% rename from docs/decisions/064-push-failure-reason-in-log.md rename to docs/decisions/073-push-failure-reason-in-log.md index 65929f9..caf639c 100644 --- a/docs/decisions/064-push-failure-reason-in-log.md +++ b/docs/decisions/073-push-failure-reason-in-log.md @@ -1,4 +1,4 @@ -# ADR-064: Код причины отказа push-сервиса в журнале +# ADR-073: Код причины отказа push-сервиса в журнале Уточняет [ADR-047](047-push-endpoint.md). diff --git a/docs/decisions/065-version-and-commit-time.md b/docs/decisions/074-version-and-commit-time.md similarity index 98% rename from docs/decisions/065-version-and-commit-time.md rename to docs/decisions/074-version-and-commit-time.md index dfecb06..30440ee 100644 --- a/docs/decisions/065-version-and-commit-time.md +++ b/docs/decisions/074-version-and-commit-time.md @@ -1,4 +1,4 @@ -# ADR-065: Версия — короткая ревизия, «время сборки» — время коммита +# ADR-074: Версия — короткая ревизия, «время сборки» — время коммита Уточняет [ADR-022](022-deploy-nginx-systemd.md) (подлинность бинаря проверяется сверкой хеша со сборкой из тега) и [ADR-057](057-version-marks-dirty-tree.md) (`+dirty` у сборки из изменённого дерева). diff --git a/docs/decisions/066-no-zoom-app-feel.md b/docs/decisions/075-no-zoom-app-feel.md similarity index 99% rename from docs/decisions/066-no-zoom-app-feel.md rename to docs/decisions/075-no-zoom-app-feel.md index 0db6e42..ccdc7d8 100644 --- a/docs/decisions/066-no-zoom-app-feel.md +++ b/docs/decisions/075-no-zoom-app-feel.md @@ -1,4 +1,4 @@ -# ADR-066: Масштабирования нет, размеры шрифтов прежние +# ADR-075: Масштабирования нет, размеры шрифтов прежние Уточняет [ADR-024](024-identity-and-ui.md): типографика из `docs/identity/brief.md` остаётся как записана, а страница перестаёт масштабироваться. diff --git a/docs/deploy.md b/docs/deploy.md index ce87c53..ba67f25 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -8,7 +8,7 @@ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bare ./cmd/bare ``` -Версия бинаря — `vcs.revision` и `vcs.time` из `debug.ReadBuildInfo()`. `bare version` печатает семь символов ревизии и время коммита в UTC: `cfd0ec0 2026-08-23T04:54:16Z`. У сборки из изменённого рабочего дерева (`vcs.modified`) к ревизии дописывается `+dirty` — сверка со сборкой из тега не должна проходить молча (ADR-057); у сборки не из git печатается `unknown`. Времени компиляции в бинаре нет: оно делало бы каждую пересборку одного коммита новым файлом (ADR-065). Те же значения отдаёт `GET /api/config` полями `version` и `commitAt`. `/healthz` отвечает только `ok`. +Версия бинаря — `vcs.revision` и `vcs.time` из `debug.ReadBuildInfo()`. `bare version` печатает семь символов ревизии и время коммита в UTC: `cfd0ec0 2026-08-23T04:54:16Z`. У сборки из изменённого рабочего дерева (`vcs.modified`) к ревизии дописывается `+dirty` — сверка со сборкой из тега не должна проходить молча (ADR-057); у сборки не из git печатается `unknown`. Времени компиляции в бинаре нет: оно делало бы каждую пересборку одного коммита новым файлом (ADR-074). Те же значения отдаёт `GET /api/config` полями `version` и `commitAt`. `/healthz` отвечает только `ok`. ## Первичная настройка сервера (один раз) @@ -147,6 +147,6 @@ ssh xmatic 'sudo install -m 0755 -o root -g root /tmp/bare /opt/bare/bare && sud ## Логи -Сервер пишет в stdout: время, метод, путь, статус, длительность; для маршрутов `/api/` вместо пути пишется шаблон (`/api/users/{nick}`), чтобы ник не попадал в журнал, а если отказ случился до маршрутизации (`Origin`, предел тела) и шаблона ещё нет — просто `/api/`; ника в журнале нет вовсе, включая отказы по лимитам (ADR-055); IP не пишется. Причины ответов `500 internal` (ADR-027) пишутся отдельной строкой, без данных запроса. Отправитель пушей пишет класс отказа — «таймаут», «имя не разрешилось», «отправка не удалась» — без адреса подписки и идентификатора устройства (ADR-047). Ответ push-сервиса пишется статусом и коротким кодом причины из тела: «пуш: push-сервис ответил 403 (BadJwtToken)». Код — диагностика вендора; всё, что на короткий код не похоже, отбрасывается целиком, и остаётся один статус (ADR-064). journald хранит по своим правилам. +Сервер пишет в stdout: время, метод, путь, статус, длительность; для маршрутов `/api/` вместо пути пишется шаблон (`/api/users/{nick}`), чтобы ник не попадал в журнал, а если отказ случился до маршрутизации (`Origin`, предел тела) и шаблона ещё нет — просто `/api/`; ника в журнале нет вовсе, включая отказы по лимитам (ADR-055); IP не пишется. Причины ответов `500 internal` (ADR-027) пишутся отдельной строкой, без данных запроса. Отправитель пушей пишет класс отказа — «таймаут», «имя не разрешилось», «отправка не удалась» — без адреса подписки и идентификатора устройства (ADR-047). Ответ push-сервиса пишется статусом и коротким кодом причины из тела: «пуш: push-сервис ответил 403 (BadJwtToken)». Код — диагностика вендора; всё, что на короткий код не похоже, отбрасывается целиком, и остаётся один статус (ADR-073). journald хранит по своим правилам. nginx журнал запросов не ведёт: `access_log off` в обоих server-блоках (ADR-056). Без этой строки он унаследовал бы `access.log` формата `combined` из `/etc/nginx/nginx.conf` — с адресом клиента и полным URI, то есть с ником и социальным графом. `error_log` остаётся: это журнал сбоев, а не запросов, и при отказе он записывает адрес клиента. diff --git a/docs/identity/brief.md b/docs/identity/brief.md index fafd015..89a670a 100644 --- a/docs/identity/brief.md +++ b/docs/identity/brief.md @@ -37,12 +37,12 @@ font-family: ui-monospace, "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monos Размеры: текст сообщений 14 px / 1.55; автор и время 12 px; заголовки секций 10 px, разрядка 0.14em, uppercase; подписи 11 px; имя чата в шапке 15 px. Шрифты не загружаются. -Поля ввода — те же 14 px, исключений нет: масштабирование в клиенте запрещено, и растить шрифт ради обхода фокус-зума iOS не приходится (ADR-066). +Поля ввода — те же 14 px, исключений нет: масштабирование в клиенте запрещено, и растить шрифт ради обхода фокус-зума iOS не приходится (ADR-075). ## Компоновка - Десктоп: сайдбар 224 px с правой границей `line`, шапка 64 px, отступы контента 32 px; сообщения — сетка `132px 1fr`, column-gap 20, row-gap 6. -- Мобильный: шапка 56 px, отступы 20 px, ввод с min-height 44 px. Нижнее поле подвала и строки ввода считается с `env(safe-area-inset-bottom)`: под системную полосу iPhone они не заходят (ADR-066). +- Мобильный: шапка 56 px, отступы 20 px, ввод с min-height 44 px. Нижнее поле подвала и строки ввода считается с `env(safe-area-inset-bottom)`: под системную полосу iPhone они не заходят (ADR-075). - Ввод — рамка 1 px ink, без скруглений, `>` цветом mark слева. - Активный элемент списка — инверсия: фон ink, текст bone. - Разделители — 1 px `line`; разделитель «новые» — 1 px mark. diff --git a/docs/plan.md b/docs/plan.md index 417e37a..9a45012 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -18,7 +18,7 @@ ``` embed.go //go:embed web в корне модуля (ADR-025) cmd/bare/main.go подкоманды: serve, vapid, version -internal/build/ ревизия и время коммита из build info (ADR-065) +internal/build/ ревизия и время коммита из build info (ADR-074) internal/config/ переменные BARE_* internal/store/ SQLite, migrations/*.sql (embed), запросы internal/auth/ argon2id, сессии, cookie @@ -36,7 +36,7 @@ web/ js/sync.js устройство, поток событий, приём и отправка js/pwa.js service worker, самообновление (ADR-068), пуши, установка js/ulid.js ULID - js/zoom.js запрет масштабирования (ADR-066) + js/zoom.js запрет масштабирования (ADR-075) js/ui/*.js экраны из ui.md js/export.js .bare scripts/deploy.sh diff --git a/docs/protocol.md b/docs/protocol.md index 56d1265..305912e 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -44,7 +44,7 @@ WrappedKey { to: nick, iv: string, ct: string } `GET /api/config` → `200 {inviteRequired: bool, vapidPublicKey: string, kdfIterations: number, maxMessageChars: 4000, version: string, commitAt: number}` -`version` — короткая ревизия сборки: семь символов хеша коммита, с суффиксом `+dirty` у бинаря из изменённого дерева (ADR-057) и `unknown` у сборки не из git. `commitAt` — время коммита в миллисекундах Unix, `0` если оно неизвестно. Это время коммита, а не момент компиляции: штамп времени сборки лишил бы смысла сверку хеша бинаря со сборкой из тега (ADR-022, ADR-065). Те же значения печатает `bare version`. Отдельного эндпоинта у них нет. +`version` — короткая ревизия сборки: семь символов хеша коммита, с суффиксом `+dirty` у бинаря из изменённого дерева (ADR-057) и `unknown` у сборки не из git. `commitAt` — время коммита в миллисекундах Unix, `0` если оно неизвестно. Это время коммита, а не момент компиляции: штамп времени сборки лишил бы смысла сверку хеша бинаря со сборкой из тега (ADR-022, ADR-074). Те же значения печатает `bare version`. Отдельного эндпоинта у них нет. `GET /api/kdf?nick=` → `200 {iterations}`. Для неизвестного ника — `kdfIterations` из конфигурации, тем же статусом. Скрытием существования ника ответ не занимается: у аккаунта, не входившего после повышения цели, число итераций своё (ADR-062), а сам факт, что ник существует, публичен (ADR-019). diff --git a/docs/ui.md b/docs/ui.md index d24ac58..8fdc740 100644 --- a/docs/ui.md +++ b/docs/ui.md @@ -8,7 +8,7 @@ Без inline-стилей и inline-скриптов (CSP). Рендер — `document.createElement` и `textContent`; `innerHTML` не используется нигде: сообщения — пользовательские данные. -Страница ведёт себя как приложение, а не как документ (ADR-066): масштабирования нет, резинового отскока нет, выделение снято с шапки, сайдбара, кнопок и разделителей — но не с текста сообщений, отпечатков, полей ввода и версии в подвале сайдбара: их копируют. Установленное на «Домой» приложение объявлено мета-строками, имя на экране — `bare`, системная полоса остаётся над страницей. Подвал сайдбара и строка ввода отступают от нижней системной полосы iPhone. +Страница ведёт себя как приложение, а не как документ (ADR-075): масштабирования нет, резинового отскока нет, выделение снято с шапки, сайдбара, кнопок и разделителей — но не с текста сообщений, отпечатков, полей ввода и версии в подвале сайдбара: их копируют. Установленное на «Домой» приложение объявлено мета-строками, имя на экране — `bare`, системная полоса остаётся над страницей. Подвал сайдбара и строка ввода отступают от нижней системной полосы iPhone. ## Вход и регистрация @@ -120,4 +120,4 @@ Строка сообщения — редактируемый блок (ADR-069), и семантику ему задают руками: `role="textbox"`, `aria-multiline="true"`, подпись `aria-label` тем же текстом, что подсказка. Заблокированный ввод перестаёт быть редактируемым и говорит об этом `aria-disabled`. -Масштабирование запрещено — и щипок, и двойной тап (ADR-066). Это сознательный размен: интерфейс ведёт себя как приложение, а человек, которому нужно увеличить мелкое, средства лишается. Размеры шрифтов от запрета не меняются: поля ввода остаются 14 px, как в `docs/identity/brief.md`. Браузер вправе запрет проигнорировать. +Масштабирование запрещено — и щипок, и двойной тап (ADR-075). Это сознательный размен: интерфейс ведёт себя как приложение, а человек, которому нужно увеличить мелкое, средства лишается. Размеры шрифтов от запрета не меняются: поля ввода остаются 14 px, как в `docs/identity/brief.md`. Браузер вправе запрет проигнорировать. diff --git a/internal/api/account.go b/internal/api/account.go index e1e781c..c21013a 100644 --- a/internal/api/account.go +++ b/internal/api/account.go @@ -17,7 +17,7 @@ import ( // // version и commitAt отвечают на вопрос «какой код сейчас работает»: // короткая ревизия сборки и время коммита, а не момент компиляции -// (ADR-065). Отдельного эндпоинта им не заводится — конфигурацию клиент +// (ADR-074). Отдельного эндпоинта им не заводится — конфигурацию клиент // читает до входа и так. func (s *server) config(w http.ResponseWriter, r *http.Request) { info := build.Current() diff --git a/internal/api/account_test.go b/internal/api/account_test.go index b7bfa19..439287b 100644 --- a/internal/api/account_test.go +++ b/internal/api/account_test.go @@ -112,7 +112,7 @@ func TestConfig(t *testing.T) { t.Errorf("maxMessageChars: получено %d, ожидалось 4000", got.MaxMessageChars) } // Версия — то же самое, что печатает `bare version`: одно место, - // один формат (ADR-065). Тестовому бинарю vcs.* не проставляются, + // один формат (ADR-074). Тестовому бинарю vcs.* не проставляются, // поэтому здесь проверяется в том числе поведение без build info — // «unknown» и 0. if !validVersion(got.Version) { diff --git a/internal/build/build.go b/internal/build/build.go index ca3079d..12c4da7 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -1,5 +1,5 @@ // Package build отвечает на вопрос «какой код сейчас работает»: ревизия -// и время коммита, которые git оставляет в бинаре при сборке (ADR-065). +// и время коммита, которые git оставляет в бинаре при сборке (ADR-074). // Момента компиляции здесь нет и не будет: штамп времени сборки делал бы // каждую пересборку одного коммита новым файлом, а подлинность бинаря // проверяется сравнением хеша со сборкой из тега (ADR-022). diff --git a/internal/build/build_test.go b/internal/build/build_test.go index 42d0d0f..a2b177b 100644 --- a/internal/build/build_test.go +++ b/internal/build/build_test.go @@ -9,7 +9,7 @@ import ( const hash = "9f2c1ab7d3e4c5061728394a5b6c7d8e9f001122" // Формат версии: семь символов ревизии, «+dirty» у изменённого дерева, -// «unknown» без ревизии (ADR-057, ADR-065). +// «unknown» без ревизии (ADR-057, ADR-074). func TestVersion(t *testing.T) { cases := []struct { info Info diff --git a/internal/push/push.go b/internal/push/push.go index 10561bf..891ac7f 100644 --- a/internal/push/push.go +++ b/internal/push/push.go @@ -70,7 +70,7 @@ const ( dropEvery = time.Minute ) -// Чтение тела ответа push-сервиса ради кода причины (ADR-064). +// Чтение тела ответа push-сервиса ради кода причины (ADR-073). const ( // maxReasonBody — сколько байт тела читаем. Код причины стоит в начале // ответа; остальное дочитывается в никуда, ради переиспользования @@ -331,7 +331,7 @@ func (s *Sender) deliver(j job) { return } defer resp.Body.Close() - // Начало тела нужно ради кода причины (ADR-064), остаток дочитывается + // Начало тела нужно ради кода причины (ADR-073), остаток дочитывается // в никуда: иначе соединение не переиспользуется. head, _ := io.ReadAll(io.LimitReader(resp.Body, maxReasonBody)) io.Copy(io.Discard, resp.Body) @@ -432,7 +432,7 @@ func (s *Sender) report(format string, args ...any) { } // status — ответ push-сервиса для журнала: код и, если он разобран, -// короткий код причины из тела (ADR-064). +// короткий код причины из тела (ADR-073). func status(code int, body []byte) string { if r := serviceReason(body); r != "" { return fmt.Sprintf("%d (%s)", code, r) @@ -443,7 +443,7 @@ func status(code int, body []byte) string { // serviceReason достаёт из тела ответа короткий код причины: APNs отвечает // {"reason":"BadJwtToken"}, Mozilla — {"errno":…,"error":"Not Found"}. // Код — диагностика вендора, а не данные пользователя, и без него отказ -// не читается: голый «403» сутки выглядел как «что-то с пушами» (ADR-064). +// не читается: голый «403» сутки выглядел как «что-то с пушами» (ADR-073). // // Тело всё же приходит снаружи, поэтому в журнал идёт не оно, а то, что // прошло safeReason. diff --git a/internal/push/push_test.go b/internal/push/push_test.go index 57e386e..5dbfe42 100644 --- a/internal/push/push_test.go +++ b/internal/push/push_test.go @@ -193,7 +193,7 @@ func TestVAPIDSubjectInToken(t *testing.T) { } // Отказ push-сервиса читается по журналу: статус и код причины из тела -// (ADR-064). Без кода 403 от APNs неотличим от любого другого отказа. +// (ADR-073). Без кода 403 от APNs неотличим от любого другого отказа. func TestServiceStatusInLog(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.Copy(io.Discard, r.Body) @@ -225,7 +225,7 @@ func TestServiceStatusInLog(t *testing.T) { // Код причины берётся из тела ответа, но телом распоряжается чужая // сторона: всё, что на короткий код не похоже, в журнал не идёт вовсе -// (ADR-064, docs/deploy.md, «Логи»). +// (ADR-073, docs/deploy.md, «Логи»). func TestServiceReason(t *testing.T) { const endpoint = "web.push.apple.com" cases := []struct{ body, want string }{ diff --git a/web/app.css b/web/app.css index 8c9f3af..749cae4 100644 --- a/web/app.css +++ b/web/app.css @@ -25,7 +25,7 @@ body { height: 100%; } -/* масштабирования нет (ADR-066). manipulation снимает зум по двойному тапу +/* масштабирования нет (ADR-075). manipulation снимает зум по двойному тапу и задержку 300 мс, которую браузер держит, ожидая второго касания; прокрутку и щипок правило не трогает — щипок запрещён в viewport. Правило стоит на html: двойной тап — жест документа, и браузер берёт @@ -41,7 +41,7 @@ body { /* виден вырез: viewport-fit=cover пускает страницу под скруглённые углы, под боковой вырез в альбомной ориентации и под верхнюю системную полосу. Полосу над страницей держит мета-строка о стиле полосы - (ADR-066), поэтому верхняя вставка обычно нулевая и не делает ничего; + (ADR-075), поэтому верхняя вставка обычно нулевая и не делает ничего; там, где она не нулевая, шапка не уезжает под часы */ padding-top: env(safe-area-inset-top); padding-left: env(safe-area-inset-left); @@ -58,7 +58,7 @@ body { /* интерфейс не выделяется: долгое нажатие по шапке, списку и кнопкам вызывает лупу и «копировать», а копировать там нечего. Текст сообщений, отпечатки и поля ввода выделяются как обычно — их именно копируют - (ADR-066) */ + (ADR-075) */ .side, .head, @@ -421,7 +421,7 @@ input[type="password"] { gap: 2px 8px; margin-top: auto; /* нижняя системная полоса iPhone проходит поверх страницы: подвал - отступает от неё, а не прячется под ней (ADR-066) */ + отступает от неё, а не прячется под ней (ADR-075) */ padding: 6px 20px calc(6px + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); } @@ -463,7 +463,7 @@ input[type="password"] { /* версия выделяется: с неё начинается разговор о поломке (ADR-067), а на iPhone скопировать её иначе нечем — ни строки адреса, ни консоли там нет. Общий запрет выделения снят с неё так же, как с текста - сообщений и отпечатков (ADR-066) */ + сообщений и отпечатков (ADR-075) */ .build { flex: none; diff --git a/web/js/main.js b/web/js/main.js index 4534c7a..da52450 100644 --- a/web/js/main.js +++ b/web/js/main.js @@ -483,7 +483,7 @@ function errorText(err) { async function boot() { // Масштабирования нет: интерфейс ведёт себя как приложение, а не как - // страница (ADR-066). Строке viewport Safari верит не всегда, поэтому + // страница (ADR-075). Строке viewport Safari верит не всегда, поэтому // страховка ставится до первого экрана. lock(); db.persist(); diff --git a/web/js/ui/shell.js b/web/js/ui/shell.js index ee314d7..3e26af8 100644 --- a/web/js/ui/shell.js +++ b/web/js/ui/shell.js @@ -61,7 +61,7 @@ function side(ctx, active) { return { nav, dispose: mount(items, ctx, active) }; } -// build — версия и время коммита из GET /api/config (ADR-065, ADR-067). +// build — версия и время коммита из GET /api/config (ADR-074, ADR-067). // Конфигурации нет — офлайн-старт до первого ответа сервера — значит, // и строки нет: выдумывать версию не из чего. Время без версии не бывает: // её сервер отдаёт всегда, хотя бы как «unknown». diff --git a/web/js/zoom.js b/web/js/zoom.js index 7118148..2b6c0b3 100644 --- a/web/js/zoom.js +++ b/web/js/zoom.js @@ -1,4 +1,4 @@ -// Запрет масштабирования — страховка к строке viewport (ADR-066). +// Запрет масштабирования — страховка к строке viewport (ADR-075). // // Основное средство — `maximum-scale=1, user-scalable=no` в index.html // и `touch-action: manipulation` в app.css. Safari вправе не послушаться: