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

+7 -3
View File
@@ -1,7 +1,11 @@
import i18next, { type i18n as I18n } from 'i18next';
import enAdmin from '../locales/en/admin.json';
import enAuth from '../locales/en/auth.json';
import enCommon from '../locales/en/common.json';
import enErrors from '../locales/en/errors.json';
import ruAdmin from '../locales/ru/admin.json';
import ruAuth from '../locales/ru/auth.json';
import ruCommon from '../locales/ru/common.json';
import ruErrors from '../locales/ru/errors.json';
@@ -11,8 +15,8 @@ export type Locale = (typeof SUPPORTED_LOCALES)[number];
export const DEFAULT_LOCALE: Locale = 'en';
export const resources = {
ru: { common: ruCommon, errors: ruErrors },
en: { common: enCommon, errors: enErrors },
ru: { common: ruCommon, auth: ruAuth, admin: ruAdmin, errors: ruErrors },
en: { common: enCommon, auth: enAuth, admin: enAdmin, errors: enErrors },
} as const;
declare module 'i18next' {
@@ -40,7 +44,7 @@ export async function createI18n(locale: Locale): Promise<I18n> {
fallbackLng: DEFAULT_LOCALE,
supportedLngs: [...SUPPORTED_LOCALES],
defaultNS: 'common',
ns: ['common', 'errors'],
ns: ['common', 'auth', 'admin', 'errors'],
resources,
interpolation: { escapeValue: false },
returnNull: false,