Files
transcriber/docs/passport.md
T
av 7f33c957e5 вход переехал на доверенный заголовок Authelia вместо собственного OIDC
- пришедшего называет заголовок Remote-User от прокси, и верят ему только с
  адреса из перечня trusted_proxies; своего входа у сервиса не осталось — ни
  корня /auth, ни кук, ни срока сессии, ни секрета клиента в конфиге и в базе
- учётная запись заводится первым обращением: EnsureUser в пакете хранилища,
  шаг схемы 202608220001 с колонкой provider_login и снятыми правилами users
- cmd/oidcstub заменён на cmd/devtools с подкомандой proxy; заодно закрыт
  унаследованный DL3066 — пользователь образа назван числом
2026-08-22 20:24:22 +03:00

127 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Паспорт проекта
Зачем это и для кого. [architecture.md](architecture.md) отвечает «как
устроено», [tasks/BACKLOG.md](../tasks/BACKLOG.md) — «в каком порядке», паспорт —
«зачем и для кого».
## Цель
Превращать записанную речь в текст, который можно читать и искать, и хранить
этот текст вместе с записью.
**Сервис — архив, и это решено 2026-08-11.** Прежде граница читалась «отдаём
текст и на этом заканчиваем»; теперь расшифровки и исходные записи лежат
бессрочно, а список отбирается по темам. Причина в основном сценарии: семейный
архив загружают один раз, а возвращаются к нему годами.
**Потребители** — список закрытый: он определяет, что считать нужным, а что
интересным.
| Кто | Что ему нужно от нас |
| --- | --- |
| Владелец сервиса | Загрузить диктофонную запись или видео из семейного архива с телефона и получить текст. Видеть, кто сколько загрузил и во что это обошлось |
| Приглашённый пользователь | Войти в приложение через свою учётную запись, загрузить запись, забрать текст, вернуться к ней через месяц. Приложение ставится на телефон; каждый видит только свои записи |
| Внешняя программа | Отдать файл по HTTP, представившись своим токеном, и опросить готовность. Сегодня не работает вовсе: домен целиком стоит за обратным прокси, и запрос программы отбивает он, не доходя до сервиса. Токен и правило прокси мимо входа приносит `api-tokens` |
**Вход у сервиса один — HTTP API**, и приложение строится поверх него. До
2026-08-11 основным входом был Telegram-бот. 2026-08-11 основным объявили
приложение: диктофонная запись на несколько часов через Telegram не проходит
вовсе. 2026-08-14 бот убран целиком — временно, до задачи, которая свяжет чат с
учётной записью. Вместе с ним из потребителей ушёл пользователь
Telegram.
Цель достигнута, когда:
- запись любого распространённого формата принимается без предварительной
подготовки, включая дорожку из видео;
- запись расчётного потолка — шести часов — доходит до текста, а не прерывается
ошибкой при достижении предела (норма — `openspec/specs/storage`);
- сервисом пользуются несколько человек, и записи одного не видны другому;
- текст доступен там же, где загружали. Человек узнаёт о его готовности, не
держа приложение открытым;
- расшифровка не теряется: к записи возвращаются через месяц и находят её по
заголовку и темам;
- владелец видит расход по каждому пользователю и понимает, во что обходится
приглашение ещё одного человека.
## Что целью не является
Граница домена. По ней в теме `architecture` судят, не перенесено ли понятие
через границу.
- **Правка текста руками.** Машинную вычитку расшифровки отдаём — литературный
текст стоит рядом с сырым, — а редактором не становимся: текст руками не
правим, не размечаем и не экспортируем в форматы документов. Граница сдвинута
2026-08-11: до того запрет читался «расшифровку отдаём как есть».
- **Разговор о записи.** Ответы на вопросы по содержанию и поиск по смыслу — за
границей. Заголовок, пересказ и темы **внутри** границы: она сдвинута
2026-08-10, и до того запись читалась «мы отдаём текст, а не выводы из него».
Считать уровни текста берётся задача
[llm-insights-adapter](../tasks/items/llm-insights-adapter.md).
- **Собственные модели.** Не обучаем и не держим у себя ни модель распознавания,
ни языковую модель: и речь, и выводы из текста считает внешний сервис.
- **Управление учётными записями.** Пользователей заводит и проверяет внешний
провайдер, свою регистрацию и свои пароли не делаем. Своя строка учётной
записи у сервиса при этом есть, и границы это не двигает: сервис **зеркалит**
имя, названное провайдером, — заводит строку при первом обращении под новым
именем и связывает с ней записи владельца. Кто этот человек и пускать ли его,
сервис не решает никогда. Одно исключение появилось 2026-08-11 вместе с
решением про PocketBase: в панель администратора владелец входит своим
паролем, потому что подпустить к ней внешнего провайдера PocketBase не даёт.
- **Живая расшифровка.** Работаем с готовой записью, поток в реальном времени не
обрабатываем.
- **Диктофон.** Запись звука делает телефон, а приложение принимает готовый
файл. Своей записи и работы без сети не делаем.
- **Файловое хранилище общего назначения.** Храним аудио и видео, отданные ради
речи в них. Складом произвольных файлов и папками сервис не становится. Общего
доступа к чужим записям целью нет, и с 2026-08-14 его нет и на деле: у записи
есть владелец, и чужую по её идентификатору не отдают
([security.md](security.md), «Периметр»). Закрыла это задача
`record-ownership`.
- **Учёт денег.** Считаем объём, минуты и токены по каждому пользователю и
показываем их владельцу. Цен, счетов и отказов по исчерпании квоты не делаем:
пользователя, потратившего слишком много, останавливает разговор или отзыв
доступа в Authelia.
## Типовые сценарии
Первые два — основные, и сегодня не работает ни один. Приложение с 2026-08-15
есть, но экранов у него пока нет: оно открывается и показывает вошедшего, а
загрузку и список заводят `upload-and-status-screen` и `records-list-screen`.
1. **Семейный архив.** Человек открывает приложение на телефоне, выбирает до
десяти записей разом — диктофонные дорожки и видео, — и закрывает его.
Загрузка показывает ход. Файл, который уже загружали, не грузится второй
раз. Когда текст готов, приходит уведомление; в списке запись видна
заголовком и темами.
2. **Возвращение к записи.** Через месяц человек открывает список, находит
запись по заголовку или теме и читает вычитанный текст, а при нужде — сырую
расшифровку.
3. **Загрузка по HTTP.** Программа шлёт `POST /app/audiorecords` со своим
токеном, получает идентификатор записи и читает её карточку
`GET /app/audiorecords/{id}`, пока не увидит `done`; текст забирает отдельным
адресом `GET /app/audiorecords/{id}/text`. Сегодня доступно только тому, кого
назвал доверенный источник: неузнанный запрос всеми адресами отклоняется.
Своего способа представиться у программы нет — его заводит `api-tokens`.
Записи при этом разграничены: видны только записи того, чьим именем пришли.
4. **Отказ на середине.** Конвертация или распознавание не удались — запись
получает признак остановки с причиной, и карточка записи отдаёт признак и
причину тому, кто её загрузил. Сообщения о неудаче сервис никому не шлёт:
доставка ушла вместе с ботом, а уведомления заводит задача `ntfy-delivery`.
## Референсы
Где смотреть prior art, когда упёрлись.
- **Yandex SpeechKit, отложенное распознавание** — модель `deferred-general`,
которой пользуемся: она и задаёт потолок по длине записи и формату.
- **Whisper и его серверные обёртки** — запасной путь, если внешний сервис
перестанет устраивать по цене или по качеству русской речи.
**PocketBase** из референсов ушла: она больше не кандидат — в стек её перевела
задача `pocketbase-storage` 2026-08-12
([adr](adr/ADR-2026-08-11-pocketbase-storage-with-admin-panel.md)); там она
держит хранилище, файлы и панель владельца. Схема и
раскладка — [database.md](database.md). Учётные записи она хранит, а заводит их
сервис по имени, названному Authelia; источником людей она при этом не
становится: заводит и проверяет их по-прежнему Authelia.