WellNuo/docs/API_INTEGRATION_REQUEST.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

714 lines
22 KiB
Markdown

# API Optimization Proposals for WellNuo Integration
> **Note:** This document is for discussion purposes only, not final requirements. All proposals are open for discussion — we're happy to consider alternative approaches and adapt to your system's capabilities. Let's schedule a call to discuss the details if needed.
---
## 1. Introduction
### 1.1 Context
We're developing the **WellNuo** mobile application with our own database of users and beneficiaries. For working with IoT devices (sensors), we need integration with your Legacy API.
### 1.2 Current Integration Architecture
```
┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ WellNuo App │ ──▶ │ WellNuo Backend │ ──▶ │ eluxnetworks.net │
│ (React Native) │ │ (Node.js) │ │ Legacy API │
└─────────────────┘ └──────────────────┘ └────────────────────┘
┌──────────────┐
│ PostgreSQL │
│ (WellNuo) │
└──────────────┘
```
### 1.3 Summary of Request
The current API workflow requires creating a user in your database to obtain an authorization token. However:
1. **Users already exist in our DB** — creating them in your DB is redundant
2. **We don't use these users** — they're only needed to obtain a token
3. **This creates "garbage" records** — unused accounts accumulate in your DB
**Request:** Add the ability for service integration via API Key without creating users.
### 1.4 Note on Current Capabilities
Technically, we **can** create users via the `new_user_form` endpoint:
```http
POST /function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=new_user_form
&firstName=John
&lastName=Doe
&email=john@example.com
&password=password123
&devices=[]
&agreementDate=2025-01-23
&privacyPolicyVersion=1.0
&phone=+1234567890
```
However, we consider this a **legacy approach** for the following reasons:
1. **Users aren't used as intended** — we create them solely to obtain an authorization token, not for actual use in your system
2. **Data duplication** — user information is stored in two databases without synchronization
3. **"Garbage" records** — accounts accumulate in your DB that will never be used directly
4. **Password transmitted in plaintext** — security issue (see section 2)
**Proposal:** Schedule a separate meeting to discuss and approve the integration architecture.
### 1.5 Which Endpoints We Actually Need
**We NEED (minimum set):**
| Endpoint | Purpose |
|----------|---------|
| `set_deployment` | Create deployment and link devices to beneficiary |
| `messages_age` | Sensor status: when last online (online/offline) |
| `device_set_well_id` | Link device by well_id |
| `device_form` | Configure sensor location (room) |
| `device_list_by_deployment` | Get list of deployment's devices |
**We DON'T NEED:**
| Endpoint | Why Not Needed |
|----------|----------------|
| `get_raw_data`, `get_presence_data` | Raw sensor data — processed on your side |
| `dashboard_*` | Dashboard is shown through Julia AI |
| `store_alarms`, `send_walarm` | Alarms are managed by your system |
| `get_sensor_*` | Charts and analytics — not our task |
| `request_node_red`, `store_flow` | We don't use Node-RED |
**Conclusion:** We only need CRUD for deployments/devices and sensor status. All sensor data and analytics remain on your side.
---
## 2. Security Issues with Current API
### 2.1 Critical Issues
| # | Issue | Severity | Description |
|---|-------|----------|-------------|
| 1 | Password in request body | 🔴 Critical | `credentials` accepts `ps` (password) in POST body |
| 2 | Plaintext beneficiary password | 🔴 Critical | `set_deployment` requires `beneficiary_password` |
| 3 | No API Key auth | 🟡 High | No service authorization mechanism |
| 4 | Redundant `user_name` | 🟡 Medium | Every request requires `user_name` + `token`, even though token already identifies user |
### 2.2 Issue #1 Details: Password in Request Body
**Current request:**
```http
POST /function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=credentials&user_name=anandk&ps=anandk_8&clientId=001&nonce=1234567890
```
**Risks:**
- Password ends up in server access logs
- Password may end up in proxy/WAF/CDN logs
- When logging POST body — full credential compromise
### 2.3 Issue #2 Details: Plaintext Password When Creating Deployment
**Current request:**
```http
POST /function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=set_deployment
&user_name=anandk
&token=eyJ...
&deployment=NEW
&beneficiary_user_name=john_doe
&beneficiary_password=password123 ← PLAINTEXT PASSWORD
&beneficiary_email=john@example.com
...
```
**Risks:**
- We're forced to know/generate user's password
- Password transmitted in plain text
- When logged — credential compromise
### 2.4 Issue #4 Details: Redundant user_name
**Current request (any endpoint):**
```http
function=device_list
&user_name=anandk ← why, if there's a token?
&token=eyJ... ← token already contains user_id
&first=0
&last=100
```
**Issue:** If the JWT token already contains the user identifier, passing `user_name` is redundant.
**Potential risk:** Token confusion attack — using one user's token with another user's `user_name`. Server should verify the match, but this is an additional failure point.
---
## 3. Our Security Standard (WellNuo API)
For reference, here's how authorization works in our API:
### 3.1 Authorization via Bearer Token in Header
```http
GET /api/auth/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
```
### 3.2 Why This Is More Secure
| Aspect | Body (current) | Header (proposed) |
|--------|----------------|-------------------|
| Logging | Often logged | Usually masked |
| Caching | May be cached | Not cached |
| CSRF protection | Vulnerable | Protected |
| Standard | Non-standard | RFC 6750 |
---
## 4. Requested Changes
### 4.1 Authorization Mechanism: Options
**Requirement:** Replace current flow with password in body with a more secure option.
#### Current flow (problematic):
```
1. POST credentials (user_name + password in body) ← password in request body
2. Get JWT token (valid 7 days)
3. Use token + user_name in every request
4. Repeat steps 1-2 when token expires
```
#### Option A: API Key (static key)
```
1. You generate an API Key for our integration (once)
2. We use the key in header: Authorization: X-API-Key sk-wellnuo-xxx
3. When revocation needed — deactivate key and issue a new one
```
**Pros:** simplicity, no refresh logic, easy audit
**Cons:** one key for entire integration
#### Option B: Service Account (token in header)
```
1. You create a service account for WellNuo (once)
2. We get token via credentials, but pass IT IN HEADER
3. Format: Authorization: Bearer eyJ...
4. user_name not needed in request body (token already identifies)
```
**Pros:** familiar JWT flow, can use existing infrastructure
**Cons:** need refresh token
#### Main requirement (both options):
- **Token/key in header** `Authorization`, not in body
- **Remove `user_name`** from request body (redundant)
---
### 4.2 Endpoint: Authorization
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=credentials
&user_name=anandk
&ps=anandk_8
&clientId=001
&nonce=1234567890
```
**Response:**
```json
{
"status": "200 OK",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 604800
}
```
#### PROPOSED REQUEST ✅
**Option A: No longer needed** (API Key doesn't require token request)
**Option B: If key validation needed**
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: X-API-Key sk-wellnuo-xxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
{
"function": "validate_api_key"
}
```
**Expected response:**
```json
{
"status": "200 OK",
"valid": true,
"client_name": "WellNuo App",
"permissions": ["deployments", "devices", "read_data"]
}
```
---
### 4.3 Endpoint: Create Deployment
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=set_deployment
&user_name=anandk
&token=eyJ...
&deployment=NEW
&beneficiary_name=John Doe
&beneficiary_email=john@example.com
&beneficiary_user_name=john_doe ← creates user in your DB
&beneficiary_password=password123 ← plaintext password
&beneficiary_address=123 Main St
&caretaker_username=jane_doe ← creates another user
&caretaker_email=jane@example.com
&persons=1
&gender=Male
&race=0
&born=1955
&pets=0
&lat=40.7128
&lng=-74.0060
&wifis=["HomeWiFi|password123"]
&devices=[497,523]
```
**Response:**
```json
{
"status": "200 OK",
"deployment_id": 42,
"beneficiary_user_id": 156,
"caretaker_user_id": 157
}
```
#### PROPOSED REQUEST ✅
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: Bearer eyJ... (or X-API-Key sk-wellnuo-xxx)
Content-Type: application/json
{
"function": "set_deployment",
"deployment": "NEW",
"external_beneficiary_id": "clxyz123-uuid-from-our-db",
"beneficiary_name": "John Doe",
"beneficiary_email": "john@example.com",
"devices": [497, 523]
}
```
**Note:** Only minimally required fields. Others (address, lat/lng, persons, pets, gender, born) — optional, we can pass them if needed.
**Expected response:**
```json
{
"status": "200 OK",
"deployment_id": 42,
"external_beneficiary_id": "clxyz123-uuid-from-our-db"
}
```
**Key differences:**
| Aspect | Current | Proposed |
|--------|---------|----------|
| Authorization | token + user_name in body | Token/key in header |
| User creation | `beneficiary_user_name` + `beneficiary_password` | NOT created |
| Beneficiary ID | Generated in your DB | `external_beneficiary_id` from our DB |
| Password | Transmitted plaintext | Not required |
---
### 4.4 Endpoint: Link Device to Deployment
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=device_set_well_id
&user_name=anandk
&token=eyJ...
&device_id=1234
&well_id=497
&mac=81A14C
```
**Response:**
```json
{
"status": "200 OK",
"success": true
}
```
#### PROPOSED REQUEST ✅
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: Bearer eyJ... (or X-API-Key)
Content-Type: application/x-www-form-urlencoded
function=device_set_well_id
&device_id=1234
&well_id=497
&mac=81A14C
```
**Change:** Remove `user_name` and `token` from body, authorization via header.
---
### 4.5 Endpoint: Update Device Metadata
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=device_form
&user_name=anandk
&token=eyJ...
&well_id=497
&device_mac=81A14C
&description=Living Room Sensor
&location=103
```
#### PROPOSED REQUEST ✅
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: Bearer eyJ... (or X-API-Key)
Content-Type: application/x-www-form-urlencoded
function=device_form
&well_id=497
&device_mac=81A14C
&description=Living Room Sensor
&location=103
```
**Change:** Remove `user_name` and `token` from body, authorization via header.
---
### 4.6 Endpoint: List Deployment Devices
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=device_list_by_deployment
&user_name=anandk
&token=eyJ...
&deployment_id=42
&first=0
&last=100
```
#### PROPOSED REQUEST ✅
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: Bearer eyJ... (or X-API-Key)
Content-Type: application/x-www-form-urlencoded
function=device_list_by_deployment
&deployment_id=42
&first=0
&last=100
```
**Change:** Remove `user_name` and `token` from body, authorization via header.
---
### 4.7 Endpoint: Sensor Status (online/offline)
**We need this endpoint** — we show users when the sensor was last online.
#### CURRENT REQUEST ❌
```http
POST https://eluxnetworks.net/function/well-api/api
Content-Type: application/x-www-form-urlencoded
function=messages_age
&clientId=wellnuo_001
&user_name=anandk
&token=eyJ...
&nonce=12345
&macs=64B70888FAD4,64B708890F80,64B708890898
```
#### PROPOSED REQUEST ✅
```http
POST https://eluxnetworks.net/function/well-api/api
Authorization: Bearer eyJ... (or X-API-Key)
Content-Type: application/x-www-form-urlencoded
function=messages_age
&clientId=wellnuo_001
&nonce=12345
&macs=64B70888FAD4,64B708890F80,64B708890898
```
**Change:** Remove `user_name` and `token` from body, authorization via header.
---
## 5. Summary of Changes
### 5.1 Changes by Endpoint
| Endpoint | Current | What to Remove | What to Add |
|----------|---------|----------------|-------------|
| **All endpoints** | `user_name` + `token` in body | `user_name`, `token` from body | `Authorization` header |
| `set_deployment` | Creates user | `beneficiary_user_name`, `beneficiary_password` | `external_beneficiary_id` |
### 5.2 List of Endpoints We Use
| # | Endpoint | Purpose | Change |
|---|----------|---------|--------|
| 1 | `credentials` | Get token | Token in header (or API Key) |
| 2 | `set_deployment` | Create deployment | + `external_beneficiary_id`, no password |
| 3 | `device_set_well_id` | Link device | Auth in header |
| 4 | `device_form` | Configure sensor (room) | Auth in header |
| 5 | `device_list_by_deployment` | List devices | Auth in header |
| 6 | `messages_age` | Sensor status (online/offline) | Auth in header |
### 5.3 Room Codes (location) — Reference
| Code | Name |
|------|------|
| 102 | Bedroom |
| 103 | Living Room |
| 104 | Kitchen |
| 105 | Bathroom |
| 106 | Hallway |
| 107 | Office |
| 108 | Garage |
| 109 | Dining Room |
| 110 | Basement |
| 200 | Other |
---
## 6. Critical Bug: `set_deployment` Does Not Return `deployment_id`
### 6.1 Problem Description
When successfully creating a deployment via `set_deployment`, the API returns a minimal response without the created record's identifier.
**Current response:**
```json
{"ok": 1, "status": "200 OK"}
```
**Required response:**
```json
{"ok": 1, "deployment_id": 78, "status": "200 OK"}
```
### 6.2 Why This Is Critical for Integration
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ CURRENT FLOW (BROKEN) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. WellNuo creates beneficiary in its DB │
│ → beneficiary_id = "clxyz123-uuid" │
│ │
│ 2. WellNuo calls set_deployment in Legacy API │
│ → Deployment created successfully │
│ → Response: {"ok": 1, "status": "200 OK"} │
│ → deployment_id = ??? ← UNKNOWN! │
│ │
│ 3. WellNuo CANNOT save the link: │
│ beneficiary_deployments.legacy_deployment_id = NULL │
│ │
│ 4. WellNuo CANNOT get sensors for this beneficiary: │
│ device_list_by_deployment requires deployment_id │
│ → INTEGRATION IMPOSSIBLE │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 6.3 Workaround Attempts (unsuccessful)
We tried to find the created deployment through search:
```bash
# Attempt: find recently created deployments
curl -X POST "..." -d "function=find_deployments" -d "well_ids=70,71,72,73,74,75"
```
**Why this doesn't work:**
- Race condition with parallel requests from different clients
- IDs not guaranteed to be sequential
- Requires additional API call
- Unreliable in production environment
### 6.4 Working Request (for reproduction)
```bash
#!/bin/bash
TOKEN="<your_token>"
TS=$(date +%s)
curl -s -X POST "https://eluxnetworks.net/function/well-api/api" \
-d "function=set_deployment" \
-d "user_name=robster" \
-d "token=$TOKEN" \
-d "deployment=NEW" \
-d "beneficiary_name=WellNuo Test" \
-d "beneficiary_email=wellnuo-test-${TS}@wellnuo.app" \
-d "beneficiary_user_name=wellnuo_test_${TS}" \
-d "beneficiary_password=wellnuo123" \
-d "beneficiary_address=WellNuo App" \
-d "caretaker_username=anandk" \
-d "caretaker_email=anandk@wellnuo.app" \
-d "firstName=WellNuo" \
-d "lastName=Test" \
-d "persons=1" \
-d "pets=0" \
-d "gender=0" \
-d "race=0" \
-d "born=1960" \
-d "lat=0" \
-d "lng=0" \
-d "wifis=[]" \
-d "devices=[]"
# Response: {"ok": 1, "status": "200 OK"}
# Expected: {"ok": 1, "deployment_id": 78, "status": "200 OK"}
```
### 6.5 Required Fix
Modify the `set_deployment` function to return the created deployment ID:
```json
{
"ok": 1,
"deployment_id": 78,
"status": "200 OK"
}
```
**Priority:** 🔴 Blocker — integration is impossible without this fix.
---
## 7. Changes on WellNuo App Backend Side (what we plan to implement)
After agreeing on the new architecture, we plan to implement the following on the WellNuo App Backend side (the backend supporting the mobile application):
### 7.1 Planned Changes
| # | Change | Description |
|---|--------|-------------|
| 1 | **API Proxy Layer** | All Legacy API calls go through WellNuo backend, not directly from mobile app |
| 2 | **Secure Key Storage** | API Key stored in Doppler (secrets manager), not in code or .env files |
| 3 | **Retry Logic** | Automatic retries for temporary errors (5xx, timeout) |
| 4 | **Error Handling** | Graceful degradation — app works even if Legacy API is temporarily unavailable |
| 5 | **Audit Logging** | Logging all Legacy API calls for debugging and monitoring |
### 7.2 Architecture After Changes
```
┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ WellNuo App │ │ WellNuo Backend │ │ eluxnetworks.net │
│ (React Native) │ │ (Node.js) │ │ Legacy API │
└────────┬────────┘ └────────┬─────────┘ └─────────┬──────────┘
│ │ │
│ 1. Create beneficiary │ │
│ ───────────────────────▶ │
│ │ │
│ │ 2. set_deployment │
│ │ (API Key in header) │
│ │ ─────────────────────────▶
│ │ │
│ │ 3. {deployment_id: 78} │
│ │ ◀─────────────────────────
│ │ │
│ │ 4. Save mapping: │
│ │ beneficiary_id ↔ │
│ │ deployment_id │
│ │ │
│ 5. Success │ │
│ ◀─────────────────────── │
│ │ │
```
### 7.3 Mapping Table (WellNuo DB)
```sql
-- Link between WellNuo beneficiary and Legacy deployment
CREATE TABLE beneficiary_deployments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
beneficiary_id UUID REFERENCES person_details(id),
legacy_deployment_id INTEGER NOT NULL, -- ID from eluxnetworks API
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(beneficiary_id)
);
```
---
## 8. Priorities
### 8.1 What's Needed for MVP (blockers)
| # | Requirement | Priority | Status |
|---|-------------|----------|--------|
| 1 | `set_deployment` returns `deployment_id` | 🔴 Blocker | Awaiting fix |
| 2 | API Key or Service Account authorization | 🔴 Blocker | Awaiting decision |
### 8.2 What Can Be Done Later
| # | Requirement | Priority |
|---|-------------|----------|
| 1 | Remove `user_name` from body | 🟡 Medium |
| 2 | Move token to header | 🟡 Medium |
| 3 | `external_beneficiary_id` instead of creating users | 🟢 Nice to have |
---
If you have any questions or comments — let's schedule a call.