Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# OAuth Schema - VoIdea
|
||||
|
||||
**Дата:** 2026-05-10
|
||||
**Статус:** Backlog (для фиксации ADR)
|
||||
|
||||
---
|
||||
|
||||
## Обзор
|
||||
|
||||
Схема авторизации: один пользователь = один провайдер. Нельзя привязать Google если уже есть Яндекс.
|
||||
|
||||
---
|
||||
|
||||
## Правила
|
||||
|
||||
### Основное правило
|
||||
|
||||
> Один пользователь = один провайдер (email или OAuth)
|
||||
|
||||
Это означает:
|
||||
- Если зарегистрировался через Яндекс → только Яндекс
|
||||
- Если зарегистрировался через Google → только Google
|
||||
- Если зарегистрировался через email → только email + пароль
|
||||
|
||||
### Нельзя
|
||||
|
||||
- Привязать Google к аккаунту зарегистрированному через Яндекс
|
||||
- Добавить второй OAuth провайдер
|
||||
- Изменить email после регистрации через OAuth
|
||||
|
||||
---
|
||||
|
||||
## Структура данных
|
||||
|
||||
### Users table
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY,
|
||||
email VARCHAR(255) UNIQUE,
|
||||
password_hash VARCHAR(255), -- NULL если OAuth-only
|
||||
|
||||
-- OAuth данные (один провайдер)
|
||||
oauth_provider VARCHAR(20), -- yandex|google|apple|null
|
||||
oauth_id VARCHAR(255), -- ID в системе провайдера
|
||||
|
||||
-- Метаданные
|
||||
email_verified BOOLEAN DEFAULT FALSE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
|
||||
-- Constraints
|
||||
CONSTRAINT users_oauth_xor_email CHECK (
|
||||
(oauth_provider IS NOT NULL AND email IS NOT NULL) OR
|
||||
(oauth_provider IS NULL AND email IS NOT NULL AND password_hash IS NOT NULL)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX uq_users_oauth ON users(oauth_provider, oauth_id) WHERE oauth_provider IS NOT NULL;
|
||||
```
|
||||
|
||||
### Почему один провайдер
|
||||
|
||||
1. **Безопасность** — меньше точек входа
|
||||
2. **Простота** — не нужно merge аккаунтов
|
||||
3. **Ясность** — пользователь знает что использует
|
||||
4. **Privacy** — данные не смешиваются между провайдерами
|
||||
|
||||
---
|
||||
|
||||
## OAuth Flow
|
||||
|
||||
### Яндекс
|
||||
|
||||
```
|
||||
1. Пользователь нажимает "Войти через Яндекс"
|
||||
2. Редирект на Яндекс OAuth
|
||||
3. Callback с code
|
||||
4. Получение access_token
|
||||
5. Получение данных пользователя
|
||||
6. Поиск/создание user по oauth_provider + oauth_id
|
||||
7. Создание JWT session
|
||||
```
|
||||
|
||||
### Google
|
||||
|
||||
Аналогично Яндексу, с заменой endpoint-ов.
|
||||
|
||||
---
|
||||
|
||||
## Регистрация через email
|
||||
|
||||
```sql
|
||||
-- При регистрации через email
|
||||
INSERT INTO users (email, password_hash, oauth_provider, oauth_id)
|
||||
VALUES ('user@example.com', 'hash123', NULL, NULL);
|
||||
```
|
||||
|
||||
### Вход через email
|
||||
|
||||
```sql
|
||||
-- Проверка пароля
|
||||
SELECT * FROM users WHERE email = 'user@example.com' AND password_hash = verify('hash123');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Защита от привязки чужого аккаунта
|
||||
|
||||
### Проблема
|
||||
|
||||
Злоумышленник может попытаться привязать Google к чужому email.
|
||||
|
||||
### Решение
|
||||
|
||||
1. **Email verification** — требуется подтверждение
|
||||
2. **Password check** — для существующих пользователей
|
||||
3. **Separate tables** — OAuth и email разделены логически
|
||||
|
||||
---
|
||||
|
||||
## Будущее (Apple OAuth)
|
||||
|
||||
### Apple будет реализован позже
|
||||
|
||||
Для Apple потребуется:
|
||||
- App Store Developer Account
|
||||
- Private Key для подписи
|
||||
- Тот же принцип: один пользователь = один провайдер
|
||||
|
||||
---
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Реализовать OAuth service
|
||||
- [ ] Интегрировать Яндекс OAuth
|
||||
- [ ] Интегрировать Google OAuth
|
||||
- [ ] Зарезервировать место для Apple (не реализовывать)
|
||||
- [ ] Тесты
|
||||
- [ ] Документация
|
||||
|
||||
---
|
||||
|
||||
*Создано: 2026-05-10*
|
||||
*См. также: docs/adr/003-oauth-schema.md*
|
||||
Reference in New Issue
Block a user