хранилище переехало с PocketBase на SQLite со своим каталогом файлов
- база своя: два пула, захват одним UPDATE ... RETURNING, шаги схемы на goose под файловым замком, одна миграция начальной схемы вместо семи прежних - транспорт переписан на net/http: свои слои, свой ограничитель частоты, отдача файла с проверкой владельца; панель /_/ и пространство /api/ исчезли - по находкам ревью: журнал не пишет путь под корнем приложения, ключ бюджета читается справа налево, узнавание известного идёт читающим пулом
This commit is contained in:
+23
-16
@@ -100,15 +100,19 @@ transcriber — **приложение, а не библиотека**: внеш
|
||||
|
||||
| Доменная ошибка | Статус | `error_code` | Сообщение |
|
||||
| --- | --- | --- | --- |
|
||||
| сессии нет | 401 | `unauthorized` | «требуется вход» |
|
||||
| предъявитель узнан, учётной записи пользователя нет | 403 | `forbidden` | «у вашей сессии нет учётной записи» |
|
||||
| пришедший не узнан | 401 | `unauthorized` | «сервис вас не узнал» |
|
||||
| запись не найдена, чужая либо ничья | 404 | `not_found` | «запись не найдена» |
|
||||
| файл не приложен, формат не распознан, негодное значение параметра | 400 | `bad_request` | «некорректный ввод» |
|
||||
| файл не приложен, формат не распознан, негодное значение параметра, негодный диапазон | 400 | `bad_request` | «некорректный ввод» |
|
||||
| запись сверх потолка размера | 413 | `too_large` | «запись больше допустимого размера», плюс предел числом |
|
||||
| запросов слишком много подряд | 429 | `too_many_requests` | «слишком много запросов подряд, попробуйте позже» |
|
||||
| текста запрошенного вида ещё нет | 409 | `not_ready` | «действие недоступно в текущем состоянии» |
|
||||
| текста или копии файла запрошенного вида ещё нет | 409 | `not_ready` | «действие недоступно в текущем состоянии» |
|
||||
| прочее | 500 | `internal` | «внутренняя ошибка» |
|
||||
|
||||
Ветвь `403`/`forbidden` ушла отсюда 2026-08-22 вместе со своим единственным
|
||||
случаем: им был владелец панели, предъявивший собственный токен хранилища.
|
||||
Ни панели, ни токенов у сервиса не осталось, а узнавание по заголовку
|
||||
учётную запись заводит само.
|
||||
|
||||
Новую штатную ветвь отказа заводим sentinel'ом и добавляем сюда — иначе
|
||||
ветвь по умолчанию отдаст 500 «внутренняя ошибка» на обычный конфликт, а
|
||||
логирующая граница спишет его в `ERROR` вместо `DEBUG`.
|
||||
@@ -124,10 +128,13 @@ transcriber — **приложение, а не библиотека**: внеш
|
||||
`json-api-for-spa` 2026-08-15.
|
||||
|
||||
**Часть отказов рождается не в обработчике** — предел тела, ограничитель
|
||||
частоты, неизвестный путь под корнем приложения — и до этой точки не доходит
|
||||
вовсе. Их приводит к той же форме слой `OneErrorForm`, стоящий снаружи всех
|
||||
прочих. Без него формы отказа было бы две, и отказ у человека на мобильной сети
|
||||
приходил бы телом библиотеки.
|
||||
частоты, неизвестный путь под корнем приложения, негодный диапазон в запросе
|
||||
файла — и до этой точки не доходит вовсе. С 2026-08-22 отдельного слоя
|
||||
перевода им не нужно: маршрутизатор и слои написаны нами, и каждый из них
|
||||
отвечает **своей доменной ошибкой** через ту же точку. Прежде их приводил к
|
||||
общей форме слой `OneErrorForm`, стоявший снаружи всех прочих и переводивший
|
||||
тело чужой библиотеки; библиотеки не осталось, и второй формы отказа взяться
|
||||
неоткуда.
|
||||
|
||||
### Разовый ответ и сохранённая диагностика
|
||||
|
||||
@@ -135,7 +142,7 @@ transcriber — **приложение, а не библиотека**: внеш
|
||||
|
||||
- **Разовый ответ на действие** (тело HTTP-ответа) — строго нейтральный: отображение выше, `err.Error()` наружу не идёт,
|
||||
полная ошибка остаётся в логах по идентификатору задачи.
|
||||
- **Сохранённая диагностика состояния** — колонка `error_text` задачи. Это
|
||||
- **Сохранённая диагностика состояния** — колонка `error_text` аудиозаписи. Это
|
||||
**поверхность владельца**, а не пользователя: сюда сырой текст ошибки допустим
|
||||
и полезен. Но:
|
||||
- **секреты запрещены** — токены, ключи, пароли, заголовок
|
||||
@@ -146,8 +153,8 @@ transcriber — **приложение, а не библиотека**: внеш
|
||||
числом рядом**: без этого непонятно, насколько сокращать.
|
||||
|
||||
*Расхождение:* `error_text` пишется целиком, без вычистки и без усечения.
|
||||
Наружу он при этом не выходит: опрос готовности отдаёт признак остановки без
|
||||
машинного текста — эту часть правила держит спека `intake`.
|
||||
Наружу он при этом не выходит: карточка записи отдаёт причину остановки без
|
||||
машинного текста — эту часть правила держит спека `archive`.
|
||||
|
||||
## panic
|
||||
|
||||
@@ -156,11 +163,11 @@ transcriber — **приложение, а не библиотека**: внеш
|
||||
- Не для управления потоком и не для ожидаемых ошибок (нет сети, плохой ввод) —
|
||||
это значения `error`.
|
||||
- `recover` — на верхней границе обработчика, чтобы один паникующий запрос не
|
||||
ронял процесс. В transcriber его вешает роутер хранилища сам
|
||||
(`apis.panicRecover`, слой с идентификатором `DefaultPanicRecoverMiddlewareId`
|
||||
на каждом роутере PocketBase): паникующий обработчик отдаёт `500`, процесс
|
||||
живёт. Своего слоя мы не пишем. У воркеров такой границы **нет**: паника в
|
||||
шаге конвейера роняет процесс целиком.
|
||||
ронял процесс. В transcriber его ставит свой слой `http.Recover`: паникующий
|
||||
обработчик отдаёт `500` нашей формой тела, а строка о панике идёт в журнал
|
||||
владельца. Слой стал своим 2026-08-22 вместе с роутером — прежде его вешала
|
||||
чужая библиотека. У воркеров такой границы **нет**: паника в шаге конвейера
|
||||
роняет процесс целиком.
|
||||
|
||||
## Несколько ошибок
|
||||
|
||||
|
||||
Reference in New Issue
Block a user