Add security audit report and PRD for custom names

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>
This commit is contained in:
Sergei 2026-01-22 18:52:01 -08:00
parent f8939a6817
commit f0d39af6dc
2 changed files with 1400 additions and 0 deletions

1250
AUDIT_REPORT.md Normal file

File diff suppressed because it is too large Load Diff

150
PRD.md Normal file
View File

@ -0,0 +1,150 @@
# 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**