From d21da8575c9649d67c4f6e95a3accec1c7188e94 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 10 Aug 2026 21:39:55 +0300 Subject: [PATCH] =?UTF-8?q?=D0=95=D0=B4=D0=B8=D0=BD=D1=8B=D0=B9=20=D1=81?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= =?UTF-8?q?=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D0=B4=D0=B2=D1=83?= =?UTF-8?q?=D1=85=20=D1=81=D0=B5=D0=BA=D1=86=D0=B8=D0=B9,=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=8F=D0=B4=D0=BE=D0=BA=20=D0=BF=D0=BE=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Секции «Ядро» и «Инфра» слиты в одну «Очередь»: полок домена у проекта нет, а две секции держали два независимых порядка вместо одного. Порядок: красный гейт, потом долги, задевающие интерфейсы, потом хранилище, вход, разграничение, приложение. Разведка потолков SpeechKit последней — она обслуживает направление, а не очередь. --- tasks/BACKLOG.md | 26 +++++++++---------- tasks/items/errors-as-instead-of-typecast.md | 2 +- tasks/items/external-call-timeouts.md | 2 +- tasks/items/http-handler-tests-never-green.md | 2 +- tasks/items/installable-pwa.md | 2 +- tasks/items/json-api-for-spa.md | 2 +- tasks/items/ntfy-delivery.md | 2 +- tasks/items/oidc-login.md | 2 +- tasks/items/pocketbase-storage.md | 2 +- tasks/items/record-ownership.md | 2 +- tasks/items/records-list-screen.md | 2 +- tasks/items/spa-framework-choice.md | 2 +- tasks/items/spa-skeleton.md | 2 +- tasks/items/speechkit-limits.md | 2 +- tasks/items/telegram-account-link.md | 2 +- tasks/items/upload-and-status-screen.md | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/tasks/BACKLOG.md b/tasks/BACKLOG.md index 5a0f274..c15933e 100644 --- a/tasks/BACKLOG.md +++ b/tasks/BACKLOG.md @@ -2,11 +2,14 @@ Что **можно взять**. Одна задача = один файл `items/.md` + строка здесь. Целей тут нет — они в [ROADMAP.md](ROADMAP.md): беклог — то, что берут, -роадмап — то, подо что берут. **Порядок строк внутри секции значим:** +роадмап — то, подо что берут. **Порядок строк значим:** это очередь, и первая строка — то, что делают следующим. Порядок назначает человек на груминге, машина его не выводит. Одно исключение производно от типа — сырьё (`research` без раздела «Вопрос») -стоит в конце секции: его не берут. Ведётся скиллом `tasks`. +стоит в конце: его не берут. Ведётся скиллом `tasks`. + +Секция одна — полок домена у проекта нет, и делить очередь на две +значило бы держать два порядка вместо одного. Тип записи стоит первым полем меты и решает, что у неё может быть: ✨ `feature` 🐞 `fix` 🧹 `chore` 🔬 `research` @@ -15,23 +18,20 @@ (работа не может продолжаться ни одной задачей), оно живёт до ответа человека, а его следы — вопросами в файлах задач. -## Ядро +## Очередь - [🐞 Починить тесты http-обработчика, ни разу не бывшие зелёными](items/http-handler-tests-never-green.md) — go test ./... падает на master: тесты требуют файла, которого нет в репозитории, и ждут 201 от ffprobe, которому скормили строку. +- [🧹 Сравнивать доменные ошибки через errors.As](items/errors-as-instead-of-typecast.md) — NoopJobError и JobNotFoundError проверяются приведением типа: первая же обёртка %w между слоями сломает проверку молча. +- [🧹 Задать таймауты обращениям к внешним сервисам](items/external-call-timeouts.md) — Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата. +- [🧹 Перевести хранилище на встроенный PocketBase](items/pocketbase-storage.md) — Хранилище, учётные записи и веб-панель нужны все три, и SQLite с goqu не даёт ни второго, ни третьего. - [✨ Пускать в приложение только после входа через OIDC](items/oidc-login.md) — HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору. - [✨ Привязать запись к владельцу и отдавать только свои](items/record-ownership.md) — У задачи и файла нет владельца, поэтому знание UUID задачи и есть право её читать. - [✨ Сопоставить пользователя Telegram с учётной записью](items/telegram-account-link.md) — Белый список сверяется с именем пользователя Telegram, которое владелец меняет в любой момент, а записи из бота ни с кем не связаны. - [✨ Свести приём и чтение записей к одному контракту для приложения](items/json-api-for-spa.md) — Сегодняшний API отвечает 404 на любую ошибку чтения и 500 на любую ошибку приёма: строить на нём экраны нечем. -- [✨ Сделать экран загрузки записи и её состояния](items/upload-and-status-screen.md) — Первое, ради чего приложение открывают: отдать файл и увидеть, что с ним происходит. -- [✨ Сделать экран списка своих записей и чтения текста](items/records-list-screen.md) — Расшифровка сегодня доходит одним сообщением и теряется в переписке; вернуться к ней через неделю нечем. -- [✨ Отправлять готовый текст через apprise и ntfy](items/ntfy-delivery.md) — Пользователь веба узнаёт о готовности только опросом с открытого экрана. -- [🧹 Сравнивать доменные ошибки через errors.As](items/errors-as-instead-of-typecast.md) — NoopJobError и JobNotFoundError проверяются приведением типа: первая же обёртка %w между слоями сломает проверку молча. -- [🔬 Потолки SpeechKit по длине записи и по формату](items/speechkit-limits.md) — Потолок длины записи и перечень принимаемых форматов неизвестны, а цель про долгие записи без них не начинается. - -## Инфра - -- [🧹 Перевести хранилище на встроенный PocketBase](items/pocketbase-storage.md) — Хранилище, учётные записи и веб-панель нужны все три, и SQLite с goqu не даёт ни второго, ни третьего. - [🔬 Выбор фреймворка для приложения](items/spa-framework-choice.md) — Конвенция веб-UI написана под htmx, а решено делать SPA: до выбора фреймворка не заводится ни сборка, ни первый экран. - [✨ Собрать каркас приложения и раздать его из бинарника](items/spa-skeleton.md) — Экранов нет и собирать их нечем: ни сборки фронтенда, ни раздачи статики в проекте не существует. +- [✨ Сделать экран загрузки записи и её состояния](items/upload-and-status-screen.md) — Первое, ради чего приложение открывают: отдать файл и увидеть, что с ним происходит. +- [✨ Сделать экран списка своих записей и чтения текста](items/records-list-screen.md) — Расшифровка сегодня доходит одним сообщением и теряется в переписке; вернуться к ней через неделю нечем. - [✨ Сделать приложение устанавливаемым на телефон](items/installable-pwa.md) — Приложение, живущее вкладкой браузера, теряется среди прочих: ярлыка на экране у него нет. -- [🧹 Задать таймауты обращениям к внешним сервисам](items/external-call-timeouts.md) — Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата. +- [✨ Отправлять готовый текст через apprise и ntfy](items/ntfy-delivery.md) — Пользователь веба узнаёт о готовности только опросом с открытого экрана. +- [🔬 Потолки SpeechKit по длине записи и по формату](items/speechkit-limits.md) — Потолок длины записи и перечень принимаемых форматов неизвестны, а цель про долгие записи без них не начинается. diff --git a/tasks/items/errors-as-instead-of-typecast.md b/tasks/items/errors-as-instead-of-typecast.md index b745977..3f62c24 100644 --- a/tasks/items/errors-as-instead-of-typecast.md +++ b/tasks/items/errors-as-instead-of-typecast.md @@ -1,7 +1,7 @@ # 🧹 Сравнивать доменные ошибки через errors.As - **Тип:** chore -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** NoopJobError и JobNotFoundError проверяются приведением типа: первая же обёртка %w между слоями сломает проверку молча. Сегодня это работает только потому, что ошибку на этом пути никто не diff --git a/tasks/items/external-call-timeouts.md b/tasks/items/external-call-timeouts.md index 41f3f74..c18c3a4 100644 --- a/tasks/items/external-call-timeouts.md +++ b/tasks/items/external-call-timeouts.md @@ -1,7 +1,7 @@ # 🧹 Задать таймауты обращениям к внешним сервисам - **Тип:** chore -- **Категория:** Инфра +- **Категория:** Очередь - **Зачем:** Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата. Все обращения наружу идут с `context.Background()` либо через `http.Get` без diff --git a/tasks/items/http-handler-tests-never-green.md b/tasks/items/http-handler-tests-never-green.md index d6af5db..b9e14dc 100644 --- a/tasks/items/http-handler-tests-never-green.md +++ b/tasks/items/http-handler-tests-never-green.md @@ -1,7 +1,7 @@ # 🐞 Починить тесты http-обработчика, ни разу не бывшие зелёными - **Тип:** fix -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** go test ./... падает на master: тесты требуют файла, которого нет в репозитории, и ждут 201 от ffprobe, которому скормили строку. Тесты заведены коммитом `87d8b05` и с тех пор ни разу не проходили: файл diff --git a/tasks/items/installable-pwa.md b/tasks/items/installable-pwa.md index d3135ad..0f3b835 100644 --- a/tasks/items/installable-pwa.md +++ b/tasks/items/installable-pwa.md @@ -1,7 +1,7 @@ # ✨ Сделать приложение устанавливаемым на телефон - **Тип:** feature -- **Категория:** Инфра +- **Категория:** Очередь - **Зачем:** Приложение, живущее вкладкой браузера, теряется среди прочих: ярлыка на экране у него нет. - **Теги:** goal:web-access diff --git a/tasks/items/json-api-for-spa.md b/tasks/items/json-api-for-spa.md index d6ba5a9..96d35de 100644 --- a/tasks/items/json-api-for-spa.md +++ b/tasks/items/json-api-for-spa.md @@ -1,7 +1,7 @@ # ✨ Свести приём и чтение записей к одному контракту для приложения - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Сегодняшний API отвечает 404 на любую ошибку чтения и 500 на любую ошибку приёма: строить на нём экраны нечем. - **Теги:** goal:web-access diff --git a/tasks/items/ntfy-delivery.md b/tasks/items/ntfy-delivery.md index c9143d8..8b7b92f 100644 --- a/tasks/items/ntfy-delivery.md +++ b/tasks/items/ntfy-delivery.md @@ -1,7 +1,7 @@ # ✨ Отправлять готовый текст через apprise и ntfy - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Пользователь веба узнаёт о готовности только опросом с открытого экрана. - **Теги:** goal:ready-notification diff --git a/tasks/items/oidc-login.md b/tasks/items/oidc-login.md index f306645..1319b88 100644 --- a/tasks/items/oidc-login.md +++ b/tasks/items/oidc-login.md @@ -1,7 +1,7 @@ # ✨ Пускать в приложение только после входа через OIDC - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору. - **Теги:** goal:multi-user, question diff --git a/tasks/items/pocketbase-storage.md b/tasks/items/pocketbase-storage.md index 10a9d40..0fe7974 100644 --- a/tasks/items/pocketbase-storage.md +++ b/tasks/items/pocketbase-storage.md @@ -1,7 +1,7 @@ # 🧹 Перевести хранилище на встроенный PocketBase - **Тип:** chore -- **Категория:** Инфра +- **Категория:** Очередь - **Зачем:** Хранилище, учётные записи и веб-панель нужны все три, и SQLite с goqu не даёт ни второго, ни третьего. PocketBase встраивается библиотекой в тот же бинарник и приносит хранилище, diff --git a/tasks/items/record-ownership.md b/tasks/items/record-ownership.md index d815067..2274af3 100644 --- a/tasks/items/record-ownership.md +++ b/tasks/items/record-ownership.md @@ -1,7 +1,7 @@ # ✨ Привязать запись к владельцу и отдавать только свои - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** У задачи и файла нет владельца, поэтому знание UUID задачи и есть право её читать. - **Теги:** goal:multi-user diff --git a/tasks/items/records-list-screen.md b/tasks/items/records-list-screen.md index 64134db..3af3f1f 100644 --- a/tasks/items/records-list-screen.md +++ b/tasks/items/records-list-screen.md @@ -1,7 +1,7 @@ # ✨ Сделать экран списка своих записей и чтения текста - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Расшифровка сегодня доходит одним сообщением и теряется в переписке; вернуться к ней через неделю нечем. - **Теги:** goal:web-access diff --git a/tasks/items/spa-framework-choice.md b/tasks/items/spa-framework-choice.md index d77aaa8..1ea5292 100644 --- a/tasks/items/spa-framework-choice.md +++ b/tasks/items/spa-framework-choice.md @@ -1,7 +1,7 @@ # 🔬 Выбор фреймворка для приложения - **Тип:** research -- **Категория:** Инфра +- **Категория:** Очередь - **Зачем:** Конвенция веб-UI написана под htmx, а решено делать SPA: до выбора фреймворка не заводится ни сборка, ни первый экран. - **Теги:** goal:web-access diff --git a/tasks/items/spa-skeleton.md b/tasks/items/spa-skeleton.md index 94a83b5..c89e640 100644 --- a/tasks/items/spa-skeleton.md +++ b/tasks/items/spa-skeleton.md @@ -1,7 +1,7 @@ # ✨ Собрать каркас приложения и раздать его из бинарника - **Тип:** feature -- **Категория:** Инфра +- **Категория:** Очередь - **Зачем:** Экранов нет и собирать их нечем: ни сборки фронтенда, ни раздачи статики в проекте не существует. - **Теги:** goal:web-access diff --git a/tasks/items/speechkit-limits.md b/tasks/items/speechkit-limits.md index 618b537..cad7ae6 100644 --- a/tasks/items/speechkit-limits.md +++ b/tasks/items/speechkit-limits.md @@ -1,7 +1,7 @@ # 🔬 Потолки SpeechKit по длине записи и по формату - **Тип:** research -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Потолок длины записи и перечень принимаемых форматов неизвестны, а цель про долгие записи без них не начинается. - **Теги:** goal:long-recordings diff --git a/tasks/items/telegram-account-link.md b/tasks/items/telegram-account-link.md index 9578550..92d03de 100644 --- a/tasks/items/telegram-account-link.md +++ b/tasks/items/telegram-account-link.md @@ -1,7 +1,7 @@ # ✨ Сопоставить пользователя Telegram с учётной записью - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Белый список сверяется с именем пользователя Telegram, которое владелец меняет в любой момент, а записи из бота ни с кем не связаны. - **Теги:** goal:multi-user diff --git a/tasks/items/upload-and-status-screen.md b/tasks/items/upload-and-status-screen.md index 40bd070..920ea99 100644 --- a/tasks/items/upload-and-status-screen.md +++ b/tasks/items/upload-and-status-screen.md @@ -1,7 +1,7 @@ # ✨ Сделать экран загрузки записи и её состояния - **Тип:** feature -- **Категория:** Ядро +- **Категория:** Очередь - **Зачем:** Первое, ради чего приложение открывают: отдать файл и увидеть, что с ним происходит. - **Теги:** goal:web-access