Направление работ: AdmLk
Код раздела: 1.1
Раздел: Вход
Статус: черновик
Ответственный: Панкова Л.А.
Версия: 0.1
Обновлено: 15.07.26
1. Назначение
Раздел описывает вход пользователя в сервисную зону МАРТ по email или телефону и паролю.
Интерфейс должен проверить учетные данные, показать ошибку при неуспешном входе или открыть сервисную зону при наличии доступа.
2. Ключевые понятия
Вход в сервисную зону — сценарий доступа пользователя в AdmLk по учетным данным аккаунта.
Учетные данные — email или телефон и пароль пользователя.
Сервисная зона — зона управления системой и глобальными настройками.
3. Scope
Входит
S1. Форма входа.
S2. Отправка учетных данных.
S3. Ошибки входа и отсутствия доступа.
Не входит
- Back 1.1.2 — вход в систему.
- Back 1.2 — проверка доступа к сервисной зоне.
- AdmLk 1.2 — главная страница после входа.
- AdmLk 3.7 — сотрудники и доступ к сервисной зоне.
4. BR
Указаны в Back 1.1.2 «Вход в систему» и Back 1.2 «Организация доступа к системе».
5. Функциональные требования
| ID | Сценарий | Функциональное требование | BR | Вес | Статус |
|---|---|---|---|---|---|
| FR1.1-1 | S1. Пользователь открывает вход | Интерфейс показывает поля «Email или телефон» и «Пароль», а также кнопку «Продолжить». | 1 | Реализовано | |
| FR1.1-2 | S1. Пользователь заполняет форму | Интерфейс принимает email или телефон, маскирует пароль и позволяет показать или скрыть пароль. | 1 | Реализовано | |
| FR1.1-3 | S2. Пользователь отправляет данные | Интерфейс активирует «Продолжить» после заполнения обязательных полей и отправляет учетные данные на проверку. | 1 | Частично \ #OQ1.1-8 | |
| FR1.1-4 | S2. Вход выполнен успешно | Интерфейс открывает сервисную зону, если учетные данные верны и у пользователя есть доступ. | 1 | Частично \ #OQ1.1-6 | |
| FR1.1-5 | S3. Данные неверные | Интерфейс показывает ошибку «Неверный логин или пароль» и позволяет исправить учетные данные. | 1 | Частично \ #OQ1.1-5 | |
| FR1.1-6 | S3. Доступ отсутствует | Интерфейс показывает ошибку «Вход не выполнен. Отсутствует доступ» и кнопку «Войти в другой аккаунт». | 1 | Не реализовано \ #OQ1.1-2 | |
| FR1.1-7 | S3. Пользователь выбирает другой аккаунт | Интерфейс возвращает пользователя к форме входа для ввода других учетных данных. | 2 | Не реализовано \ #OQ1.1-3 |
6. Открытые вопросы
| ID | Источник | Вопрос | Кому | Статус | Рекомендации | Итоговое решение |
|---|---|---|---|---|---|---|
| #OQ1.1-1 | Figma / Back \ Код вне BRD | Должен ли AdmLk поддерживать восстановление пароля со страницы входа или сценарий вынесен за рамки текущего раздела? По коду: уже реализовано — на форме есть кнопка «Забыл пароль» → /auth/password-recovery, присутствует полный сценарий восстановления. \ LoginForm.vue:51-58; features/auth-password-recovery; AuthService.ts:85-112 | Бизнес (Герман) | Open | Вопрос из стадии A снят наполовину: код отвечает «поддерживается». Осталось продуктовое решение. (А, рекоменд.) закрыть вопрос как «поддерживается» и добавить требование на «Забыл пароль» в scope 1.1; (Б) если восстановление не должно жить в сервисном кабинете — скрыть кнопку и явно вынести за скоуп. | Артем: по коду еще нормально не реализовано. Весь раздел в любом случае нужно будет переписывать, перенося наработки Кости. Восстановление пароля я бы оставил. |
| #OQ1.1-2 | Код FR1.1-6 | Требование говорит: при отсутствии доступа показать «Вход не выполнен. Отсутствует доступ» и кнопку «Войти в другой аккаунт». В коде сценария нет вообще: при успехе всегда редирект на /, при любой ошибке — только «Неверный логин или пароль»; состояние «нет доступа» не различается. \ useAuthLogin.ts:16-33 (поиск по «Отсутствует доступ»/«Войти в другой» — совпадений нет) | Бизнес/Разработка | Open | Требование веса 1 не реализовано; «нет доступа» неотличим от «неверный пароль». Механика упирается в контракт: согласовать с Back: 1.2, возвращает ли бэкенд отдельный код отказа по доступу. (А, рекоменд.) бэкенд даёт код отказа → фронт показывает экран «Отсутствует доступ» + «Войти в другой аккаунт»; (Б) если отказ по доступу на этом этапе невозможен — зафиксировать в BRD, что FR1.1-6/FR1.1-7 вне текущей реализации, и снять вес 1. Связать с OQ1.1-3, OQ1.1-5. | Артем: весь вход был сделан еще до моего прихода, его в любом случае переписывать, так что я бы на него не ориентировался. Зачем нужна отдельная кнопка “Войти в другой аккаунт” я не понимаю - по сути мы еще ни в один не вошли. Выглядит, как лишний отвлекающий визуальный мусор. Я бы оставил только предупреждение “Вход не выполнен. Отсутствует доступ” |
| #OQ1.1-3 | Код FR1.1-7 | Требование говорит: «Войти в другой аккаунт» возвращает пользователя к форме входа. В коде кнопки и перехода нет — зависит от отсутствующего экрана отказа (см. OQ1.1-2); отдельный механизм выхода существует, но с экраном отказа не связан. \ features/auth-logout/model (поиск по «Войти в другой» — совпадений нет) | Бизнес/Разработка | Open | Производная от OQ1.1-2 — без экрана отказа кнопке негде жить. Рекомендация: при реализации переиспользовать features/auth-logout (кнопка = выход + возврат к форме). Решается вместе с OQ1.1-2. | Артем: см. предыдущий пункт. Если сделать отдельное отображение кнопки, которое будет возвращать обратно, то это абсолютно бессмысленное принуждение пользователя кликать на кнопку после каждой неудачной попытки. По мне, сообщения с ошибкой достаточно. |
| #OQ1.1-4 | Код вне BRD | Что нашли: на форме входа есть кнопка «Регистрация» → /auth/registration, а весь вход построен на партнёрском сценарии (эндпоинт LoginPartner). В BRD 1.1 саморегистрация не описана. \ LoginForm.vue:42-49; server/api/auth/login.post.ts:25 | Бизнес (Герман) | Open | Экран входа переиспользован из партнёрского кабинета. Решение бизнеса: нужна ли кнопка «Регистрация» в сервисной зоне (доступ туда выдаётся через AdmLk 3.7 / Back 8.1, а не самозаписью). (А, рекоменд.) убрать кнопку и вынести саморегистрацию за скоуп; (Б) если нужна — внести требованием. Контракт партнёрского входа — отдельный вопрос OQ1.1-9. | Артем: реализация раздела черновая. Считаю, что кнопку стоит убрать. |
| #OQ1.1-5 | Код FR1.1-5 | Требование говорит: показать «Неверный логин или пароль» и дать исправить данные. В коде текст верен для неверных данных, но захардкожен на ЛЮБУЮ ошибку: сервер маппит все не-OK ответы в это сообщение, а форма игнорирует реальный текст ошибки — сеть, сбой сервера и «нет доступа» тоже показываются как «Неверный логин или пароль». \ LoginForm.vue:79-84; server/api/auth/login.post.ts:39-46 | Разработка | Закрывает PM | Хардкод текста на любую ошибку — дефект, продуктового выбора нет (какой текст для отказа по доступу — решается в OQ1.1-2). Закрываю сам: пробрасывать реальный код/текст ошибки от бэкенда, «Неверный логин или пароль» показывать только для invalid-credentials, для сети/сервера — отдельный текст → тикет в Bitrix. Это же открывает механику для OQ1.1-2. | Артем: реализация раздела черновая. Нужно переделать |
| #OQ1.1-6 | Код FR1.1-4 | Требование говорит: после верного входа открыть сервисную зону. В коде редирект на / есть, но auth_token ставится httpOnly, а проверки isAuthenticated/isTokenValid читают его через document.cookie — на клиенте всегда false, из-за чего глобальный middleware дёргает refresh-token на каждом переходе. \ login.post.ts:58,64; account.session.ts:21-27; AuthService.ts:159-163; auth.global.ts:34-49 | Разработка (Влад) | Open | Вход работает, но механика сессии на клиенте сломана — лишний refresh на каждом переходе. Выбор архитектурный. Вопрос к Владу: (А, рекоменд.) определять авторизацию по состоянию сессии / ответу /api/auth/account, а не по httpOnly-куке (её из JS не видно), либо добавить лёгкую не-httpOnly куку-флаг; (Б) оставить как есть, приняв refresh на каждом переходе как цену (хуже по производительности). | Артем: реализация раздела черновая. Нужно переделать |
| #OQ1.1-7 | Код вне BRD | Что нашли: две точки входа на одну форму — /auth/authorization и /login (через отдельный widget на тот же LoginForm); в middleware публичен только /auth/authorization, а /login — нет, поэтому неавторизованного с /login редиректит прочь. Плюс два почти одинаковых middleware. \ pages/login.vue:1-7; widgets/auth-login/ui/AuthLoginWidget.vue:1-8; auth.global.ts:20-29; middleware/auth.ts:20-25 | Разработка | Закрывает PM | Дубль маршрута с нерабочим поведением (/login недоступен неавторизованному — то есть тем, кому он и нужен), продуктового вопроса нет. Закрываю сам: оставить один маршрут /auth/authorization, удалить /login + widget (или сделать редирект), свести два middleware к одному → тикет в Bitrix. | Артем: реализация раздела черновая. Нужно переделать |
| #OQ1.1-8 | Код FR1.1-3 | Требование говорит: активировать «Продолжить» после заполнения обязательных полей. В коде кнопка активна не по «заполненности», а по валидному формату email/телефона и паролю ≥ 4 символов; порог 4 расходится с PASSWORD_MIN_LENGTH=8 и схемой min(1) — три разных значения в одном проекте. \ LoginForm.vue:87-112; error-messages.ts:18; auth.schema.ts:28 | Разработка | Закрывает PM | Гейт строже требования + рассинхрон порогов (4 / 8 / 1). Длину пароля на входе проверяет бэкенд, навязывать её форме незачем. Закрываю сам: гейтить кнопку по непустым полям, длину/сложность на входе не проверять; пороги, если нужны, вынести в конфиг и устранить рассинхрон → тикет в Bitrix. | Артем: реализация раздела черновая. Нужно переделать |
| #OQ1.1-9 | Код вне BRD | Что нашли: вход сервисной зоны идёт через IdentityService/LoginPartner, тело запроса — fullPhoneNumber. То есть сервисный кабинет логинится партнёрским методом. \ server/api/auth/login.post.ts:20-25; AuthService.ts:16-24 | Разработка (Влад) | Open | Вопрос к Владу + Back: 1.1.2: верный ли это метод/контракт identity для сервисного кабинета. (А) подтвердить, что LoginPartner применим и для сервисной зоны; (Б) завести отдельный service-login контракт. Связано с OQ1.1-4 (экран переиспользован из партнёрского кабинета) и с OQ1.1-2 (где живёт отказ по доступу). | Артем: считаю, что лучше добавить сервисный метод |
Вопросы по сверке с кодом
BRD 1.1 v0.1 · musbooking.weblk.adminpanel · commit c376579/main · 2026-07-10 · якорь
features/auth-login(+pages/auth/authorization.vue,entities/account,shared/api/AuthService.ts,server/api/auth) Сводка: вопросов 9 (бизнесовых 4 / программных 5) · подтверждено без вопросов 2 (FR1.1-1, FR1.1-2) · отрезано находок обратного прохода 4 (фильтр кириллицы/пробелов в пароле, дропдаун кодов стран и международный формат телефона, выход из системы, перехватчик обновления токена) Под особым вниманием: FR1.1-6 / FR1.1-7 — сценарий «отсутствует доступ» в коде не реализован; FR1.1-4 — хранение токена/сессии на клиенте работает не так, как ожидается.
Бизнесовые
| № | Связано с | Что в BRD | Что в коде | Где в коде |
|---|---|---|---|---|
| Б1 | FR1.1-6 | При отсутствии доступа показать «Вход не выполнен. Отсутствует доступ» и кнопку «Войти в другой аккаунт» | Сценария нет: при успехе всегда редирект на /, при любой ошибке — только «Неверный логин или пароль»; состояние «нет доступа» не различается — нужно решение по UX отказа в доступе | useAuthLogin.ts:16-33; grep по «Отсутствует доступ»/«Войти в другой» — совпадений нет |
| Б2 | FR1.1-7 | «Войти в другой аккаунт» возвращает пользователя к форме входа | Кнопки и перехода нет (зависит от Б1); отдельный механизм выхода есть, но с экраном отказа не связан | features/auth-logout/model; grep по «Войти в другой» — совпадений нет |
| Б3 | OQ1.1-1 | Открытый вопрос: поддерживать ли восстановление пароля со страницы входа | Уже реализовано: на форме есть кнопка «Забыл пароль» → /auth/password-recovery, присутствует полный сценарий восстановления — нужно решение, оставляем ли в скоупе AdmLk 1.1 | LoginForm.vue:51-58; features/auth-password-recovery; AuthService.ts:85-112 |
| Б4 | вне BRD | — | На форме входа есть кнопка «Регистрация» → /auth/registration, а весь вход построен на партнёрском сценарии (эндпоинт LoginPartner) — нужно решение, входит ли саморегистрация / партнёрский вход в сервисный кабинет | LoginForm.vue:42-49; server/api/auth/login.post.ts:25 |
Рекомендация / варианты решения
- Сценарий отсутствия доступа (Б1, Б2; механика — П1) — сейчас «нет доступа» неотличим от «неверный пароль». Вариант А (рекоменд.): бэкенд (Back 1.2) возвращает отдельный код отказа, фронт показывает экран «Отсутствует доступ» + «Войти в другой аккаунт» (кнопка = выход + возврат к форме, переиспользовать
features/auth-logout). Вариант Б: если для сервисного кабинета отказ по доступу на этом этапе невозможен — зафиксировать в BRD, что FR1.1-6 / FR1.1-7 вне текущей реализации, и снять вес 1. - Восстановление пароля (Б3) — код уже поддерживает. Вариант А (рекоменд.): закрыть OQ1.1-1 как «поддерживается» и добавить требование на «Забыл пароль». Вариант Б: если восстановление не должно жить в сервисном кабинете — скрыть кнопку и явно вынести за скоуп.
- Саморегистрация и партнёрский вход (Б4; контракт — П5) — экран входа переиспользован из партнёрского кабинета. Согласовать с продуктом: нужна ли кнопка «Регистрация» в сервисной зоне и корректен ли партнёрский identity-флоу; при отказе — убрать кнопку и уточнить контракт входа.
Программные
| № | Связано с | Что в BRD | Что в коде | Где в коде |
|---|---|---|---|---|
| П1 | FR1.1-5 | Показать «Неверный логин или пароль» и дать исправить данные | Текст верен для неверных данных, но захардкожен на ЛЮБУЮ ошибку: сервер маппит все не-OK ответы в это сообщение, а форма игнорирует реальный текст ошибки — сеть/сервер/«нет доступа» тоже показываются как «Неверный логин или пароль» | LoginForm.vue:79-84; server/api/auth/login.post.ts:39-46 |
| П2 | FR1.1-4 | После верного входа открыть сервисную зону | Редирект на / есть, но auth_token ставится httpOnly, а isAuthenticated / isTokenValid читают его через document.cookie — на клиенте всегда false, из-за чего глобальный middleware дёргает refresh-token на каждом переходе | login.post.ts:58,64; account.session.ts:21-27; AuthService.ts:159-163; auth.global.ts:34-49 |
| П3 | вне BRD | — | Две точки входа на одну форму: /auth/authorization (pages/auth) и /login (pages/login.vue → widgets/auth-login → тот же LoginForm); в middleware публичен только /auth/authorization, /login — нет, неавторизованного с /login редиректит прочь. Плюс два почти одинаковых middleware | pages/login.vue:1-7; widgets/auth-login/ui/AuthLoginWidget.vue:1-8; auth.global.ts:20-29; middleware/auth.ts:20-25 |
| П4 | FR1.1-3 | Активировать «Продолжить» после заполнения обязательных полей | Кнопка активна не по «заполненности», а по валидному формату email/телефона и паролю ≥ 4 символов; порог 4 расходится с PASSWORD_MIN_LENGTH=8 и схемой min(1) | LoginForm.vue:87-112; error-messages.ts:18; auth.schema.ts:28 |
| П5 | вне BRD | — | Вход сервисной зоны идёт через IdentityService/LoginPartner, тело запроса — fullPhoneNumber; подтвердить, что это верный метод/контракт identity для сервисного кабинета (Back 1.1.2) | server/api/auth/login.post.ts:20-25; AuthService.ts:16-24 |
Рекомендация / варианты решения
- Разделение ошибок входа (П1; закрывает механику Б1) — Вариант А (рекоменд.): пробрасывать реальный код/текст ошибки от бэкенда и показывать «Неверный логин или пароль» только для invalid-credentials, «Отсутствует доступ» — для отказа по доступу, отдельный текст — для сети/сервера. Вариант Б (минимум): не хардкодить текст, а показывать фактический
session.error. - Хранение токена/сессии на клиенте (П2) — Вариант А (рекоменд.): определять авторизацию по состоянию сессии / ответу
/api/auth/account, а не по httpOnly-куке (её из JS не видно) — либо добавить лёгкую не-httpOnly куку-флаг. Вариант Б: оставить как есть, осознанно приняв refresh на каждом переходе как цену (хуже по производительности). - Дубли точек входа и middleware (П3) — Вариант А (рекоменд.): оставить один маршрут (
/auth/authorization), удалить/login+ widget или сделать из него редирект, свести два middleware к одному. Вариант Б: если/loginнужен — добавить его в список публичных маршрутов. - Порог валидации кнопки (П4) — логину лучше не навязывать длину пароля (её проверяет бэкенд). Вариант А (рекоменд.): гейтить кнопку по непустым полям, длину/сложность на входе не проверять. Вариант Б: если формат-валидация нужна — вынести пороги в конфиг и устранить рассинхрон 4 / 8 / 1.
- Контракт метода входа (П5) — подтвердить с бэкендом (Back 1.1.2), что
LoginPartner— правильный метод для сервисной зоны; при необходимости завести отдельный service-login контракт.