WellNuo/CLAUDE.md
Sergei d453126c89 feat: Room location picker + robster credentials
- Backend: Update Legacy API credentials to robster/rob2
- Frontend: ROOM_LOCATIONS with icons and legacyCode mapping
- Device Settings: Modal picker for room selection
- api.ts: Bidirectional conversion (code ↔ name)
- Various UI/UX improvements across screens

PRD-DEPLOYMENT.md completed (Score: 9/10)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-24 15:22:40 -08:00

18 KiB
Raw Blame History

WellNuo - Project Architecture

API-First Architecture

IMPORTANT: This project uses an API-first approach. NO local storage for business data!

Key Principles

  1. All beneficiary data comes from the remote API only

    • No AsyncStorage for beneficiaries
    • No local caching of beneficiary lists
    • Every CRUD operation goes through the WellNuo API
  2. Single Source of Truth: WellNuo Backend

    • All beneficiary data is stored in PostgreSQL (hosted on eluxnetworks.net)
    • Changes are immediately persisted to the server
    • App always fetches fresh data on screen focus

API Endpoints

WellNuo API (Primary)

Base URL: https://wellnuo.smartlaunchhub.com/api

Method Endpoint Description
GET /me/beneficiaries List all beneficiaries for current user
GET /me/beneficiaries/:id Get single beneficiary details
POST /me/beneficiaries Create new beneficiary
PATCH /me/beneficiaries/:id Update beneficiary
DELETE /me/beneficiaries/:id Remove beneficiary access
POST /me/beneficiaries/:id/activate Activate device for beneficiary
GET /auth/me Get current user profile with beneficiaries
PATCH /auth/profile Update user profile (firstName, lastName, phone)

Authentication: Bearer token (JWT from /auth/verify-otp)

Legacy API (WebView Dashboard)

Base URL: https://eluxnetworks.net/function/well-api/api

Used only for:

  • Developer Mode / WebView dashboard
  • Real sensor data visualization (from NDK devices)

Data Flow

┌─────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  React App  │ ──▶ │  WellNuo Backend │ ──▶ │    PostgreSQL    │
│  (Expo)     │ ◀── │  (Express.js)    │ ◀── │ (eluxnetworks.net)│
└─────────────┘     └──────────────────┘     └──────────────────┘

Database Schema

  • users - User accounts (email, password hash)
  • person_details - Beneficiary profiles (firstName, lastName, avatar, etc.)
  • user_access - Links accessor_id → beneficiary_id with role (owner/viewer)
  • subscriptions - Subscription status for beneficiaries
  • devices - IoT devices linked to beneficiaries

What NOT to do

  • Don't use localBeneficiaries from BeneficiaryContext for actual data
  • Don't save beneficiary data to AsyncStorage
  • Don't cache API responses locally for offline use
  • Don't assume data is available without API call
  • Don't save user profile data (name, phone) to SecureStore
  • Don't use userName from SecureStore - it's legacy!

What TO do

  • Always fetch fresh data via api.getAllBeneficiaries() or api.getWellNuoBeneficiary(id)
  • Get user profile via api.getMe(), update via api.updateProfile() (calls /auth/profile)
  • Use useFocusEffect to reload data when screen gains focus
  • Handle loading and error states for all API calls
  • Show appropriate feedback on successful operations
  • Only store in SecureStore: accessToken, userId, userEmail (technical auth data)

Navigation Controller (Centralized Routing)

All navigation decisions are centralized in services/NavigationController.ts.

IMPORTANT: NavigationController is NOT automatic middleware!

  • It does NOT intercept or control all navigation automatically
  • It's a utility that must be EXPLICITLY called at specific points in the app
  • You must manually call nav.navigateAfterLogin(), nav.navigateAfterAddBeneficiary(), etc.
  • Regular navigation (e.g., router.push('/profile')) works independently

When to use NavigationController:

  • After OTP verification (login flow)
  • After creating a new beneficiary
  • After completing purchase/demo selection
  • When you need to determine the "correct next screen" based on user state

When NOT needed:

  • Simple screen-to-screen navigation (just use router.push())
  • Tab navigation (handled by Expo Router)
  • Back navigation (handled automatically)

Key Files

  • services/NavigationController.ts - All routing logic and conditions
  • hooks/useNavigationFlow.ts - React hook for easy usage in components

Navigation Flow After Login

User enters OTP code
        ↓
   Has firstName in profile?
        │
   NO  → /(auth)/enter-name
        │
   YES → Has beneficiaries?
        │
   NO  → /(auth)/add-loved-one
        │
   YES → Check equipment status of first beneficiary
        ├── none → /(auth)/purchase
        ├── ordered/shipped → /(tabs)/beneficiaries/:id/equipment
        ├── delivered → /(auth)/activate
        └── active/demo → /(tabs)/dashboard

Navigation After Adding Beneficiary

Beneficiary created in DB
        ↓
   User already has WellNuo devices?
        │
   NO  → /(auth)/purchase (buy equipment)
        │
   YES → /(auth)/activate (connect existing device)

Navigation After Purchase

Payment completed / Demo selected
        ↓
   Demo mode?
        │
   YES → /(auth)/activate (immediate activation)
        │
   NO  → /(tabs)/beneficiaries/:id/equipment (track delivery)

Usage Example

import { useNavigationFlow } from '@/hooks/useNavigationFlow';

function MyScreen() {
  const nav = useNavigationFlow();

  // After login - automatically determines correct screen
  nav.navigateAfterLogin(profile, beneficiaries);

  // After adding beneficiary
  nav.navigateAfterAddBeneficiary(42, hasExistingDevices);

  // After purchase
  nav.navigateAfterPurchase(42, { demo: true });

  // Quick shortcuts
  nav.goToDashboard();
  nav.goToPurchase(beneficiaryId);
  nav.goToActivate(beneficiaryId);
}

Available Routes (ROUTES constant)

ROUTES.AUTH.LOGIN           // /(auth)/login
ROUTES.AUTH.VERIFY_OTP      // /(auth)/verify-otp
ROUTES.AUTH.ENTER_NAME      // /(auth)/enter-name
ROUTES.AUTH.ADD_LOVED_ONE   // /(auth)/add-loved-one
ROUTES.AUTH.PURCHASE        // /(auth)/purchase
ROUTES.AUTH.ACTIVATE        // /(auth)/activate

ROUTES.TABS.DASHBOARD       // /(tabs)/dashboard
ROUTES.TABS.BENEFICIARIES   // /(tabs)/beneficiaries
ROUTES.TABS.CHAT            // /(tabs)/chat
ROUTES.TABS.VOICE           // /(tabs)/voice
ROUTES.TABS.PROFILE         // /(tabs)/profile

ROUTES.BENEFICIARY.DETAIL(id)       // /(tabs)/beneficiaries/:id
ROUTES.BENEFICIARY.SUBSCRIPTION(id) // /(tabs)/beneficiaries/:id/subscription
ROUTES.BENEFICIARY.EQUIPMENT(id)    // /(tabs)/beneficiaries/:id/equipment
ROUTES.BENEFICIARY.SHARE(id)        // /(tabs)/beneficiaries/:id/share

Development

Server Location

  • Production: root@91.98.205.156:/var/www/wellnuo-api/
  • PM2 process: wellnuo-api

Key Files

  • services/api.ts - All API methods
  • services/NavigationController.ts - Centralized routing logic
  • hooks/useNavigationFlow.ts - Navigation hook for components
  • contexts/BeneficiaryContext.tsx - Beneficiary state management (current selection only)
  • app/(tabs)/beneficiaries/ - Beneficiary screens

Running Locally

# Start Expo on port 8081 with iPhone 16 Pro Max
IOS_SIMULATOR_UDID=6BB240A2-0F2F-41E4-B568-9FFAF9B7FBA2 npx expo start --port 8081 --ios

Specs (Спецификации задач)

Структурированные спецификации для планирования и отслеживания задач.

Структура

specs/
├── wellnuo/           # Основное приложение
├── wellnuo-lite/      # Lite версия
├── shared/            # Общие задачи (backend, API)
└── templates/         # Шаблоны

Типы спек

  • FEATURE-XXX — новая функциональность
  • BUG-XXX — исправление бага
  • TASK-XXX — техническая задача

Как работать со спеками

Создать спеку:

Создай спеку для фичи "название" в specs/wellnuo/

Начать работу:

Прочитай specs/wellnuo/FEATURE-001-voice-integration.md и начни реализацию

Продолжить:

Продолжи по спеке FEATURE-001 с шага 3

Обновить статус:

Отметь шаги 1-3 как выполненные в FEATURE-001

Важно

  • Спека = план работы. Claude следует шагам из Implementation Steps
  • Статусы: 🔴 Not Started | 🟡 In Progress | 🟢 Done
  • Подробности в specs/README.md

Правила разработки (Development Approach)

Методология и подход к качеству кода и тестированию.

ГЛАВНОЕ ПРАВИЛО: НЕ ДОБАВЛЯЙ НИЧЕГО БЕЗ СОГЛАСОВАНИЯ

ЗАПРЕЩЕНО без явного согласования с юзером:

  • Добавлять новые UI элементы (бейджи, кнопки, тексты)
  • Менять поведение которое юзер не просил менять
  • "Улучшать" что-то по своей инициативе
  • Интерпретировать данные API и решать как их показывать

Если видишь что-то непонятное (например equipmentStatus: "demo"):

  1. СПРОСИ юзера: "Что это значит? Как это должно отображаться?"
  2. НЕ ПРИДУМЫВАЙ сам UI решения
  3. НЕ ДОБАВЛЯЙ бейджи/тексты которые юзер не просил

Твоя задача — делать ТОЛЬКО то что просят, не больше.


Правило: ЧИТАЙ КОД ПЕРЕД ИЗМЕНЕНИЯМИ

  1. Всегда читай существующий код компонента перед изменением

    • Понять текущую логику, state machine, conditional rendering
    • Не добавлять логику которая уже есть
    • Не ломать существующее поведение
  2. Проследи весь user flow, не только один экран

    • Если фиксишь список — проверь как это влияет на detail page
    • Если фиксишь backend — проверь как UI отображает новые данные
    • Backend fix без проверки UI — это НЕ завершённый fix

Правило edge cases: ПРОВЕРЯЙ ВСЕ СОСТОЯНИЯ

Перед тем как сказать "готово", проверь UI для ВСЕХ возможных состояний:

  • Happy path (всё работает)
  • Пустое состояние (нет данных)
  • Ошибка (API недоступен)
  • Специальные режимы (demo mode, trial, expired и т.д.)

Не проси юзера тестить пока сам не проверил

  1. Сначала проверь API ответ (curl)
  2. Потом проверь что UI правильно отображает этот ответ
  3. Потом сделай скриншот и убедись
  4. Только потом говори юзеру "готово, проверь"

Частые ошибки которых НЕЛЬЗЯ допускать

  • Фиксить backend и НЕ проверять frontend
  • Проверить только один сценарий и сказать "готово"
  • Не читать существующий код и добавлять дублирующую логику
  • Игнорировать edge cases (demo mode, expired subscription, etc.)
  • Делать изменения "вслепую" без понимания текущей логики

Julia AI Voice Agent (LiveKit)

Расположение скрипта

Python Agent для голосового ассистента Julia находится здесь:

/Users/sergei/Desktop/WellNuo/WellNuoLite/julia-agent/julia-ai/src/agent.py

Архитектура Voice Assistant

┌─────────────┐     ┌────────────────────────┐     ┌─────────────────┐     ┌──────────────────┐
│  Mobile App │ ──▶ │ Julia Token Server     │ ──▶ │  LiveKit Cloud  │ ──▶ │   Python Agent   │
│  (Expo)     │     │ wellnuo.smartlaunchhub │     │  (Agents Cloud) │     │   (agent.py)     │
└─────────────┘     └────────────────────────┘     └─────────────────┘     └──────────────────┘
       │                      │                                                      │
       │                      │ metadata: {deploymentId, beneficiaryNamesDict}       │
       │                      └──────────────────────────────────────────────────────┘
       │                                                                              │
       │                                                                              ▼
       │                                                                 ┌──────────────────┐
       │                                                                 │  WellNuo API     │
       └─────────────────────────────────────────────────────────────────│  eluxnetworks.net│
                              text chat goes directly here               └──────────────────┘

SINGLE_DEPLOYMENT_MODE

Флаг SINGLE_DEPLOYMENT_MODE контролирует отправку beneficiary_names_dict:

Режим SINGLE_DEPLOYMENT_MODE Что отправляется
Lite true только deployment_id
Full false deployment_id + beneficiary_names_dict

Файлы с флагом:

  • WellNuoLite/app/(tabs)/chat.tsx — текстовый чат
  • WellNuoLite/services/livekitService.ts — голосовой ассистент

Ключевые файлы

Файл Назначение
julia-agent/julia-ai/src/agent.py Python агент для LiveKit Cloud
services/livekitService.ts Клиент для получения токена
components/VoiceCall.tsx UI голосового звонка

Серверы

Сервис URL Расположение
Julia Token Server https://wellnuo.smartlaunchhub.com/julia root@91.98.205.156:/var/www/julia-token-server/
WellNuo API https://eluxnetworks.net/function/well-api/api Внешний сервис
Debug Console https://wellnuo.smartlaunchhub.com/debug/ root@91.98.205.156:/var/www/wellnuo-debug/

Деплой Python агента на LiveKit Cloud

Путь к агенту (локально):

/Users/sergei/Desktop/WellNuo/WellNuoLite/julia-agent/julia-ai/

Структура директории:

julia-ai/
├── src/
│   └── agent.py          # Основной Python агент
├── livekit.toml          # Конфигурация LiveKit Cloud
├── Dockerfile            # Для сборки на LiveKit Cloud
├── pyproject.toml        # Python зависимости
└── AGENTS.md             # Документация LiveKit

Текущий Agent ID: CA_Yd3qcuYEVKKE LiveKit Project: live-kit-demo-70txlh6a Region: eu-central

Редактирование агента

# Открыть код агента
code /Users/sergei/Desktop/WellNuo/WellNuoLite/julia-agent/julia-ai/src/agent.py

Основные места в agent.py:

  • Инструкции Julia — строка ~50-100 (system prompt)
  • Обработка metadata — функция _build_request_data()
  • Вызов API — метод send_to_wellnuo_api()
  • agent_name — строка 435: agent_name="julia-ai"

Деплой изменений

cd /Users/sergei/Desktop/WellNuo/WellNuoLite/julia-agent/julia-ai

# 1. Проверить что работает локально (опционально)
uv run python src/agent.py console

# 2. Задеплоить на LiveKit Cloud
lk agent deploy

# Это:
# - Соберёт Docker образ
# - Запушит в LiveKit Cloud registry
# - Развернёт новую версию агента

Полезные команды

# Список агентов в проекте
lk agent list

# Логи агента (в реальном времени)
lk agent logs

# Логи определённого агента
lk agent logs --id CA_Yd3qcuYEVKKE

# Статус агента
lk agent list --verbose

Связка Agent ↔ Token Server

Token Server использует имя julia-ai для диспетчеризации агента:

// /var/www/julia-token-server/server.js
const AGENT_NAME = 'julia-ai';  // Должно совпадать с agent_name в agent.py

При создании нового агента:

  1. Измени agent_name в agent.py
  2. Обнови AGENT_NAME в Token Server
  3. Перезапусти Token Server: pm2 restart julia-token-server