12 KiB
Email OTP Auth Implementation Plan
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Включить реальный вход в приложение по одноразовому пинкоду из письма через Supabase только для заранее заведенных пользователей с ролями admin и logistician.
Architecture: Фронтенд остается на текущем AuthContext и OtpLoginForm, но demo-подсказки перестают влиять на рабочий auth flow. Supabase Auth отвечает за отправку email OTP и создание session, а приложение после подтверждения кода читает профиль только из public.users и roles. Новые пользователи через форму не создаются: доступ есть только у тех email, которые заранее заведены в auth.users и синхронизированы с public.users.
Tech Stack: React 18, Vite, Supabase JS v2, Supabase Auth Email OTP, Supabase SQL, Vitest.
File Structure
- Modify:
src/context/AuthContext.jsx— отключить автосоздание пользователей, ужесточить рабочий OTP-flow, обработать отсутствие профиля. - Modify:
src/context/AuthContext.test.js— покрыть новую логику для рабочего режима и сохранить demo-фолбэк. - Modify:
src/components/auth/OtpLoginForm.jsx— убрать рабочую зависимость от выбора demo-роли и уточнить тексты для OTP-входа. - Modify:
src/components/auth/OtpLoginForm.test.jsx— скорректировать ожидания под новый рабочий сценарий. - Modify:
src/pages/LoginPage.jsx— оставить линейный сценарийemail -> код -> вход, без влияния роли в production-режиме. - Create:
docs/operations/supabase-email-otp-auth.md— пошаговая настройка Supabase Auth, пользователей и ролей. - Reference:
src/supabaseClient.js— проверить, что frontend env уже подаются корректно. - Reference:
supabase/schema.sql— использовать существующиеroles,users,handle_new_user()и не дублировать auth-механику.
Chunk 1: Frontend Auth Flow Tightening
Task 1: Зафиксировать ожидаемое поведение auth-flow тестами
Files:
-
Modify:
src/context/AuthContext.test.js -
Modify:
src/components/auth/OtpLoginForm.test.jsx -
Step 1: Add failing tests for production OTP constraints
Добавить проверки на:
-
в рабочем режиме email не подменяется demo-значением;
-
форма не подсказывает выбор роли как источник прав;
-
текст формы объясняет вход по email-коду;
-
demo-режим остается рабочим fallback.
-
Step 2: Run targeted tests to verify they fail
Run: npm test -- src/context/AuthContext.test.js src/components/auth/OtpLoginForm.test.jsx
Expected: FAIL on outdated demo-oriented behavior.
- Step 3: Keep existing demo tests if still valid
Если текущие тесты про resolveDemoUser и resolveLoginEmail остаются полезными, сохранить их и добавить рядом production-specific expectations вместо полной замены.
- Step 4: Re-run targeted tests after each test update
Run: npm test -- src/context/AuthContext.test.js src/components/auth/OtpLoginForm.test.jsx
Expected: FAIL only for not-yet-implemented UI/auth changes.
Task 2: Отключить саморегистрацию через OTP-форму
Files:
-
Modify:
src/context/AuthContext.jsx -
Modify:
src/pages/LoginPage.jsx -
Step 1: Write the minimal production auth contract
В AuthContext зафиксировать:
-
requestOtp()вызываетsupabase.auth.signInWithOtp -
options.shouldCreateUserбольше не передается какtrue -
pendingEmailостается текущим entered email -
demo-mode behavior не ломается
-
Step 2: Make the implementation minimal
Изменить рабочий режим так, чтобы:
-
логин шел только для уже существующего email;
-
новая учетная запись не создавалась автоматически;
-
текст ошибки из Supabase пробрасывался наверх без маскировки.
-
Step 3: Verify the targeted auth tests
Run: npm test -- src/context/AuthContext.test.js
Expected: PASS
- Step 4: Sanity-check login screen code
Убедиться, что src/pages/LoginPage.jsx не передает рабочую роль из UI в production-сценарий и не связывает доступ с выбором roleHint.
Task 3: Привести OTP-форму к рабочему сценарию доступа по списку email
Files:
-
Modify:
src/components/auth/OtpLoginForm.jsx -
Modify:
src/components/auth/OtpLoginForm.test.jsx -
Step 1: Remove role selection from the production story
Сохранить roleHint только как demo-only affordance, но не показывать пользователю, что роль задается при реальном входе.
- Step 2: Update copy for real OTP flow
Тексты формы должны говорить:
-
email вводится пользователем;
-
код приходит на почту;
-
доступ определяется учетной записью в системе, а не выбором роли.
-
Step 3: Keep demo fallback explicit but isolated
Если isDemoMode === true, оставить подсказку и поведение demo-режима, но визуально отделить его от реального сценария.
- Step 4: Re-run form tests
Run: npm test -- src/components/auth/OtpLoginForm.test.jsx
Expected: PASS
Chunk 2: Profile Resolution And Access Guard
Task 4: Обработать сценарий “auth user есть, профиля в public.users нет”
Files:
-
Modify:
src/context/AuthContext.jsx -
Modify:
src/context/AuthContext.test.js -
Step 1: Add a failing test for missing profile
Проверить сценарий:
-
Supabase session создана;
-
запрос в
public.usersне нашел профиль или вернул ошибку; -
пользователь не считается успешно авторизованным в приложении без понятной реакции.
-
Step 2: Implement minimal guard
В onAuthStateChange:
-
если профиль не найден, не выдавать рабочий
userв приложение; -
сохранять понятную ошибку или вынуждать повторный вход;
-
не падать молча.
-
Step 3: Verify tests
Run: npm test -- src/context/AuthContext.test.js
Expected: PASS
Task 5: Уточнить контракт роли и профиля
Files:
-
Modify:
src/context/AuthContext.jsx -
Reference:
supabase/schema.sql -
Step 1: Verify role source
Роль должна читаться только из public.users -> roles(name).
- Step 2: Keep fallback conservative
Если роль не пришла, не повышать доступ по умолчанию; допустим fallback только в безопасный минимум (manager) либо ошибка доступа, в зависимости от того, что окажется проще и безопаснее после чтения кода.
- Step 3: Re-run auth tests
Run: npm test -- src/context/AuthContext.test.js
Expected: PASS
Chunk 3: Supabase Setup And Data Seeding
Task 6: Подготовить рабочую инструкцию по настройке Supabase Auth
Files:
-
Create:
docs/operations/supabase-email-otp-auth.md -
Step 1: Document dashboard settings
Описать:
-
где включить email OTP;
-
что проверить в email auth settings;
-
что self-signup должен быть выключен, если используется whitelist-only access.
-
Step 2: Document required frontend env
Зафиксировать:
-
VITE_SUPABASE_URL -
VITE_SUPABASE_ANON_KEY -
Step 3: Document function secrets separately
Коротко пояснить:
- frontend env идут в
.env.local; - Edge Function secrets задаются через Supabase secrets/dashboard;
- для OTP-входа frontend не использует
SUPABASE_SERVICE_ROLE_KEY.
Task 7: Подготовить SQL/операционную часть для двух пользователей
Files:
-
Create or extend:
docs/operations/supabase-email-otp-auth.md -
Reference:
supabase/schema.sql -
Step 1: Describe manual user creation in Supabase Auth
Нужно заранее создать:
-
skylanguage@yandex.ru -
mk7029953@yandex.ru -
Step 2: Document role binding in public.users
Подготовить SQL-пример или пошаговое описание, как этим пользователям назначить:
-
skylanguage@yandex.ru->admin -
mk7029953@yandex.ru->logistician -
Step 3: Check trigger compatibility
Убедиться по схеме, что handle_new_user():
-
не ломает вручную заведенных пользователей;
-
корректно пишет профиль в
public.users; -
использует
raw_user_meta_data ->> 'role', если оно есть. -
Step 4: Add operator verification checklist
Проверка после настройки:
- код приходит на обе почты;
adminвидит админский раздел;logisticianвидит логистический контур;- неизвестный email не получает доступ.
Chunk 4: End-To-End Verification
Task 8: Полная проверка реализации
Files:
-
Reference:
src/context/AuthContext.jsx -
Reference:
src/components/auth/OtpLoginForm.jsx -
Reference:
src/pages/LoginPage.jsx -
Reference:
docs/operations/supabase-email-otp-auth.md -
Step 1: Run focused frontend tests
Run: npm test -- src/context/AuthContext.test.js src/components/auth/OtpLoginForm.test.jsx
Expected: PASS
- Step 2: Run full test suite
Run: npm test
Expected: PASS
- Step 3: Run linter
Run: npm run lint
Expected: PASS
- Step 4: Run production build
Run: npm run build
Expected: PASS
- Step 5: Manual Supabase validation
Проверить руками:
- отправка кода на
skylanguage@yandex.ru - отправка кода на
mk7029953@yandex.ru - успешный вход по пинкоду
- корректная роль после входа
- отказ для email вне whitelist