# 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` || `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 - [x] **Migration: добавить custom_name в user_access** - Путь: `backend/migrations/009_add_custom_name.sql` - SQL: `ALTER TABLE user_access ADD COLUMN custom_name VARCHAR(200);` - Индекс не нужен (поле не для поиска) - [x] **API: изменить GET /me/beneficiaries (список)** - Файл: `backend/src/routes/beneficiaries.js` - В SELECT добавить `custom_name` из `user_access` - В ответе добавить поле `displayName`: `custom_name || name` - Также вернуть `originalName` (из `beneficiaries.name`) для UI - [x] **API: изменить GET /me/beneficiaries/:id (детали)** - Файл: `backend/src/routes/beneficiaries.js` - Добавить `custom_name` из `user_access` в SELECT - В ответе: `displayName`, `originalName`, `customName` - [x] **API: изменить PATCH /me/beneficiaries/:id (обновление)** - Файл: `backend/src/routes/beneficiaries.js` - Логика: - Если `role === 'custodian'` → обновить `beneficiaries.name` - Иначе → обновить `user_access.custom_name` - Добавить параметр `customName` в body - [x] **Деплой миграции на сервер** - SSH: `root@91.98.205.156` - Путь: `/var/www/wellnuo-api/` - Команда: `node run-migration.js` - PM2: `pm2 restart wellnuo-api` ### Frontend - [x] **Types: обновить Beneficiary interface** - Файл: `types/index.ts` или где определён тип - Добавить: `displayName?: string`, `originalName?: string`, `customName?: string` - [x] **API service: обновить типы ответов** - Файл: `services/api.ts` - Обновить интерфейсы для beneficiary endpoints - [x] **UI: список beneficiaries — показывать displayName** - Файл: `app/(tabs)/index.tsx` или где рендерится список - Заменить `beneficiary.name` на `beneficiary.displayName || beneficiary.name` - [x] **UI: header в BeneficiaryDetail — показывать displayName** - Файл: `app/(tabs)/beneficiaries/[id]/index.tsx` - Строка 378: `{beneficiary.name}` → `{beneficiary.displayName || beneficiary.name}` - [x] **UI: Edit модал — разная логика для ролей** - Файл: `app/(tabs)/beneficiaries/[id]/index.tsx` - Для custodian: - Label: "Name" - Редактирует `name` (оригинал) - Для guardian/caretaker: - Label: "Your name for [originalName]" - Placeholder: originalName - Редактирует `customName` - При сохранении отправлять правильное поле - [x] **UI: MockDashboard — показывать displayName** - Файл: `components/MockDashboard.tsx` - Передавать `displayName` вместо `name` --- ## Вне scope (не делаем) - Синхронизация имён с голосовым AI (Ultravox) — будет отдельной задачей - Интеграция с WellNuo Lite — пока не трогаем - Миграция существующих данных — `custom_name` изначально NULL, fallback работает --- ## Чеклист верификации ### Функциональность - [x] Custodian может редактировать оригинальное имя (`beneficiaries.name`) - [x] Guardian/Caretaker могут редактировать своё персональное имя (`user_access.custom_name`) - [x] Список beneficiaries показывает `displayName` (custom_name || name) - [x] Header на детальной странице показывает `displayName` - [x] Edit модал показывает разные labels для разных ролей - [x] При первом открытии (custom_name = NULL) показывается оригинальное имя ### Backend - [x] Миграция применена без ошибок - [x] GET `/me/beneficiaries` возвращает `displayName`, `originalName` - [x] GET `/me/beneficiaries/:id` возвращает `displayName`, `originalName`, `customName` - [x] PATCH `/me/beneficiaries/:id` правильно определяет что обновлять по роли ### Код - [x] Нет TypeScript ошибок (`npx tsc --noEmit`) - [x] Backend работает без ошибок в логах PM2 - [x] Нет console.log в продакшн коде (кроме отладочных с `[DEBUG]`) ### UI/UX - [x] Имена отображаются корректно во всех местах - [x] Edit модал понятен для обоих типов редактирования - [x] Нет визуальных багов ### Edge Cases - [x] custom_name = NULL → показывается originalName - [x] Пустая строка custom_name = "" → считается как NULL - [x] Длинные имена не ломают UI --- **Минимальный проходной балл: 8/10**