AUDIT_REPORT.md: - Full security audit (90 findings reviewed) - 6 critical tasks for immediate fix - 45 recommendations for later - Complete RLS implementation plan (1-2 weeks) - Doppler for secrets management - Winston + Sentry for logging PRD.md: - Personalized beneficiary names feature - custom_name in user_access table - Backend + Frontend tasks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.9 KiB
PRD — Персонализированные имена beneficiaries
Цель
Позволить каждому пользователю иметь своё персональное имя для каждого beneficiary. Custodian редактирует оригинальное имя (видно всем по умолчанию), остальные роли — своё custom_name.
Контекст
Сейчас имя beneficiary хранится в beneficiaries.name и одинаково для всех пользователей. Нужно добавить возможность персонализации: каждый accessor (кроме custodian) может задать своё имя через user_access.custom_name.
User Flow
Flow 1: Custodian редактирует имя (оригинал)
| # | Актор | Действие | Система | Результат |
|---|---|---|---|---|
| 1 | Custodian | Открывает список beneficiaries | GET /me/beneficiaries |
Показывает name из beneficiaries таблицы |
| 2 | Custodian | Нажимает на beneficiary | GET /me/beneficiaries/:id |
Открывает детали |
| 3 | Custodian | Нажимает "Edit" | — | Открывает Edit модал |
| 4 | Custodian | Меняет имя, нажимает "Save" | PATCH /me/beneficiaries/:id |
Обновляет beneficiaries.name |
| 5 | System | — | Сохраняет в БД | Имя обновлено для ВСЕХ |
Flow 2: Guardian/Caretaker редактирует имя (персональное)
| # | Актор | Действие | Система | Результат |
|---|---|---|---|---|
| 1 | Caretaker | Открывает список beneficiaries | GET /me/beneficiaries |
Показывает custom_name |
| 2 | Caretaker | Нажимает на beneficiary | GET /me/beneficiaries/:id |
Открывает детали |
| 3 | Caretaker | Нажимает "Edit" | — | Открывает Edit модал |
| 4 | Caretaker | Меняет имя, нажимает "Save" | PATCH /me/beneficiaries/:id |
Обновляет user_access.custom_name |
| 5 | System | — | Сохраняет в БД | Имя видно только ЭТОМУ пользователю |
Flow 3: Отображение (все роли)
| # | Актор | Действие | Система | Результат |
|---|---|---|---|---|
| 1 | User | Открывает Dashboard/список | GET /me/beneficiaries |
— |
| 2 | System | — | Для каждого: custom_name || name |
Возвращает displayName |
| 3 | User | Видит список | — | Каждый beneficiary показан с персональным именем |
Задачи
Backend
-
Migration: добавить custom_name в user_access
- Путь:
backend/migrations/009_add_custom_name.sql - SQL:
ALTER TABLE user_access ADD COLUMN custom_name VARCHAR(200); - Индекс не нужен (поле не для поиска)
- Путь:
-
API: изменить GET /me/beneficiaries (список)
- Файл:
backend/src/routes/beneficiaries.js - В SELECT добавить
custom_nameизuser_access - В ответе добавить поле
displayName:custom_name || name - Также вернуть
originalName(изbeneficiaries.name) для UI
- Файл:
-
API: изменить GET /me/beneficiaries/:id (детали)
- Файл:
backend/src/routes/beneficiaries.js - Добавить
custom_nameизuser_accessв SELECT - В ответе:
displayName,originalName,customName
- Файл:
-
API: изменить PATCH /me/beneficiaries/:id (обновление)
- Файл:
backend/src/routes/beneficiaries.js - Логика:
- Если
role === 'custodian'→ обновитьbeneficiaries.name - Иначе → обновить
user_access.custom_name
- Если
- Добавить параметр
customNameв body
- Файл:
-
Деплой миграции на сервер
- SSH:
root@91.98.205.156 - Путь:
/var/www/wellnuo-api/ - Команда:
node run-migration.js - PM2:
pm2 restart wellnuo-api
- SSH:
Frontend
-
Types: обновить Beneficiary interface
- Файл:
types/index.tsили где определён тип - Добавить:
displayName?: string,originalName?: string,customName?: string
- Файл:
-
API service: обновить типы ответов
- Файл:
services/api.ts - Обновить интерфейсы для beneficiary endpoints
- Файл:
-
UI: список beneficiaries — показывать displayName
- Файл:
app/(tabs)/index.tsxили где рендерится список - Заменить
beneficiary.nameнаbeneficiary.displayName || beneficiary.name
- Файл:
-
UI: header в BeneficiaryDetail — показывать displayName
- Файл:
app/(tabs)/beneficiaries/[id]/index.tsx - Строка 378:
{beneficiary.name}→{beneficiary.displayName || beneficiary.name}
- Файл:
-
UI: Edit модал — разная логика для ролей
- Файл:
app/(tabs)/beneficiaries/[id]/index.tsx - Для custodian:
- Label: "Name"
- Редактирует
name(оригинал)
- Для guardian/caretaker:
- Label: "Your name for [originalName]"
- Placeholder: originalName
- Редактирует
customName
- При сохранении отправлять правильное поле
- Файл:
-
UI: MockDashboard — показывать displayName
- Файл:
components/MockDashboard.tsx - Передавать
displayNameвместоname
- Файл:
Вне scope (не делаем)
- Синхронизация имён с голосовым AI (Ultravox) — будет отдельной задачей
- Интеграция с WellNuo Lite — пока не трогаем
- Миграция существующих данных —
custom_nameизначально NULL, fallback работает
Чеклист верификации
Функциональность
- Custodian может редактировать оригинальное имя (
beneficiaries.name) - Guardian/Caretaker могут редактировать своё персональное имя (
user_access.custom_name) - Список beneficiaries показывает
displayName(custom_name || name) - Header на детальной странице показывает
displayName - Edit модал показывает разные labels для разных ролей
- При первом открытии (custom_name = NULL) показывается оригинальное имя
Backend
- Миграция применена без ошибок
- GET
/me/beneficiariesвозвращаетdisplayName,originalName - GET
/me/beneficiaries/:idвозвращаетdisplayName,originalName,customName - PATCH
/me/beneficiaries/:idправильно определяет что обновлять по роли
Код
- Нет TypeScript ошибок (
npx tsc --noEmit) - Backend работает без ошибок в логах PM2
- Нет console.log в продакшн коде (кроме отладочных с
[DEBUG])
UI/UX
- Имена отображаются корректно во всех местах
- Edit модал понятен для обоих типов редактирования
- Нет визуальных багов
Edge Cases
- custom_name = NULL → показывается originalName
- Пустая строка custom_name = "" → считается как NULL
- Длинные имена не ломают UI
Минимальный проходной балл: 8/10