{ "_meta": { "name": "SysAnal", "updatedAt": "2025-12-13T00:45:17.412Z" }, "elements": [ { "id": "info-project", "type": "card", "title": "WellNuo Mobile App", "subtitle": "Elderly Care Monitoring", "description": "**Stack:**\n- React Native 0.81.5 + Expo SDK 54\n- Expo Router 6.x\n- Backend: existing API (Python)\n- AI: OpenAI GPT-3.5-turbo (text only)\n\n**Repository:**\nGitea: `robert/MobileApp_react_native`\nBranch: `development`\n\n**We build:** frontend only", "tags": [ "system" ], "borderColor": "gray", "x": 140, "y": 543.75 }, { "id": "info-legend", "type": "card", "title": "TAG LEGEND", "subtitle": "Who performs the action", "description": "**frontend** - React Native app (our work)\n**backend** - Existing API (already done)\n**external** - External services (OpenAI, Stripe)\n**env** - Environment variables/credentials\n\n**completed: true** = access obtained/verified\n**completed: false** = need to obtain", "tags": [ "system" ], "borderColor": "gray", "x": 520, "y": 716.25 }, { "id": "info-data-flow", "type": "card", "title": "DATA FLOW PATTERN", "subtitle": "How data flows", "description": "**Every data screen:**\n\n1. **Mount** → setLoading(true)\n2. **API Request** → frontend → backend\n3. **Condition** → success/error?\n4. **Success** → setData() → render\n5. **Error** → setError() → Retry\n\n**Arrows:** → request | ← response", "tags": [ "system" ], "borderColor": "gray", "x": 140, "y": 780 }, { "id": "env-section", "type": "card", "title": "ENV / CREDENTIALS", "subtitle": "All project credentials", "description": "Environment variables section.\nVerified: December 12, 2025\n\n✅ = available | ❌ = needed", "tags": [ "env" ], "borderColor": "cyan", "x": 520, "y": 307.5 }, { "id": "env-gitea", "type": "card", "title": "GITEA_URL ✅", "subtitle": "Code repository", "description": "https://gitea.serv00.org\n\n**Repo:** robert/MobileApp_react_native\n**Branch:** development", "tags": [ "env" ], "borderColor": "cyan", "completed": true, "x": 900, "y": 77.5 }, { "id": "env-api-url", "type": "card", "title": "API_URL ✅", "subtitle": "Backend API endpoint", "description": "**URL:** `https://eluxnetworks.net/function/well-api/api`\n\n**Format:** x-www-form-urlencoded\n**Parameter:** function=function_name\n\n**Dashboard:** https://react.eluxnetworks.net/dashboard\n\n**Verified:** working ✅", "tags": [ "env", "backend" ], "borderColor": "cyan", "completed": true, "x": 900, "y": 192.5 }, { "id": "env-api-credentials", "type": "card", "title": "API_CREDENTIALS ✅", "subtitle": "Login/password for API", "description": "**Username:** anandk\n**Password:** anandk_8\n\n**Test response:**\n- user_id: 43\n- max_role: 2\n- privileges: 21,38,29,41,42\n\n**Verified:** 12.12.2025 ✅", "tags": [ "env", "backend" ], "borderColor": "cyan", "completed": true, "x": 900, "y": 307.5 }, { "id": "env-expo-project", "type": "card", "title": "EXPO_PROJECT_ID ✅", "subtitle": "EAS Project ID", "description": "For EAS Build and Push Notifications\n\nhttps://expo.dev\n\n**Project ID:** 4f415b4b-41c8-4b98-989c-32f6b3f97481\n**Owner:** serter2069ya\n\nCreated: Dec 17, 2025", "tags": [ "env" ], "borderColor": "cyan", "completed": true, "x": 900, "y": 422.5 }, { "id": "env-stripe-pub", "type": "card", "title": "STRIPE_PUBLISHABLE_KEY ❌", "subtitle": "Stripe Public Key", "description": "`pk_xxx`\n\nFor in-app payments\n\nhttps://dashboard.stripe.com/apikeys", "tags": [ "env", "external" ], "borderColor": "cyan", "completed": false, "x": 1280, "y": 77.5 }, { "id": "env-stripe-secret", "type": "card", "title": "STRIPE_SECRET_KEY ❌", "subtitle": "Stripe Secret (backend)", "description": "`sk_xxx`\n\nBackend only!", "tags": [ "env", "backend" ], "borderColor": "cyan", "completed": false, "x": 1280, "y": 192.5 }, { "id": "env-sendgrid", "type": "card", "title": "SENDGRID_API_KEY ❌", "subtitle": "Email service", "description": "`SG.xxx`\n\nFor sending:\n- Welcome email\n- Password reset", "tags": [ "env", "external" ], "borderColor": "cyan", "completed": false, "x": 1280, "y": 307.5 }, { "id": "api-structure", "type": "card", "title": "API STRUCTURE", "subtitle": "Existing API structure", "description": "**Base URL:**\n`https://eluxnetworks.net/function/well-api/api`\n\n**Format:** POST x-www-form-urlencoded\n\n**Functions (verified):**\n- `function=credentials` → login\n- `function=voice_ask` → AI chat\n\n**Parameters credentials:**\n- user_name, ps, clientId, nonce\n\n**Parameters voice_ask:**\n- clientId, user_name, token, question, deployment_id", "tags": [ "backend" ], "borderColor": "green", "x": 900, "y": 537.5 }, { "id": "flow-start", "type": "card", "title": "1. APP START", "subtitle": "App launch", "description": "**File:** `app/_layout.tsx`\n\nUser opens the app.\nSplash Screen is shown.", "tags": [ "frontend" ], "borderColor": "blue", "x": 900, "y": 652.5 }, { "id": "flow-check-token", "type": "condition", "title": "2. Token in SecureStore?", "subtitle": "Authorization check", "description": "```javascript\nconst token = await SecureStore.getItemAsync('accessToken')\n```\n\nIf token exists → verify validity\nIf not → Login Screen", "tags": [ "frontend" ], "borderColor": "yellow", "x": 1280, "y": 652.5 }, { "id": "flow-login-screen", "type": "card", "title": "3. LOGIN SCREEN", "subtitle": "Login screen", "description": "**File:** `app/(auth)/login.tsx`\n\n**State:**\n- username, password\n- loading, error\n\n**Fields:**\n- Username (not email!)\n- Password\n\n**Buttons:**\n- [Sign In]\n- [Forgot Password?]\n- [Create Account]", "tags": [ "frontend" ], "borderColor": "blue", "x": 1948.8316650390625, "y": 717.6703491210938 }, { "id": "flow-login-loading", "type": "card", "title": "3a. Loading State", "subtitle": "Show spinner", "description": "```javascript\nsetLoading(true)\nsetError(null)\n```\n\n- Disable button\n- Show spinner", "tags": [ "frontend" ], "borderColor": "blue", "x": 1660, "y": 540 }, { "id": "flow-login-api", "type": "card", "title": "4. POST function=credentials", "subtitle": "Authorization (existing API)", "description": "**URL:** https://eluxnetworks.net/function/well-api/api\n**Format:** x-www-form-urlencoded\n\n**Request:**\n```\nfunction=credentials\nuser_name=anandk\nps=password\nclientId=001\nnonce=random_number\n```\n\n**Response 200:**\n```json\n{\n \"access_token\": \"jwt...\",\n \"privileges\": \"21,38,29,41,42\",\n \"user_id\": 43,\n \"max_role\": 2,\n \"status\": \"200 OK\"\n}\n```", "tags": [ "backend" ], "borderColor": "green", "x": 1981.828125, "y": 401.3630065917969 }, { "id": "flow-login-condition", "type": "condition", "title": "4a. Success?", "subtitle": "Response check", "description": "**status === \"200 OK\"?**\n\n**Yes** → Save token\n**No** → Show error", "tags": [ "frontend" ], "borderColor": "yellow", "x": 2388.911865234375, "y": 394.84893798828125 }, { "id": "flow-login-success", "type": "card", "title": "5. Save token", "subtitle": "SecureStore", "description": "```javascript\nawait SecureStore.setItemAsync('accessToken', response.access_token)\nawait SecureStore.setItemAsync('userId', response.user_id)\nawait SecureStore.setItemAsync('privileges', response.privileges)\n```\n\nNavigate to main screen", "tags": [ "frontend" ], "borderColor": "blue", "x": 2800, "y": 480 }, { "id": "flow-login-error", "type": "card", "title": "5b. Error State", "subtitle": "Show error", "description": "```javascript\nsetLoading(false)\nsetError('Invalid credentials')\n```\n\n- Red error text\n- Retry button active", "tags": [ "frontend" ], "borderColor": "red", "x": 2578.297607421875, "y": 681.2437744140625 }, { "id": "flow-register-screen", "type": "card", "title": "3r. REGISTER SCREEN", "subtitle": "Registration screen", "description": "**File:** `app/(auth)/register.tsx`\n\n**Fields:**\n- Full Name\n- Email\n- Password\n- Confirm Password\n\n**Buttons:**\n- [Create Account]\n- [Sign In]", "tags": [ "frontend" ], "borderColor": "blue", "x": 1660, "y": 880 }, { "id": "flow-register-validate", "type": "condition", "title": "3r-1. Validation?", "subtitle": "Client-side check", "description": "- Name not empty?\n- Email valid?\n- Password >= 6?\n- Passwords match?", "tags": [ "frontend" ], "borderColor": "yellow", "x": 2040, "y": 880 }, { "id": "flow-register-api", "type": "card", "title": "3r-2. POST register", "subtitle": "Registration API", "description": "**Request:**\n```json\n{\n \"name\": \"John\",\n \"email\": \"user@example.com\",\n \"password\": \"xxx\"\n}\n```\n\n**Response 201:** tokens\n**Error 409:** Email exists", "tags": [ "backend" ], "borderColor": "green", "x": 2420, "y": 880 }, { "id": "flow-register-email", "type": "card", "title": "3r-3. Welcome Email", "subtitle": "SendGrid", "description": "Backend sends welcome email\n\n(on server)", "tags": [ "external" ], "borderColor": "orange", "x": 2800, "y": 880 }, { "id": "flow-forgot-screen", "type": "card", "title": "3f. FORGOT PASSWORD", "subtitle": "Password recovery", "description": "**File:** `app/(auth)/forgot.tsx`\n\n**Field:** Email\n\n**Buttons:**\n- [Send Reset Link]\n- [Back to Login]", "tags": [ "frontend" ], "borderColor": "blue", "x": 1660, "y": 1050 }, { "id": "flow-forgot-api", "type": "card", "title": "3f-1. POST forgot", "subtitle": "Reset API", "description": "**Request:**\n```json\n{ \"email\": \"user@example.com\" }\n```\n\n**Response 200:**\n```json\n{ \"message\": \"Reset link sent\" }\n```", "tags": [ "backend" ], "borderColor": "green", "x": 2040, "y": 1050 }, { "id": "flow-patients-list", "type": "card", "title": "6. PATIENTS LIST", "subtitle": "Main screen - patients list", "description": "**File:** `app/(tabs)/index.tsx`\n\n**State:**\n- patients: Patient[]\n- loading, error\n\n**UI:**\n- Card list\n- Pull to refresh\n- [+] Add\n\n**Tab Bar:** Home | Chat | Profile", "tags": [ "frontend" ], "borderColor": "blue", "x": 3180, "y": 480 }, { "id": "flow-patients-loading", "type": "card", "title": "6a. Loading", "subtitle": "useEffect mount", "description": "```javascript\nuseEffect(() => {\n loadPatients()\n}, [])\n```\n\nsetLoading(true)", "tags": [ "frontend" ], "borderColor": "blue", "x": 3560, "y": 400 }, { "id": "flow-patients-api", "type": "card", "title": "6b. GET patients", "subtitle": "API request", "description": "**Request:**\n```\nfunction=get_patients\ntoken=jwt\n```\n\n**Response:**\n```json\n{ \"patients\": [...] }\n```", "tags": [ "backend" ], "borderColor": "green", "x": 3940, "y": 400 }, { "id": "flow-patients-condition", "type": "condition", "title": "6c. Success?", "subtitle": "Check", "description": "**ok === true?**\n\n**Yes** → render\n**No** → error", "tags": [ "frontend" ], "borderColor": "yellow", "x": 4320, "y": 400 }, { "id": "flow-patients-render", "type": "card", "title": "6d. Render", "subtitle": "Render", "description": "```javascript\nsetLoading(false)\nsetPatients(data)\n```\n\nFlatList updates", "tags": [ "frontend" ], "borderColor": "blue", "x": 4700, "y": 340 }, { "id": "flow-patients-error", "type": "card", "title": "6e. Error", "subtitle": "Error + Retry", "description": "```javascript\nsetError('Failed')\n```\n\n[Retry] button", "tags": [ "frontend" ], "borderColor": "red", "x": 4700, "y": 480 }, { "id": "flow-patient-dashboard", "type": "card", "title": "7. PATIENT DASHBOARD", "subtitle": "Patient dashboard", "description": "**File:** `app/patients/[id]/index.tsx`\n\n**Sections:**\n- Status (online/offline)\n- Health (pulse, steps, sleep)\n- Medication reminders\n- [Chat with Julia] → AI Chat", "tags": [ "frontend" ], "borderColor": "blue", "x": 3180, "y": 620 }, { "id": "flow-add-patient", "type": "card", "title": "6+. ADD PATIENT", "subtitle": "Add patient", "description": "**File:** `app/patients/add.tsx`\n\n**Fields:**\n- Name\n- Photo\n- Relationship\n- Device ID", "tags": [ "frontend" ], "borderColor": "blue", "x": 3180, "y": 760 }, { "id": "flow-chat-screen", "type": "card", "title": "8. AI CHAT SCREEN", "subtitle": "Text chat with Julia", "description": "**File:** `app/(tabs)/chat.tsx`\n\n**State:**\n- messages: Message[]\n- input, sending\n\n**UI:**\n- History (bubbles)\n- Input + Send\n- Typing indicator", "tags": [ "frontend" ], "borderColor": "blue", "x": 3560, "y": 620 }, { "id": "flow-chat-send", "type": "card", "title": "8a. Send", "subtitle": "Send message", "description": "```javascript\nsetSending(true)\nsetMessages([...messages, {\n role: 'user',\n content: input\n}])\n```", "tags": [ "frontend" ], "borderColor": "blue", "x": 3940, "y": 560 }, { "id": "flow-chat-send-api", "type": "card", "title": "9. POST function=voice_ask", "subtitle": "Send message (existing API)", "description": "**URL:** https://eluxnetworks.net/function/well-api/api\n**Format:** x-www-form-urlencoded\n\n**Request:**\n```\nfunction=voice_ask\nclientId=MA_001\nuser_name=anandk\ntoken=jwt_token\nquestion=How is mom doing?\ndeployment_id=21\n```\n\n**Response 200:**\n```json\n{\n \"ok\": true,\n \"response\": {\n \"Command\": \"REPORT\",\n \"body\": \"Hello! How can I assist you?\",\n \"language\": \"English\"\n },\n \"status\": \"200 OK\"\n}\n```", "tags": [ "backend" ], "borderColor": "green", "x": 4320, "y": 560 }, { "id": "flow-chat-openai", "type": "card", "title": "10. OpenAI GPT-3.5-turbo", "subtitle": "AI processing (on backend)", "description": "Backend uses:\n**Model:** gpt-3.5-turbo\n\nThis happens on server.\nFrontend just sends question and gets response.\n\n**We do NOT call OpenAI directly!**", "tags": [ "external" ], "borderColor": "orange", "x": 4700, "y": 620 }, { "id": "flow-chat-response", "type": "card", "title": "10a. Render Response", "subtitle": "Show response", "description": "```javascript\nsetSending(false)\nsetMessages([...messages, {\n role: 'assistant',\n content: response.body\n}])\n```", "tags": [ "frontend" ], "borderColor": "blue", "x": 4700, "y": 760 }, { "id": "flow-profile-screen", "type": "card", "title": "11. PROFILE SCREEN", "subtitle": "User profile", "description": "**File:** `app/(tabs)/profile.tsx`\n\n**Sections:**\n- Avatar, name, email\n- [Edit Profile]\n- Notification Settings\n- [Subscription]\n- [Logout]", "tags": [ "frontend" ], "borderColor": "blue", "x": 3560, "y": 760 }, { "id": "flow-profile-api", "type": "card", "title": "11a. GET profile", "subtitle": "Load profile", "description": "**Response:**\n```json\n{\n \"name\": \"John\",\n \"email\": \"...\",\n \"subscription\": {...}\n}\n```", "tags": [ "backend" ], "borderColor": "green", "x": 3940, "y": 760 }, { "id": "flow-profile-update", "type": "card", "title": "11b. PATCH profile", "subtitle": "Update", "description": "**Request:**\n```json\n{ \"name\": \"New\" }\n```", "tags": [ "backend" ], "borderColor": "green", "x": 4320, "y": 760 }, { "id": "flow-subscription-screen", "type": "card", "title": "12. SUBSCRIPTION", "subtitle": "Subscription management", "description": "**File:** `app/subscription/index.tsx`\n\n**Plans:**\n- Free: 1 patient\n- Basic ($9.99): 3 patients\n- Premium ($19.99): Unlimited", "tags": [ "frontend" ], "borderColor": "blue", "x": 3560, "y": 900 }, { "id": "flow-stripe-checkout", "type": "card", "title": "12a. Stripe Checkout", "subtitle": "Payment page", "description": "WebView or in-app browser\n\nAfter payment → redirect\n`wellnuo://payment-success`", "tags": [ "external" ], "borderColor": "orange", "x": 3940, "y": 900 }, { "id": "flow-stripe-webhook", "type": "card", "title": "12b. Stripe Webhook", "subtitle": "Backend processing", "description": "**Events:**\n- checkout.session.completed\n- invoice.paid\n\nDB update", "tags": [ "backend" ], "borderColor": "green", "x": 4320, "y": 900 }, { "id": "flow-logout", "type": "card", "title": "13. LOGOUT", "subtitle": "Sign out", "description": "```javascript\nawait SecureStore.deleteItemAsync('accessToken')\nawait SecureStore.deleteItemAsync('userId')\nrouter.replace('/(auth)/login')\n```", "tags": [ "frontend" ], "borderColor": "blue", "x": 3180, "y": 900 }, { "id": "db-schema", "type": "card", "title": "DATABASE SCHEMA", "subtitle": "PostgreSQL tables", "description": "**users:** id, name, email, password_hash, avatar, subscription\n\n**patients:** id, name, avatar, device_id, status, health_data\n\n**user_patients:** user_id, patient_id, relationship\n\n**messages:** id, user_id, patient_id, role, content\n\n**alerts:** id, patient_id, type, message, read\n\n**password_resets:** id, user_id, token, expires_at", "tags": [ "backend" ], "borderColor": "teal", "x": 140, "y": 1000 }, { "id": "design-colors", "type": "card", "title": "DESIGN: Colors", "subtitle": "Color palette", "description": "**Primary:**\n- `#4A90D9` - Primary Blue\n- `#2E5C8A` - Primary Dark\n\n**Status:**\n- `#5AC8A8` - Success\n- `#F5A623` - Warning\n- `#D0021B` - Error\n\n**Neutral:**\n- `#FFFFFF` - Background\n- `#F5F7FA` - Surface\n- `#333333` - Text Primary", "tags": [ "system" ], "borderColor": "pink", "x": 520, "y": 1000 }, { "id": "design-typography", "type": "card", "title": "DESIGN: Typography", "subtitle": "Fonts", "description": "**Font:** Inter\n\n**Sizes:**\nxs: 12, sm: 14, base: 16\nlg: 18, xl: 20, 2xl: 24\n\n**Weights:** 400, 500, 600, 700", "tags": [ "system" ], "borderColor": "pink", "x": 900, "y": 1000 }, { "id": "todo-frontend", "type": "card", "title": "TODO: Frontend tasks", "subtitle": "What needs to be done", "description": "**1. Auth:**\n- [ ] Login screen\n- [ ] Register screen\n- [ ] Forgot password\n- [ ] SecureStore\n\n**2. Chat:**\n- [ ] Chat UI (bubbles)\n- [ ] voice_ask API\n- [ ] Typing indicator\n\n**3. Patients:**\n- [ ] List screen\n- [ ] Dashboard\n- [ ] Add patient\n\n**4. Profile:**\n- [ ] Profile screen\n- [ ] Subscription\n- [ ] Logout", "tags": [ "frontend" ], "borderColor": "blue", "completed": false, "x": 1280, "y": 1000 } ], "connections": [ { "from": "info-project", "to": "info-legend" }, { "from": "info-legend", "to": "info-data-flow" }, { "from": "info-project", "to": "env-section" }, { "from": "env-section", "to": "env-gitea" }, { "from": "env-section", "to": "env-api-url" }, { "from": "env-section", "to": "env-api-credentials" }, { "from": "env-section", "to": "env-expo-project" }, { "from": "env-section", "to": "env-stripe-pub" }, { "from": "env-section", "to": "env-stripe-secret" }, { "from": "env-section", "to": "env-sendgrid" }, { "from": "env-section", "to": "api-structure" }, { "from": "api-structure", "to": "flow-start" }, { "from": "flow-start", "to": "flow-check-token" }, { "from": "flow-check-token", "to": "flow-login-screen", "label": "No token" }, { "from": "flow-check-token", "to": "flow-patients-list", "label": "Has token" }, { "from": "flow-login-screen", "to": "flow-login-loading", "label": "Sign In" }, { "from": "flow-login-loading", "to": "flow-login-api" }, { "from": "flow-login-api", "to": "flow-login-condition" }, { "from": "flow-login-condition", "to": "flow-login-success", "label": "200 OK" }, { "from": "flow-login-condition", "to": "flow-login-error", "label": "Error" }, { "from": "flow-login-success", "to": "flow-patients-list" }, { "from": "flow-login-error", "to": "flow-login-screen", "label": "Retry" }, { "from": "flow-login-screen", "to": "flow-register-screen", "label": "Create Account" }, { "from": "flow-register-screen", "to": "flow-register-validate", "label": "Submit" }, { "from": "flow-register-validate", "to": "flow-register-api", "label": "Valid" }, { "from": "flow-register-api", "to": "flow-register-email" }, { "from": "flow-register-email", "to": "flow-login-success" }, { "from": "flow-login-screen", "to": "flow-forgot-screen", "label": "Forgot?" }, { "from": "flow-forgot-screen", "to": "flow-forgot-api", "label": "Submit" }, { "from": "flow-forgot-api", "to": "flow-login-screen", "label": "Email sent" }, { "from": "flow-patients-list", "to": "flow-patients-loading", "label": "Mount" }, { "from": "flow-patients-loading", "to": "flow-patients-api" }, { "from": "flow-patients-api", "to": "flow-patients-condition" }, { "from": "flow-patients-condition", "to": "flow-patients-render", "label": "Success" }, { "from": "flow-patients-condition", "to": "flow-patients-error", "label": "Error" }, { "from": "flow-patients-error", "to": "flow-patients-loading", "label": "Retry" }, { "from": "flow-patients-render", "to": "flow-patients-list", "label": "Render" }, { "from": "flow-patients-list", "to": "flow-patient-dashboard", "label": "Select patient" }, { "from": "flow-patients-list", "to": "flow-add-patient", "label": "+ Add" }, { "from": "flow-add-patient", "to": "flow-patients-list", "label": "Created" }, { "from": "flow-patient-dashboard", "to": "flow-chat-screen", "label": "Chat with Julia" }, { "from": "flow-chat-screen", "to": "flow-chat-send", "label": "Send" }, { "from": "flow-chat-send", "to": "flow-chat-send-api" }, { "from": "flow-chat-send-api", "to": "flow-chat-openai" }, { "from": "flow-chat-openai", "to": "flow-chat-response" }, { "from": "flow-chat-response", "to": "flow-chat-screen", "label": "Render" }, { "from": "flow-patients-list", "to": "flow-profile-screen", "label": "Tab: Profile" }, { "from": "flow-profile-screen", "to": "flow-profile-api", "label": "Load" }, { "from": "flow-profile-screen", "to": "flow-profile-update", "label": "Edit" }, { "from": "flow-profile-screen", "to": "flow-subscription-screen", "label": "Subscription" }, { "from": "flow-profile-screen", "to": "flow-logout", "label": "Logout" }, { "from": "flow-subscription-screen", "to": "flow-stripe-checkout", "label": "Select Plan" }, { "from": "flow-stripe-checkout", "to": "flow-stripe-webhook" }, { "from": "flow-stripe-webhook", "to": "flow-profile-screen", "label": "Updated" }, { "from": "flow-logout", "to": "flow-login-screen" }, { "from": "db-schema", "to": "design-colors" }, { "from": "design-colors", "to": "design-typography" }, { "from": "design-typography", "to": "todo-frontend" } ], "tagsDictionary": [ { "name": "system", "color": "gray" }, { "name": "env", "color": "cyan" }, { "name": "frontend", "color": "blue" }, { "name": "backend", "color": "green" }, { "name": "external", "color": "orange" } ] }