Контекст
На шаге ввода OTP после регистрации (SignupPage) и восстановления пароля (ForgotPasswordPage) отображается ResendCodeControl с таймером повторной отправки (RESEND_CODE_DELAY_MS = 60 с, ключ в localStorage). По истечении таймера кнопка «Отправить код» активна, но по клику вызывается заглушка: toast.warning('Функционал в разработке!') в src/features/otp-form/ui/ResendCodeControl.tsx.
Пользователь не может запросить новый код, если письмо не пришло или код истёк. API для resend на бэкенде ещё не реализован — задача в бэклог: согласовать контракт, реализовать бэк, затем подключить фронт. UI-таймер и черновик lastSentAt уже есть и должны быть синхронизированы с серверным rate limit.
| Сценарий |
Страница |
Первичная отправка |
Подтверждение OTP |
| Регистрация |
SignupPage |
POST /auth/sign-up |
POST /auth/sign-up/confirm |
| Сброс пароля |
ForgotPasswordPage |
POST /auth/password/reset |
POST /auth/password/reset/verify |
Технические требования
Бэкенд (блокер)
POST /auth/sign-up/resend — body: { email }
POST /auth/password/reset/resend — body: { email }
- Альтернатива: идемпотентный повтор
sign-up / password/reset с тем же email — зафиксировать в контракте
- Rate limiting: не чаще 1 раза в N сек (согласовать с
RESEND_CODE_DELAY_MS = 60000); при превышении — 429 или error с retryAfter
- Безопасность: единые ответы без утечки существования email; лимиты по IP/email; инвалидация старого кода при выдаче нового
Фронтенд (после готовности API)
- Локация:
src/features/otp-form/ui/ResendCodeControl.tsx, src/entities/auth/api/http.ts, src/entities/auth/model/schemas.ts, SignupPage, ForgotPasswordPage
- Инструменты: TanStack Query, Zod,
sonner, LocalStorageDraft, useTimer
- Логика:
ResendCodeControl — проп onResend / mutation + email; убрать заглушку с toast
AuthHttp.signupResend, AuthHttp.resetPasswordResend + хуки useResendSignupCode, useResendResetPasswordCode
- Подключить на
/signup и /forgot-password (шаг otp)
- Успех:
toast.success, обновить lastSentAt, restart() таймера
429 / retryAfter: синхронизировать таймер с сервером
isPending — disabled кнопки
- До бэка (опционально):
NEXT_PUBLIC_OTP_RESEND_ENABLED — скрыть кнопку вместо заглушки
Цель и критерии приемки (Definition of Done)
Зависимости
- Backend: контракт + реализация
- Frontend: HTTP + хуки +
ResendCodeControl
- QA: оба флоу, спам-клики, истёкший draft
Важные указания
- Безопасность: не логировать OTP;
email из draft с TTL (DRAFT_TTL_MS)
- Ошибки:
skipGlobalValidationToast по аналогии с useSignupConfirm / useSendCode
Контекст
На шаге ввода OTP после регистрации (
SignupPage) и восстановления пароля (ForgotPasswordPage) отображаетсяResendCodeControlс таймером повторной отправки (RESEND_CODE_DELAY_MS= 60 с, ключ вlocalStorage). По истечении таймера кнопка «Отправить код» активна, но по клику вызывается заглушка:toast.warning('Функционал в разработке!')вsrc/features/otp-form/ui/ResendCodeControl.tsx.Пользователь не может запросить новый код, если письмо не пришло или код истёк. API для resend на бэкенде ещё не реализован — задача в бэклог: согласовать контракт, реализовать бэк, затем подключить фронт. UI-таймер и черновик
lastSentAtуже есть и должны быть синхронизированы с серверным rate limit.SignupPagePOST /auth/sign-upPOST /auth/sign-up/confirmForgotPasswordPagePOST /auth/password/resetPOST /auth/password/reset/verifyТехнические требования
Бэкенд (блокер)
POST /auth/sign-up/resend— body:{ email }POST /auth/password/reset/resend— body:{ email }sign-up/password/resetс тем же email — зафиксировать в контрактеRESEND_CODE_DELAY_MS= 60000); при превышении —429или error сretryAfterФронтенд (после готовности API)
src/features/otp-form/ui/ResendCodeControl.tsx,src/entities/auth/api/http.ts,src/entities/auth/model/schemas.ts,SignupPage,ForgotPasswordPagesonner,LocalStorageDraft,useTimerResendCodeControl— пропonResend/ mutation +email; убрать заглушку с toastAuthHttp.signupResend,AuthHttp.resetPasswordResend+ хукиuseResendSignupCode,useResendResetPasswordCode/signupи/forgot-password(шагotp)toast.success, обновитьlastSentAt,restart()таймера429/retryAfter: синхронизировать таймер с серверомisPending— disabled кнопкиNEXT_PUBLIC_OTP_RESEND_ENABLED— скрыть кнопку вместо заглушкиЦель и критерии приемки (Definition of Done)
Зависимости
ResendCodeControlВажные указания
emailиз draft с TTL (DRAFT_TTL_MS)skipGlobalValidationToastпо аналогии сuseSignupConfirm/useSendCode