From 1e926f8072da40718b35ce035af2f1553ebb216a Mon Sep 17 00:00:00 2001 From: Antigravity Date: Wed, 13 May 2026 14:50:37 -0400 Subject: [PATCH] feat: rebrand to Curio and update ingress for curaflow.applaude.net --- curaflow/.gitea/workflows/build.yaml | 8 +- curaflow/backend/botLogic.js | 4 +- curaflow/backend/configManager.js | 50 ++++--- curaflow/backend/i18n.js | 2 +- curaflow/backend/queueManager.js | 45 +++--- curaflow/backend/server.js | 9 +- curaflow/backend_tests.js | 44 ++++++ curaflow/billing.html | 12 +- curaflow/dashboard.html | 205 ++++++++++++++++----------- curaflow/dashboard.js | 25 ++++ curaflow/index.css | 108 ++++++++++++++ curaflow/index.html | 67 +++++++-- curaflow/index.js | 2 +- curaflow/k8s/apisix-route.yaml | 17 +++ curaflow/k8s/app.yaml | 40 ++---- curaflow/k8s/database.yaml | 14 +- curaflow/lab.html | 12 +- curaflow/login.html | 16 ++- curaflow/pharmacy.html | 12 +- curaflow/register.html | 4 +- curaflow/settings.html | 12 +- curaflow/staff.html | 12 +- curaflow/tenantLoader.js | 47 ++++++ 23 files changed, 575 insertions(+), 192 deletions(-) create mode 100644 curaflow/backend_tests.js create mode 100644 curaflow/k8s/apisix-route.yaml create mode 100644 curaflow/tenantLoader.js diff --git a/curaflow/.gitea/workflows/build.yaml b/curaflow/.gitea/workflows/build.yaml index 89ce024..f112a6d 100644 --- a/curaflow/.gitea/workflows/build.yaml +++ b/curaflow/.gitea/workflows/build.yaml @@ -1,4 +1,4 @@ -name: Build CuraFlow HMS +name: Build Curio HMS on: [push] jobs: @@ -16,8 +16,8 @@ jobs: docker run --rm \ --volumes-from "$JOB_CONTAINER" \ gcr.io/kaniko-project/executor:latest \ - --context=dir://"$GITHUB_WORKSPACE/curaflow" \ - --dockerfile="$GITHUB_WORKSPACE/curaflow/Dockerfile" \ - --destination=192.168.8.250:5000/agentic-os/curaflow:latest \ + --context=dir://"$GITHUB_WORKSPACE" \ + --dockerfile="$GITHUB_WORKSPACE/Dockerfile" \ + --destination=192.168.8.250:5000/Curio:latest \ --insecure \ --skip-tls-verify diff --git a/curaflow/backend/botLogic.js b/curaflow/backend/botLogic.js index 09ea471..09d1ffd 100644 --- a/curaflow/backend/botLogic.js +++ b/curaflow/backend/botLogic.js @@ -19,7 +19,7 @@ class BotLogic { if (text.includes('hi') && !this.states[`${patientId}_lang`]) { this.states[patientId] = 'SELECT_LANG'; return { - reply: "Welcome to CuraFlow! Please select your language / भाषा चुनें / భాషను ఎంచుకోండి:\n\n1. English\n2. Hindi (हिंदी)\n3. Telugu (తెలుగు)", + reply: "Welcome to Curio! Please select your language / भाषा चुनें / భాషను ఎంచుకోండి:\n\n1. English\n2. Hindi (हिंदी)\n3. Telugu (తెలుగు)", buttons: ["English", "Hindi", "Telugu"] }; } @@ -56,7 +56,7 @@ class BotLogic { this.states[patientId] = 'TRIAGE_START'; return { reply: i18n.t(lang, 'triage_ask', { token: result.token }) + - ` \n\n💳 *Payment Required*: Please pay ₹${result.fee} to activate your token: http://razorpay.me/curaflow_mock`, + ` \n\n💳 *Payment Required*: Please pay ₹${result.fee} to activate your token: http://razorpay.me/Curio_mock`, }; } else { return { diff --git a/curaflow/backend/configManager.js b/curaflow/backend/configManager.js index 4103afa..64dec09 100644 --- a/curaflow/backend/configManager.js +++ b/curaflow/backend/configManager.js @@ -1,30 +1,46 @@ /** - * ConfigManager: Central configuration for hospital-wide pricing and slots. + * ConfigManager: Central configuration for multi-tenant hospital settings and white-labeling. */ class ConfigManager { constructor() { - this.config = { - consultationFee: 500, - slotDuration: 30, // minutes - onlineSlotLimit: 3, - walkinSlotLimit: 5, - hospitalName: "Dr. Sharma's Clinic", - currency: "₹" + this.tenants = { + 'default': { + name: "Curio Clinic", + logo: "C", + primaryColor: "#0F172A", + secondaryColor: "#38BDF8", + consultationFee: 500, + currency: "₹" + }, + 'sharma-clinic': { + name: "Dr. Sharma's Cardiology", + logo: "S", + primaryColor: "#1E3A8A", // Deep Blue + secondaryColor: "#60A5FA", + consultationFee: 800, + currency: "₹" + }, + 'apollo-hospitals': { + name: "Apollo Multispecialty", + logo: "A", + primaryColor: "#065F46", // Dark Green + secondaryColor: "#34D399", + consultationFee: 1200, + currency: "₹" + } }; } - get(key) { - return this.config[key]; + getTenantConfig(tenantId) { + return this.tenants[tenantId] || this.tenants['default']; } - set(key, value) { - this.config[key] = value; - console.log(`Config updated: ${key} = ${value}`); - } - - getAll() { - return this.config; + updateTenantConfig(tenantId, newConfig) { + if (!this.tenants[tenantId]) { + this.tenants[tenantId] = { ...this.tenants['default'] }; + } + this.tenants[tenantId] = { ...this.tenants[tenantId], ...newConfig }; } } diff --git a/curaflow/backend/i18n.js b/curaflow/backend/i18n.js index e0749aa..6b53621 100644 --- a/curaflow/backend/i18n.js +++ b/curaflow/backend/i18n.js @@ -1,5 +1,5 @@ /** - * i18n: Translation manager for CuraFlow WhatsApp Bot. + * i18n: Translation manager for Curio WhatsApp Bot. * Supports English (en), Hindi (hi), and Telugu (te). */ diff --git a/curaflow/backend/queueManager.js b/curaflow/backend/queueManager.js index 0c65c9c..a66abcc 100644 --- a/curaflow/backend/queueManager.js +++ b/curaflow/backend/queueManager.js @@ -1,5 +1,5 @@ /** - * QueueManager: Handles the hybrid slot logic for CuraFlow + * QueueManager: Handles the hybrid slot logic for Curio * - 30-min slots * - Max 3 online bookings (Hard Cap) * - 5 Walk-in slots @@ -9,65 +9,68 @@ const configManager = require('./configManager'); class QueueManager { constructor() { - this.slots = {}; // Key: "YYYY-MM-DD:HH:mm" + this.slots = {}; // Key: "tenantId:YYYY-MM-DD:HH:mm" } - getSlotKey(date, time) { - // Round time to nearest slot duration - const duration = configManager.get('slotDuration'); + getSlotKey(tenantId, date, time) { + const config = configManager.getTenantConfig(tenantId); + const duration = config.slotDuration || 30; const [hours, minutes] = time.split(':'); const roundedMins = parseInt(minutes) < duration ? '00' : duration; - return `${date}:${hours}:${roundedMins}`; + return `${tenantId}:${date}:${hours}:${roundedMins}`; } - getSlotStatus(date, time) { - const key = this.getSlotKey(date, time); + getSlotStatus(tenantId, date, time) { + const key = this.getSlotKey(tenantId, date, time); if (!this.slots[key]) { + const config = configManager.getTenantConfig(tenantId); this.slots[key] = { online: 0, walkin: 0, - maxOnline: configManager.get('onlineSlotLimit'), - maxWalkin: configManager.get('walkinSlotLimit') + maxOnline: config.onlineSlotLimit || 3, + maxWalkin: config.walkinSlotLimit || 5 }; } return this.slots[key]; } - bookOnline(date, time) { - const status = this.getSlotStatus(date, time); + bookOnline(date, time, tenantId = 'default') { + const status = this.getSlotStatus(tenantId, date, time); + const config = configManager.getTenantConfig(tenantId); if (status.online < status.maxOnline) { status.online++; return { success: true, token: `ON-${status.online}`, - slot: this.getSlotKey(date, time), + slot: this.getSlotKey(tenantId, date, time), status: 'PENDING_PAYMENT', - fee: configManager.get('consultationFee') + fee: config.consultationFee }; } return { success: false, message: "Slot full for online booking. Try next slot." }; } - bookWalkin(date, time) { - const status = this.getSlotStatus(date, time); + bookWalkin(date, time, tenantId = 'default') { + const status = this.getSlotStatus(tenantId, date, time); + const config = configManager.getTenantConfig(tenantId); if (status.walkin < status.maxWalkin) { status.walkin++; return { success: true, token: `WK-${status.walkin}`, status: 'PENDING_PAYMENT', - fee: configManager.get('consultationFee') + fee: config.consultationFee }; } return { success: false, message: "Clinic is at full capacity for this slot." }; } - getDailyUpdates(patientId) { - // Mock data for daily updates + getDailyUpdates(patientId, tenantId = 'default') { + const config = configManager.getTenantConfig(tenantId); return [ - "Good morning! Your appointment with Dr. Sharma is at 10:30 AM today.", + `Good morning! Your appointment with ${config.name} is scheduled for today.`, "Queue Update: The clinic is running 10 mins behind schedule. Please plan accordingly.", - "Reminder: Don't forget to bring your previous blood reports." + "Reminder: Don't forget to bring your previous reports." ]; } } diff --git a/curaflow/backend/server.js b/curaflow/backend/server.js index 7f131f5..9efe3f2 100644 --- a/curaflow/backend/server.js +++ b/curaflow/backend/server.js @@ -1,6 +1,7 @@ const express = require('express'); const path = require('path'); const botLogic = require('./botLogic'); +const configManager = require('./configManager'); const app = express(); const port = 3000; @@ -12,6 +13,12 @@ app.get('/', (req, res) => { res.sendFile(path.join(__dirname, '../login.html')); }); +// Multi-tenant Config API +app.get('/api/config/:tenantId', (req, res) => { + const config = configManager.getTenantConfig(req.params.tenantId); + res.json(config); +}); + // Mock WhatsApp Webhook app.post('/whatsapp/webhook', async (req, res) => { const { from, body } = req.body; @@ -28,5 +35,5 @@ app.post('/whatsapp/webhook', async (req, res) => { }); app.listen(port, '0.0.0.0', () => { - console.log(`CuraFlow WhatsApp Mock Server running at http://0.0.0.0:${port}`); + console.log(`Curio WhatsApp Mock Server running at http://0.0.0.0:${port}`); }); diff --git a/curaflow/backend_tests.js b/curaflow/backend_tests.js new file mode 100644 index 0000000..7027732 --- /dev/null +++ b/curaflow/backend_tests.js @@ -0,0 +1,44 @@ +const queueManager = require('./backend/queueManager'); +const botLogic = require('./backend/botLogic'); +const configManager = require('./backend/configManager'); + +console.log("=== STARTING BACKEND UNIT TESTS ==="); + +// 1. Test QueueManager - Online Booking Limits +console.log("\nTesting QueueManager: Online Booking Limits"); +const date = "2026-05-13"; +const time = "10:00"; + +for (let i = 0; i < 4; i++) { + const res = queueManager.bookOnline(date, time); + console.log(`Booking ${i+1}:`, res.success ? `Success - ${res.token}` : `Failed - ${res.message}`); +} + +// 2. Test QueueManager - Walkin Booking +console.log("\nTesting QueueManager: Walk-in Booking"); +const walkRes = queueManager.bookWalkin(date, time); +console.log("Walkin result:", walkRes.token); + +// 3. Test Bot Logic - WhatsApp Simulation +console.log("\nTesting BotLogic: WhatsApp Interactions"); +async function testBot() { + const msg1 = await botLogic.handleMessage("9876543210", "Hi"); + console.log("User: Hi -> Bot:", msg1.reply); + + const msg2 = await botLogic.handleMessage("9876543210", "Book Token"); + console.log("User: Book Token -> Bot:", msg2.reply); + console.log("Buttons:", msg2.buttons); +} + +testBot(); + +// 4. Test ConfigManager - Multi-tenancy +console.log("\nTesting ConfigManager: Multi-tenancy"); +const sharmaConfig = configManager.getTenantConfig('sharma-clinic'); +console.log("Sharma Clinic Name:", sharmaConfig.name); + +// 5. Test Multi-tenant Booking +console.log("\nTesting Multi-tenant Booking (Sharma Clinic)"); +const sharmaRes = queueManager.bookOnline(date, time, 'sharma-clinic'); +console.log("Sharma Booking Result:", sharmaRes.success ? `Success - ${sharmaRes.token} (Fee: ${sharmaRes.fee})` : "Failed"); + diff --git a/curaflow/billing.html b/curaflow/billing.html index 5f0ae36..de2486d 100644 --- a/curaflow/billing.html +++ b/curaflow/billing.html @@ -3,7 +3,7 @@ - CuraFlow Billing | Hospital Revenue & Accounts + Curio Billing | Hospital Revenue & Accounts @@ -13,7 +13,7 @@
diff --git a/curaflow/dashboard.html b/curaflow/dashboard.html index a3fe7f8..9dc4268 100644 --- a/curaflow/dashboard.html +++ b/curaflow/dashboard.html @@ -3,21 +3,22 @@ - CuraFlow Dashboard | Dr. Sharma's Clinic + Dashboard | Curio + @@ -44,101 +46,142 @@ -
-
- In Queue -

12 Patients

- ↑ 4 since last hour -
-
- Current Slot (10:00-10:30) -
-
- Online: 3/3 (CLOSED) -
-
-
- Walk-in: 4/5 -
+
+
+
+ In Queue +

12 Patients

+ ↑ 4 since last hour +
+
+ Current Slot (10:00-10:30) +
+
+ Online: 3/3 (CLOSED) +
+
+
+ Walk-in: 4/5 +
+
-
-
- Avg. Wait Time -

18 Mins

- Target: 15 Mins -
-
+
+ Avg. Wait Time +

18 Mins

+ Target: 15 Mins +
+ -
-
-
-

Live Queue

-
- All - Appointments - Walk-ins +
+
+
+

Live Queue

+
+ All + Appointments + Walk-ins +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TokenPatient NameSourceLangTriage AIStatusArrivalActions
#012Rahul VermaOnlineHIHigh Fever / CoughIn Room09:15 AM
#013Anjali SinghWalk-inTEGeneral CheckupUnpaid (₹500)09:30 AM
#014Suresh KumarOnlineENBack PainPaid (Waiting)09:45 AM
+
+ +
+
+

✨ AI Insights

+

Predicted peak time: 11:30 AM. Suggesting 5-min break for staff now.

+
+ No-show Alert +

Token #015 (Vikram) hasn't replied to the 10-min reminder.

+
+
+
+
+
+ + - -
-
-

✨ AI Insights

-

Predicted peak time: 11:30 AM. Suggesting 5-min break for staff now.

-
- No-show Alert -

Token #015 (Vikram) hasn't replied to the 10-min reminder.

-
-
-
-
+ +