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:
parent
f8939a6817
commit
f0d39af6dc
1250
AUDIT_REPORT.md
Normal file
1250
AUDIT_REPORT.md
Normal file
File diff suppressed because it is too large
Load Diff
150
PRD.md
Normal file
150
PRD.md
Normal 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**
|
||||
Loading…
x
Reference in New Issue
Block a user