feat(auth): add user profile, phone login, and account deletion

This commit is contained in:
iu
2026-10-12 14:26:32 +03:00
parent 1cb9aaf198
commit 86aff695df
46 changed files with 2893 additions and 134 deletions
@@ -0,0 +1,57 @@
# Proposal
## Why
Управление аккаунтом сейчас ограничено регистрацией и входом: пользователь не может
изменить имя или пароль, а `PATCH /auth/me/preferences` умеет только настройки отображения.
Вход возможен только по email, хотя мобильный сценарий естественно подразумевает номер
телефона. Нужен явный профиль и вход по любому из двух идентификаторов.
## What Changes
- Профиль пользователя: изменение имени; смена пароля с подтверждением текущего пароля и
отзывом **всех** refresh-токенов (все сессии, включая текущую).
- `phone` добавляется в аккаунт как второй идентификатор входа, хранится в строгом формате
E.164, уникален, без подтверждения (SMS/OTP вне объёма).
- `email` перестаёт быть обязательным: обязателен **хотя бы один** из `email`/`phone`.
Оба — логины: заданный идентификатор нельзя изменить или удалить, но недостающий можно
добавить один раз (add-only).
- Вход по единому полю: `identifier` — email или E.164-телефон; определение по наличию `@`.
- **BREAKING** (API): `POST /auth/login` принимает `identifier` вместо `email`;
`POST /auth/register` принимает `phone` и допускает отсутствие `email`.
- Новые инструменты профиля на всех поверхностях: страница `/profile` в вебе и отдельный
экран в Android; поля входа/регистрации обновляются на обеих поверхностях.
- Удаление аккаунта со всем содержимым: по подтверждению текущего пароля, немедленно и
необратимо. Каскадно удаляются альбомы пользователя (включая доступ других участников),
фото, комментарии, лайки, метки, уведомления, share-ссылки и приглашения; блобы добираются
фоновым `reconcile`.
- Вне объёма: подтверждение телефона (SMS/OTP), смена/удаление заданных логинов, изменение
avatar, «корзина»/отложенное удаление аккаунта, экспорт данных перед удалением.
## Capabilities
### New Capabilities
- `user-profile`: управление аккаунтом пользователя на всех поверхностях — чтение профиля,
изменение имени, смена пароля с отзывом сессий, добавление недостающего идентификатора и
удаление аккаунта со всем содержимым; телефон виден только владельцу (email, как и прежде,
виден участникам альбома).
### Modified Capabilities
- `auth`: вход по email **или** телефону через единый `identifier`; регистрация с
требованием «хотя бы одного» из email/phone; хранение телефона в E.164.
## Impact
- Backend: `backend/internal/auth/{service.go,handlers.go,store.go,sqlite_store.go,repository.go}`,
`backend/internal/models/models.go`, `backend/internal/app/app.go` (маршруты).
- Миграции: PostgreSQL `000013_user_phone.*`, SQLite `000005_user_phone.*` (в SQLite — rebuild
`users` для снятия `NOT NULL` с email).
- Frontend: `routes/(public)/login/+page.svelte`, новая `routes/(app)/profile/+page.svelte`,
`lib/components/AppShell.svelte`, `lib/api.ts`, `lib/types.ts`, `lib/stores/auth.svelte.ts`.
- Android: `data/network/dto/Dtos.kt`, `data/network/GaloApi.kt`, `data/network/ErrorMapper.kt`,
`ui/auth/*`, новый `ui/profile/*`, `ui/GaloNavHost.kt`.
- Данные/скрипты: `scripts/seed.py` (передача phone), существующие аккаунты остаются
email-only и получают `phone = NULL`.
- Удаление: каскад FK в PostgreSQL/SQLite; очистка блобов существующим `reconcile`
(eventual, не в транзакции удаления).
- Приватность: `phone` не попадает в `PublicUser` (участники, загрузчики, комментарии).