feat(web): sign-in, first-run setup, app shell and user admin (M1)
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 50s
ci / ts / ts (packages + web) (push) Successful in 43s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 27s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m22s

- core: AuthSession keeps the access token in memory, refreshes it
  once for all parallel requests (single-flight) and retries them;
  refresh races between tabs are retried, reuse signs out; ApiError
  carries problem+json codes and field errors
- web: TanStack Router with guards — guests go to /login, the bootstrap
  admin to /setup/admin, temporary passwords to /setup/password, admin
  pages by role
- login, setup screens, Classic shell (top bar, role-based sidebar,
  empty player), settings: name, theme, language, password, devices
- users admin: search, role filter, create with a one-time temporary
  password, reset, block, role change, delete as the policy allows;
  audit log for admins
- ru/en strings for auth, admin and error codes; language and theme
  are saved in the profile

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-20 06:33:46 +03:00
1 parent f075863f15
commit ab092def54
44 files changed
+4070 -203

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
{
"users": {
"title": "Пользователи",
"subtitle": "Создание пользователей и модераторов, роли, сброс пароля, блокировка",
"create": "Создать пользователя",
"search": "Имя или логин",
"all": "Все",
"col_user": "Пользователь",
"col_role": "Роль",
"col_status": "Статус",
"col_last_login": "Был в сети",
"status_active": "Активен",
"status_blocked": "Заблокирован",
"status_must_change": "Ждёт смены пароля",
"never": "Ещё не входил",
"empty": "Никого не нашли",
"more": "Показать ещё",
"actions": "Действия с {{username}}",
"reset_password": "Сбросить пароль",
"block": "Заблокировать",
"unblock": "Разблокировать",
"make_role": "Сделать: {{role}}",
"delete": "Удалить",
"delete_confirm": "Удалить {{username}}? Его история и лайки пропадут.",
"block_confirm": "Заблокировать {{username}}? Все его сессии завершатся.",
"reset_confirm": "Сбросить пароль {{username}}? Все его сессии завершатся.",
"confirm": "Подтвердить",
"you": "вы"
},
"create": {
"title": "Новый пользователь",
"username": "Логин",
"username_hint": "Латинские буквы, цифры, «.», «_», «-»",
"display_name": "Имя",
"role": "Роль",
"password_note": "Пароль сгенерирует сервер и покажет один раз.",
"submit": "Создать"
},
"temp_password": {
"title": "Временный пароль",
"text": "Передайте пароль пользователю {{username}}. Он виден только сейчас; при входе его попросят сменить.",
"done": "Готово"
},
"audit": {
"title": "Журнал",
"subtitle": "Действия администраторов и модераторов",
"col_when": "Когда",
"col_who": "Кто",
"col_action": "Действие",
"col_details": "Подробности",
"system": "Система",
"empty": "Записей пока нет",
"more": "Показать ещё",
"actions": {
"user.bootstrap_create": "Создан стартовый администратор",
"user.bootstrap_credentials": "Заданы учётные данные администратора",
"user.create": "Создан пользователь",
"user.rename": "Изменено имя",
"user.role_change": "Изменена роль",
"user.block": "Пользователь заблокирован",
"user.unblock": "Пользователь разблокирован",
"user.password_reset": "Сброшен пароль",
"user.delete": "Пользователь удалён"
}
}
}