WellNuo/PRD.md
Sergei f0d39af6dc 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>
2026-01-22 18:52:01 -08:00

7.9 KiB
Raw Blame History

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

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