- Fix saveWiFiPassword to use encrypted passwords map instead of decrypted - Fix getWiFiPassword to decrypt from encrypted storage - Fix test expectations for migration and encryption functions - Remove unused error variables to fix linting warnings - All 27 tests now passing with proper encryption/decryption flow The WiFi credentials cache feature was already implemented but had bugs where encrypted and decrypted password maps were being mixed. This commit ensures proper encryption is maintained throughout the storage lifecycle.
12 KiB
WellNuo - Project Architecture
API-First Architecture
IMPORTANT: This project uses an API-first approach. NO local storage for business data!
Key Principles
-
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
-
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 beneficiariesdevices- IoT devices linked to beneficiaries
What NOT to do
- ❌ Don't use
localBeneficiariesfrom 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
userNamefrom SecureStore - it's legacy!
What TO do
- ✅ Always fetch fresh data via
api.getAllBeneficiaries()orapi.getWellNuoBeneficiary(id) - ✅ Get user profile via
api.getMe(), update viaapi.updateProfile()(calls/auth/profile) - ✅ Use
useFocusEffectto 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 conditionshooks/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 methodsservices/NavigationController.ts- Centralized routing logichooks/useNavigationFlow.ts- Navigation hook for componentscontexts/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"):
- СПРОСИ юзера: "Что это значит? Как это должно отображаться?"
- НЕ ПРИДУМЫВАЙ сам UI решения
- НЕ ДОБАВЛЯЙ бейджи/тексты которые юзер не просил
Твоя задача — делать ТОЛЬКО то что просят, не больше.
Правило: ЧИТАЙ КОД ПЕРЕД ИЗМЕНЕНИЯМИ
-
Всегда читай существующий код компонента перед изменением
- Понять текущую логику, state machine, conditional rendering
- Не добавлять логику которая уже есть
- Не ломать существующее поведение
-
Проследи весь user flow, не только один экран
- Если фиксишь список — проверь как это влияет на detail page
- Если фиксишь backend — проверь как UI отображает новые данные
- Backend fix без проверки UI — это НЕ завершённый fix
Правило edge cases: ПРОВЕРЯЙ ВСЕ СОСТОЯНИЯ
Перед тем как сказать "готово", проверь UI для ВСЕХ возможных состояний:
- Happy path (всё работает)
- Пустое состояние (нет данных)
- Ошибка (API недоступен)
- Специальные режимы (demo mode, trial, expired и т.д.)
Не проси юзера тестить пока сам не проверил
- Сначала проверь API ответ (curl)
- Потом проверь что UI правильно отображает этот ответ
- Потом сделай скриншот и убедись
- Только потом говори юзеру "готово, проверь"
Частые ошибки которых НЕЛЬЗЯ допускать
- ❌ Фиксить backend и НЕ проверять frontend
- ❌ Проверить только один сценарий и сказать "готово"
- ❌ Не читать существующий код и добавлять дублирующую логику
- ❌ Игнорировать edge cases (demo mode, expired subscription, etc.)
- ❌ Делать изменения "вслепую" без понимания текущей логики