From 657a04309e38c49375320089632fee8891dc742a Mon Sep 17 00:00:00 2001 From: Iu Date: Mon, 12 Oct 2026 14:27:19 +0300 Subject: [PATCH] chore(openspec): archive add-user-profile and sync main specs --- .../.openspec.yaml | 0 .../2026-10-12-add-user-profile}/design.md | 0 .../2026-10-12-add-user-profile}/proposal.md | 0 .../specs/auth/spec.md | 0 .../specs/user-profile/spec.md | 0 .../2026-10-12-add-user-profile}/tasks.md | 0 openspec/specs/auth/spec.md | 26 +++- openspec/specs/user-profile/spec.md | 120 ++++++++++++++++++ 8 files changed, 139 insertions(+), 7 deletions(-) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/.openspec.yaml (100%) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/design.md (100%) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/proposal.md (100%) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/specs/auth/spec.md (100%) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/specs/user-profile/spec.md (100%) rename openspec/changes/{add-user-profile => archive/2026-10-12-add-user-profile}/tasks.md (100%) create mode 100644 openspec/specs/user-profile/spec.md diff --git a/openspec/changes/add-user-profile/.openspec.yaml b/openspec/changes/archive/2026-10-12-add-user-profile/.openspec.yaml similarity index 100% rename from openspec/changes/add-user-profile/.openspec.yaml rename to openspec/changes/archive/2026-10-12-add-user-profile/.openspec.yaml diff --git a/openspec/changes/add-user-profile/design.md b/openspec/changes/archive/2026-10-12-add-user-profile/design.md similarity index 100% rename from openspec/changes/add-user-profile/design.md rename to openspec/changes/archive/2026-10-12-add-user-profile/design.md diff --git a/openspec/changes/add-user-profile/proposal.md b/openspec/changes/archive/2026-10-12-add-user-profile/proposal.md similarity index 100% rename from openspec/changes/add-user-profile/proposal.md rename to openspec/changes/archive/2026-10-12-add-user-profile/proposal.md diff --git a/openspec/changes/add-user-profile/specs/auth/spec.md b/openspec/changes/archive/2026-10-12-add-user-profile/specs/auth/spec.md similarity index 100% rename from openspec/changes/add-user-profile/specs/auth/spec.md rename to openspec/changes/archive/2026-10-12-add-user-profile/specs/auth/spec.md diff --git a/openspec/changes/add-user-profile/specs/user-profile/spec.md b/openspec/changes/archive/2026-10-12-add-user-profile/specs/user-profile/spec.md similarity index 100% rename from openspec/changes/add-user-profile/specs/user-profile/spec.md rename to openspec/changes/archive/2026-10-12-add-user-profile/specs/user-profile/spec.md diff --git a/openspec/changes/add-user-profile/tasks.md b/openspec/changes/archive/2026-10-12-add-user-profile/tasks.md similarity index 100% rename from openspec/changes/add-user-profile/tasks.md rename to openspec/changes/archive/2026-10-12-add-user-profile/tasks.md diff --git a/openspec/specs/auth/spec.md b/openspec/specs/auth/spec.md index e17aef3..86804ee 100644 --- a/openspec/specs/auth/spec.md +++ b/openspec/specs/auth/spec.md @@ -7,25 +7,37 @@ ## Requirements ### Requirement: Регистрация пользователя -Пользователь SHALL иметь возможность зарегистрироваться, указав email, пароль и имя. Пароль SHALL храниться в виде bcrypt-хэша. +Пользователь SHALL регистрироваться, указав имя, пароль и хотя бы один из идентификаторов — +email или телефон. Пароль SHALL храниться в виде bcrypt-хэша. Телефон SHALL нормализоваться +к формату E.164 и быть уникальным; email SHALL приводиться к нижнему регистру и быть +уникальным. #### Scenario: Успешная регистрация -- **WHEN** пользователь отправляет уникальный email, пароль и имя +- **WHEN** пользователь отправляет свободный email, имя и пароль - **THEN** система создаёт учётную запись и возвращает access- и refresh-токены +#### Scenario: Регистрация по телефону +- **WHEN** пользователь отправляет свободный телефон в формате E.164, имя и пароль +- **THEN** система создаёт учётную запись и возвращает access- и refresh-токены + +#### Scenario: Нет ни email, ни телефона +- **WHEN** пользователь не указывает ни email, ни телефон +- **THEN** система отклоняет регистрацию + #### Scenario: Повторный email -- **WHEN** пользователь регистрируется с уже занятым email +- **WHEN** пользователь регистрируется с уже занятым email или телефоном - **THEN** система возвращает ошибку конфликта и не создаёт вторую запись -### Requirement: Вход по email и паролю -Пользователь SHALL иметь возможность войти, указав email и пароль. +### Requirement: Вход по email или телефону +Пользователь SHALL входить по единому идентификатору — email или телефону в формате +E.164 — и паролю. #### Scenario: Успешный вход -- **WHEN** пользователь вводит верные email и пароль +- **WHEN** пользователь вводит существующий email или телефон и верный пароль - **THEN** система возвращает access- и refresh-токены #### Scenario: Неверные учётные данные -- **WHEN** пользователь вводит неверный email или пароль +- **WHEN** пользователь вводит несуществующий идентификатор или неверный пароль - **THEN** система возвращает 401, не раскрывая, какое именно поле неверно ### Requirement: Обновление access-токена diff --git a/openspec/specs/user-profile/spec.md b/openspec/specs/user-profile/spec.md new file mode 100644 index 0000000..dc3fe0a --- /dev/null +++ b/openspec/specs/user-profile/spec.md @@ -0,0 +1,120 @@ +# user-profile Specification + +## Purpose + +Управление аккаунтом пользователя: просмотр и изменение профиля, смена пароля с отзывом +сессий, добавление второго идентификатора входа и удаление аккаунта со всем содержимым — +единообразно в веб-интерфейсе и Android-клиенте. + +## Requirements + +### Requirement: Просмотр собственного профиля +Пользователь SHALL получать свой профиль с именем, email, телефоном и аватаром. +Телефон SHALL быть виден только владельцу и SHALL NOT попадать в публичные представления +пользователя (участники альбома, загрузчики, комментарии). + +#### Scenario: Получение профиля +- **WHEN** аутентифицированный пользователь запрашивает свой профиль +- **THEN** ответ содержит его имя, email (если задан), телефон (если задан) и аватар + +#### Scenario: Телефон не утекает +- **WHEN** пользователь просматривает участников альбома +- **THEN** представления других пользователей не содержат телефон + +### Requirement: Изменение имени +Пользователь SHALL изменять своё имя. Пустое имя SHALL отклоняться. Смена имени SHALL +применяться немедленно и отражаться при следующем чтении профиля. + +#### Scenario: Успешное изменение +- **WHEN** пользователь отправляет непустое имя +- **THEN** система сохраняет его и возвращает обновлённый профиль + +#### Scenario: Пустое имя +- **WHEN** пользователь отправляет пустое имя +- **THEN** система отклоняет запрос и не меняет профиль + +### Requirement: Смена пароля с отзывом сессий +Пользователь SHALL менять пароль, подтвердив текущий пароль. Система SHALL отклонять +неверный текущий пароль и новый пароль короче 8 символов. Успешная смена SHALL отзывать +все refresh-токены пользователя на всех устройствах. + +#### Scenario: Успешная смена +- **WHEN** пользователь вводит верный текущий пароль и новый пароль допустимой длины +- **THEN** система сохраняет новый хэш и отзывает все refresh-токены пользователя + +#### Scenario: Неверный текущий пароль +- **WHEN** пользователь вводит неверный текущий пароль +- **THEN** система возвращает ошибку и не меняет пароль + +#### Scenario: Слабый новый пароль +- **WHEN** новый пароль короче 8 символов +- **THEN** система отклоняет запрос и сохраняет старый пароль + +### Requirement: Добавление недостающего идентификатора +Пользователь с одним заданным идентификатором (email или телефон) SHALL добавить +недостающий один раз после проверки уникальности. Система SHALL отклонять добавление, когда +оба идентификатора уже заданы, а также изменение или удаление заданного. После добавления +оба идентификатора SHALL работать для входа. + +#### Scenario: Добавление телефона +- **WHEN** пользователь без телефона добавляет свободный номер в формате E.164 +- **THEN** система сохраняет номер, и вход по нему становится возможен + +#### Scenario: Занятый идентификатор +- **WHEN** добавляемый email или телефон уже принадлежит другому пользователю +- **THEN** система возвращает ошибку конфликта и не меняет профиль + +#### Scenario: Оба уже заданы +- **WHEN** у пользователя уже заданы и email, и телефон, и он пытается добавить третий +- **THEN** система отклоняет запрос + +### Requirement: Удаление аккаунта со всем содержимым +Пользователь SHALL удалять свой аккаунт, подтвердив текущий пароль. Неверный пароль SHALL +отклоняться. Успешное удаление SHALL быть немедленным и необратимым: SHALL каскадно +удаляться альбомы пользователя (вместе с доступом других участников), его фото, +комментарии, лайки, метки, уведомления, share-ссылки и приглашения. Блобы SHALL +освобождаться фоновой сверкой хранилища, а не в транзакции удаления. + +#### Scenario: Успешное удаление +- **WHEN** пользователь подтверждает удаление верным текущим паролем +- **THEN** учётная запись и связанное содержимое удаляются, и вход больше невозможен + +#### Scenario: Общие альбомы +- **WHEN** удаляемый пользователь владеет альбомом, в котором есть другие участники +- **THEN** альбом удаляется вместе с ними + +#### Scenario: Неверный пароль +- **WHEN** пользователь подтверждает удаление неверным паролем +- **THEN** система возвращает ошибку и не удаляет аккаунт + +### Requirement: Страница профиля в веб-интерфейсе +Веб-приложение SHALL предоставлять отдельную страницу профиля, доступную из шапки, с +показом идентификаторов и формами изменения имени, смены пароля и удаления аккаунта. + +#### Scenario: Открытие страницы +- **WHEN** аутентифицированный пользователь открывает профиль из шапки +- **THEN** отображаются его идентификаторы и формы редактирования + +#### Scenario: Выход после смены пароля +- **WHEN** смена пароля завершилась успешно +- **THEN** клиент очищает токены и перенаправляет на страницу входа + +#### Scenario: Выход после удаления +- **WHEN** удаление аккаунта завершилось успешно +- **THEN** клиент очищает токены и перенаправляет на страницу входа + +### Requirement: Экран профиля в Android-клиенте +Android-приложение SHALL предоставлять отдельный экран профиля, доступный из списка +альбомов, с теми же возможностями, что и веб-страница. + +#### Scenario: Открытие экрана +- **WHEN** пользователь открывает профиль из списка альбомов +- **THEN** отображаются идентификаторы и формы редактирования + +#### Scenario: Возврат после смены пароля +- **WHEN** смена пароля завершилась успешно +- **THEN** приложение очищает токены и возвращает на экран входа + +#### Scenario: Возврат после удаления +- **WHEN** удаление аккаунта завершилось успешно +- **THEN** приложение очищает токены и возвращает на экран входа