evaldoc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.staging.example +19 -0
- package/.firebaserc +6 -0
- package/.github/workflows/auto-merge-to-main.yml +28 -0
- package/.github/workflows/ci.yml +27 -0
- package/.github/workflows/npxhub-publish.yml +170 -0
- package/.prettierignore +4 -0
- package/.prettierrc.json +7 -0
- package/README.md +142 -0
- package/SRS.md +448 -0
- package/apphosting.staging.yaml +48 -0
- package/apphosting.yaml +50 -0
- package/bin/evaldoc.cjs +105 -0
- package/cors.json +8 -0
- package/docs/ARCHITECTURE.md +769 -0
- package/docs/ARCHITECTURE_SUMMARY.md +323 -0
- package/docs/DEPLOYMENT.md +86 -0
- package/docs/DEPLOYMENT_STEPS.md +373 -0
- package/docs/DEPLOY_FIRESTORE_RULES.md +239 -0
- package/docs/DEPLOY_STORAGE_RULES.md +82 -0
- package/docs/DOCTOR_TUTORIAL.md +467 -0
- package/docs/FIREBASE_STORAGE_CORS_FIX.md +131 -0
- package/docs/FIXES_APPLIED.md +128 -0
- package/docs/IMPLEMENTATION.md +498 -0
- package/docs/IMPLEMENTATION_COMPLETE.md +317 -0
- package/docs/LLM-SETUP.md +216 -0
- package/docs/MANUAL_TEST_GUIDE.md +327 -0
- package/docs/PATIENT_GUIDE.md +451 -0
- package/docs/PLATFORM_OVERVIEW.md +194 -0
- package/docs/QUICKSTART.md +252 -0
- package/docs/QUICK_REFERENCE.md +222 -0
- package/docs/READY_TO_TEST.md +383 -0
- package/docs/RUN.md +237 -0
- package/docs/START_TESTING.md +130 -0
- package/docs/STRIPE_CONNECT_SETUP.md +454 -0
- package/docs/SYSTEM_READY.md +345 -0
- package/docs/THREADS_IMPLEMENTATION_COMPLETE.md +431 -0
- package/docs/THREAD_IMPLEMENTATION_GUIDE.md +345 -0
- package/docs/firebasefiles.md +21 -0
- package/docs/homepage.md +1208 -0
- package/docs/payments.md +159 -0
- package/eslint.config.js +76 -0
- package/firebase.json +27 -0
- package/firestore.indexes.json +88 -0
- package/firestore.rules +125 -0
- package/functions/package-lock.json +2884 -0
- package/functions/package.json +20 -0
- package/functions/src/analytics.js +101 -0
- package/functions/src/audit.js +28 -0
- package/functions/src/auth.js +19 -0
- package/functions/src/drafts.js +128 -0
- package/functions/src/feedback.js +164 -0
- package/functions/src/firebase-init.js +29 -0
- package/functions/src/i18n.js +134 -0
- package/functions/src/limits.js +27 -0
- package/functions/src/llm.js +271 -0
- package/functions/src/ner.js +162 -0
- package/functions/src/notifications.js +273 -0
- package/functions/src/orgs.js +127 -0
- package/functions/src/patient-api.js +545 -0
- package/functions/src/payment.js +830 -0
- package/functions/src/safety.js +188 -0
- package/functions/src/stripe-config.js +33 -0
- package/functions/src/topics.js +94 -0
- package/functions/src/triage.js +191 -0
- package/functions/src/utils.js +28 -0
- package/functions/src/validate.js +177 -0
- package/functions/test-firebase.js +36 -0
- package/jest.config.js +18 -0
- package/package.json +52 -0
- package/public/404.html +93 -0
- package/public/app/analytics.html +336 -0
- package/public/app/analytics.js +177 -0
- package/public/app/app.css +1400 -0
- package/public/app/app.js +1754 -0
- package/public/app/config.js +14 -0
- package/public/app/inbox-threads.js +843 -0
- package/public/app/inbox.html +598 -0
- package/public/app/inbox.js +397 -0
- package/public/app/index.html +612 -0
- package/public/assets/logo.jpg +0 -0
- package/public/chat.html +137 -0
- package/public/css/chat.css +870 -0
- package/public/css/landing-enhance.css +298 -0
- package/public/css/styles.css +1198 -0
- package/public/favicon.svg +5 -0
- package/public/find-doctor.html +220 -0
- package/public/index.html +399 -0
- package/public/js/chat-threads.js +513 -0
- package/public/js/chat.js +832 -0
- package/public/js/search.js +41 -0
- package/public/privacy.html +101 -0
- package/public/robots.txt +6 -0
- package/public/site.webmanifest +12 -0
- package/public/terms.html +110 -0
- package/scripts/create-test-provider.js +55 -0
- package/scripts/deploy-staging.sh +51 -0
- package/scripts/fix-provider.js +39 -0
- package/scripts/quick-test.sh +37 -0
- package/scripts/test-chat.sh +54 -0
- package/scripts/test-multi-turn.js +137 -0
- package/scripts/test-ner-simple.js +28 -0
- package/scripts/test-ner.js +60 -0
- package/scripts/test-stripe-connect.js +304 -0
- package/scripts/test-webhook-secret.sh +24 -0
- package/server.js +3864 -0
- package/storage.rules +22 -0
- package/test-api.json +1 -0
- package/tests/emulator/README.md +38 -0
- package/tests/emulator/counters.emulator.test.js +81 -0
- package/tests/integration/api-account-selfserve.test.js +312 -0
- package/tests/integration/api-admin-digest.test.js +202 -0
- package/tests/integration/api-chat-satisfaction.test.js +259 -0
- package/tests/integration/api-doctor-drafts.test.js +236 -0
- package/tests/integration/api-doctor-inbox.test.js +401 -0
- package/tests/integration/api-org.test.js +328 -0
- package/tests/integration/api-payment.test.js +664 -0
- package/tests/integration/api-provider-settings.test.js +475 -0
- package/tests/integration/api-qr.test.js +121 -0
- package/tests/integration/api-security.test.js +241 -0
- package/tests/integration/api-stripe-search.test.js +303 -0
- package/tests/integration/api-webhook-deletion.test.js +231 -0
- package/tests/mocks/firebase-admin.js +220 -0
- package/tests/unit/analytics.test.js +151 -0
- package/tests/unit/audit-bugs.test.js +203 -0
- package/tests/unit/chat-ui-logic.test.js +283 -0
- package/tests/unit/drafts.test.js +104 -0
- package/tests/unit/feedback.test.js +148 -0
- package/tests/unit/i18n.test.js +229 -0
- package/tests/unit/llm-retry.test.js +122 -0
- package/tests/unit/notifications.test.js +155 -0
- package/tests/unit/orgs.test.js +328 -0
- package/tests/unit/payment.test.js +889 -0
- package/tests/unit/safety-edge-cases.test.js +509 -0
- package/tests/unit/safety-srs-compliance.test.js +252 -0
- package/tests/unit/safety.test.js +291 -0
- package/tests/unit/server-helpers.test.js +774 -0
- package/tests/unit/topics-limits.test.js +158 -0
- package/tests/unit/triage.test.js +152 -0
- package/tests/unit/validate.test.js +408 -0
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
# EvalDoc Technical Architecture
|
|
2
|
+
|
|
3
|
+
## ๐ System Architecture Overview
|
|
4
|
+
|
|
5
|
+
EvalDoc is a full-stack web application built for scalability, reliability, and ease of maintenance in resource-constrained environments.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ๐๏ธ Architecture Diagram
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
13
|
+
โ CLIENT LAYER โ
|
|
14
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
15
|
+
โ Landing Page โ Patient Chat โ Doctor Dashboard โ
|
|
16
|
+
โ (index.html) โ (chat.html) โ (app/index.html) โ
|
|
17
|
+
โ โ โ (app/inbox.html) โ
|
|
18
|
+
โ โ โ (app/analytics.html) โ
|
|
19
|
+
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
|
|
20
|
+
โ โ โ
|
|
21
|
+
โผ โผ โผ
|
|
22
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
23
|
+
โ APPLICATION LAYER โ
|
|
24
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
25
|
+
โ Node.js + Express Server (server.js) โ
|
|
26
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
27
|
+
โ โ Routes: โ โ
|
|
28
|
+
โ โ - /api/provider (Public provider info) โ โ
|
|
29
|
+
โ โ - /api/chat (Patient messaging) โ โ
|
|
30
|
+
โ โ - /api/conversations (Doctor inbox) โ โ
|
|
31
|
+
โ โ - /api/analytics (Platform metrics) โ โ
|
|
32
|
+
โ โ - /api/me (Doctor profile) โ โ
|
|
33
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
34
|
+
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
|
|
35
|
+
โ โ
|
|
36
|
+
โผ โผ
|
|
37
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
38
|
+
โ AI SERVICES โ โ DATABASE LAYER โ
|
|
39
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
40
|
+
โ DeepSeek API (Primary) โ โ Firebase Firestore โ
|
|
41
|
+
โ Google Gemini (Fallback)โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
42
|
+
โ โ โ โ Collections: โ โ
|
|
43
|
+
โ functions/src/llm.js โ โ โ - providers โ โ
|
|
44
|
+
โ โ โ โ - conversations โ โ
|
|
45
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ - messages (sub) โ โ
|
|
46
|
+
โ โ - safetyEvents โ โ
|
|
47
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ - analytics โ โ
|
|
48
|
+
โ AUTHENTICATION โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
49
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ
|
|
50
|
+
โ Firebase Auth โ โ Firebase Admin SDK โ
|
|
51
|
+
โ - Email/Password โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
52
|
+
โ - Token-based โ
|
|
53
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ๐๏ธ File Structure
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
EvalDoc/
|
|
62
|
+
โโโ public/ # Static assets (hosted on Firebase)
|
|
63
|
+
โ โโโ index.html # Landing page
|
|
64
|
+
โ โโโ chat.html # Patient chat interface
|
|
65
|
+
โ โ
|
|
66
|
+
โ โโโ assets/ # Media files
|
|
67
|
+
โ โ โโโ logo.jpg # Brand logo
|
|
68
|
+
โ โ
|
|
69
|
+
โ โโโ css/ # Stylesheets
|
|
70
|
+
โ โ โโโ chat.css # Patient chat styles
|
|
71
|
+
โ โ โโโ styles.css # Landing page styles
|
|
72
|
+
โ โ
|
|
73
|
+
โ โโโ js/ # Client-side scripts
|
|
74
|
+
โ โ โโโ chat.js # Patient chat logic
|
|
75
|
+
โ โ โโโ search.js # Doctor search
|
|
76
|
+
โ โ
|
|
77
|
+
โ โโโ app/ # Doctor dashboard
|
|
78
|
+
โ โโโ index.html # Dashboard home
|
|
79
|
+
โ โโโ inbox.html # Conversation inbox
|
|
80
|
+
โ โโโ analytics.html # Analytics dashboard
|
|
81
|
+
โ โโโ app.css # Dashboard styles
|
|
82
|
+
โ โโโ app.js # Dashboard logic
|
|
83
|
+
โ โโโ inbox.js # Inbox logic
|
|
84
|
+
โ โโโ analytics.js # Analytics logic
|
|
85
|
+
โ โโโ config.js # Firebase configuration
|
|
86
|
+
โ
|
|
87
|
+
โโโ functions/ # Firebase Cloud Functions
|
|
88
|
+
โ โโโ src/
|
|
89
|
+
โ โโโ index.js # Cloud Functions entry
|
|
90
|
+
โ โโโ llm.js # AI integration
|
|
91
|
+
โ โโโ patient-api.js # Patient API handlers
|
|
92
|
+
โ
|
|
93
|
+
โโโ server.js # Local development server
|
|
94
|
+
โโโ firestore.rules # Database security rules
|
|
95
|
+
โโโ firebase.json # Firebase configuration
|
|
96
|
+
โโโ .env # Environment variables
|
|
97
|
+
|
|
98
|
+
Documentation/
|
|
99
|
+
โโโ PLATFORM_OVERVIEW.md # Platform summary
|
|
100
|
+
โโโ DOCTOR_TUTORIAL.md # Doctor user guide
|
|
101
|
+
โโโ PATIENT_GUIDE.md # Patient user guide
|
|
102
|
+
โโโ ARCHITECTURE.md # This file
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## ๐พ Database Schema
|
|
108
|
+
|
|
109
|
+
### Firestore Collections
|
|
110
|
+
|
|
111
|
+
#### 1. **providers**
|
|
112
|
+
Doctor profiles and settings
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
{
|
|
116
|
+
id: "auto-generated",
|
|
117
|
+
ownerId: "firebase-auth-uid",
|
|
118
|
+
handle: "dr-sarah-amina", // Unique URL identifier
|
|
119
|
+
displayName: "Dr. Sarah Amina",
|
|
120
|
+
email: "sarah@example.com",
|
|
121
|
+
specialty: "Family Medicine",
|
|
122
|
+
country: "US",
|
|
123
|
+
locale: "en",
|
|
124
|
+
photoUrl: "https://...",
|
|
125
|
+
logoUrl: "https://...",
|
|
126
|
+
brandPrimaryColor: "#4fb3a4",
|
|
127
|
+
brandSecondaryColor: "#297B56",
|
|
128
|
+
welcomeMessage: "Welcome! How can I help?",
|
|
129
|
+
enabledTopics: [
|
|
130
|
+
"medication_info_safety",
|
|
131
|
+
"general_health_info",
|
|
132
|
+
...
|
|
133
|
+
],
|
|
134
|
+
status: "published", // draft | published | suspended
|
|
135
|
+
monthlyChatCount: 45,
|
|
136
|
+
monthlyChatCountMonth: "2026-01",
|
|
137
|
+
createdAt: Timestamp,
|
|
138
|
+
updatedAt: Timestamp
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### 2. **conversations**
|
|
143
|
+
Chat sessions between patients and providers
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
{
|
|
147
|
+
id: "auto-generated",
|
|
148
|
+
providerId: "provider-doc-id",
|
|
149
|
+
sessionId: "anonymous-session-id", // Patient identifier
|
|
150
|
+
handle: "dr-sarah-amina",
|
|
151
|
+
topic: "general_health_info",
|
|
152
|
+
|
|
153
|
+
// Client info (optional)
|
|
154
|
+
clientName: "John Doe",
|
|
155
|
+
clientEmail: "john@example.com",
|
|
156
|
+
clientPhone: "+256123456789",
|
|
157
|
+
|
|
158
|
+
// Status
|
|
159
|
+
isEscalated: false,
|
|
160
|
+
escalationReason: null, // "red_flag" | null
|
|
161
|
+
|
|
162
|
+
// Message summaries
|
|
163
|
+
lastUserMessage: "What should I do...",
|
|
164
|
+
lastAssistantMessage: "For a fever...",
|
|
165
|
+
lastMessageAt: Timestamp,
|
|
166
|
+
|
|
167
|
+
// Timestamps
|
|
168
|
+
createdAt: Timestamp,
|
|
169
|
+
updatedAt: Timestamp
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### 3. **messages** (subcollection of conversations)
|
|
174
|
+
Individual messages in a conversation
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
conversations/{conversationId}/messages/{messageId}
|
|
178
|
+
{
|
|
179
|
+
id: "auto-generated",
|
|
180
|
+
role: "user", // user | assistant
|
|
181
|
+
content: "What should I do about...",
|
|
182
|
+
safetyFlags: ["pii_detected"], // Array of safety flags
|
|
183
|
+
createdAt: Timestamp
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### 4. **safetyEvents**
|
|
188
|
+
Tracked safety incidents and escalations
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
{
|
|
192
|
+
id: "auto-generated",
|
|
193
|
+
providerId: "provider-doc-id",
|
|
194
|
+
conversationId: "conversation-id",
|
|
195
|
+
eventType: "escalated", // escalated | blocked_input | blocked_output | pii_detected
|
|
196
|
+
details: {
|
|
197
|
+
flags: ["severe_pain", "chest_pain"],
|
|
198
|
+
reason: "red_flag"
|
|
199
|
+
},
|
|
200
|
+
createdAt: Timestamp
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## ๐ API Endpoints
|
|
207
|
+
|
|
208
|
+
### Public Endpoints (No Auth Required)
|
|
209
|
+
|
|
210
|
+
#### `GET /api/provider?handle={handle}`
|
|
211
|
+
Get public provider information
|
|
212
|
+
|
|
213
|
+
**Query Params**:
|
|
214
|
+
- `handle` (required): Doctor's unique handle
|
|
215
|
+
|
|
216
|
+
**Response**:
|
|
217
|
+
```json
|
|
218
|
+
{
|
|
219
|
+
"handle": "dr-sarah-amina",
|
|
220
|
+
"displayName": "Dr. Sarah Amina",
|
|
221
|
+
"specialty": "Family Medicine",
|
|
222
|
+
"welcomeMessage": "Welcome!",
|
|
223
|
+
"brandPrimaryColor": "#4fb3a4",
|
|
224
|
+
"enabledTopics": ["medication_info_safety", ...],
|
|
225
|
+
"status": "published"
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### `POST /api/chat`
|
|
230
|
+
Send patient message and get AI response
|
|
231
|
+
|
|
232
|
+
**Body**:
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"handle": "dr-sarah-amina",
|
|
236
|
+
"sessionId": "anonymous-uuid",
|
|
237
|
+
"message": "What should I do about fever?",
|
|
238
|
+
"topic": "general_health_info",
|
|
239
|
+
"clientName": "John Doe", // Optional
|
|
240
|
+
"clientEmail": "john@email.com", // Optional
|
|
241
|
+
"clientPhone": "+256123456789" // Optional
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Response**:
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"conversationId": "conv-id",
|
|
249
|
+
"response": "For a fever, you should...",
|
|
250
|
+
"escalation": false,
|
|
251
|
+
"safetyFlags": []
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Protected Endpoints (Auth Required)
|
|
256
|
+
|
|
257
|
+
#### `GET /api/me`
|
|
258
|
+
Get current logged-in doctor's profile
|
|
259
|
+
|
|
260
|
+
**Headers**: `Authorization: Bearer {firebase-token}`
|
|
261
|
+
|
|
262
|
+
**Response**: Full provider object
|
|
263
|
+
|
|
264
|
+
#### `GET /api/conversations?limit=100`
|
|
265
|
+
Get all conversations for logged-in doctor
|
|
266
|
+
|
|
267
|
+
**Headers**: `Authorization: Bearer {firebase-token}`
|
|
268
|
+
|
|
269
|
+
**Query Params**:
|
|
270
|
+
- `limit` (optional): Max conversations to return (default: 30, max: 100)
|
|
271
|
+
|
|
272
|
+
**Response**:
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"conversations": [
|
|
276
|
+
{
|
|
277
|
+
"id": "conv-id",
|
|
278
|
+
"sessionId": "session-uuid",
|
|
279
|
+
"clientName": "John Doe",
|
|
280
|
+
"lastUserMessage": "What should...",
|
|
281
|
+
"lastMessageAt": Timestamp,
|
|
282
|
+
"isEscalated": false,
|
|
283
|
+
...
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### `GET /api/conversation/:id`
|
|
290
|
+
Get single conversation with full message history
|
|
291
|
+
|
|
292
|
+
**Headers**: `Authorization: Bearer {firebase-token}`
|
|
293
|
+
|
|
294
|
+
**Response**:
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"id": "conv-id",
|
|
298
|
+
"sessionId": "session-uuid",
|
|
299
|
+
"messages": [
|
|
300
|
+
{
|
|
301
|
+
"role": "user",
|
|
302
|
+
"message": "What should I do?",
|
|
303
|
+
"createdAt": Timestamp
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"role": "assistant",
|
|
307
|
+
"message": "For a fever...",
|
|
308
|
+
"createdAt": Timestamp
|
|
309
|
+
}
|
|
310
|
+
],
|
|
311
|
+
...
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
#### `GET /api/analytics?period=month`
|
|
316
|
+
Get platform-wide analytics
|
|
317
|
+
|
|
318
|
+
**Headers**: `Authorization: Bearer {firebase-token}`
|
|
319
|
+
|
|
320
|
+
**Query Params**:
|
|
321
|
+
- `period` (optional): today | week | month | quarter | all
|
|
322
|
+
|
|
323
|
+
**Response**:
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"summary": {
|
|
327
|
+
"totalDoctors": 15,
|
|
328
|
+
"activeDoctors": 12,
|
|
329
|
+
"totalConversations": 450,
|
|
330
|
+
"uniquePatients": 320
|
|
331
|
+
},
|
|
332
|
+
"doctors": [
|
|
333
|
+
{
|
|
334
|
+
"displayName": "Dr. Sarah",
|
|
335
|
+
"conversationCount": 45,
|
|
336
|
+
"uniquePatients": 32,
|
|
337
|
+
"messageCount": 180
|
|
338
|
+
}
|
|
339
|
+
],
|
|
340
|
+
"period": "month"
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## ๐ค AI Integration
|
|
347
|
+
|
|
348
|
+
### LLM Service (`functions/src/llm.js`)
|
|
349
|
+
|
|
350
|
+
#### AI Provider Priority
|
|
351
|
+
1. **DeepSeek** (Primary) - Better medical accuracy
|
|
352
|
+
2. **Google Gemini** (Fallback) - Backup if DeepSeek fails
|
|
353
|
+
3. **Generic Response** - If both fail
|
|
354
|
+
|
|
355
|
+
#### Function: `generateResponse()`
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
async function generateResponse({ topicConfig, message, provider }) {
|
|
359
|
+
// 1. Try DeepSeek
|
|
360
|
+
try {
|
|
361
|
+
return await callDeepSeek({ topicConfig, message, provider });
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error('DeepSeek failed:', error);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// 2. Fallback to Gemini
|
|
367
|
+
try {
|
|
368
|
+
return await callGemini({ topicConfig, message, provider });
|
|
369
|
+
} catch (error) {
|
|
370
|
+
console.error('Gemini failed:', error);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 3. Generic fallback
|
|
374
|
+
return genericResponse(topicConfig);
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### Safety Features
|
|
379
|
+
|
|
380
|
+
**Input Analysis**:
|
|
381
|
+
- PII detection (emails, phone numbers, addresses)
|
|
382
|
+
- Red flag keywords (chest pain, severe bleeding, etc.)
|
|
383
|
+
- Escalation triggers
|
|
384
|
+
|
|
385
|
+
**Output Analysis**:
|
|
386
|
+
- Medical advice blocking
|
|
387
|
+
- Diagnosis blocking
|
|
388
|
+
- Prescription blocking
|
|
389
|
+
- Dosing recommendations blocking
|
|
390
|
+
|
|
391
|
+
**Red Flag Keywords**:
|
|
392
|
+
```javascript
|
|
393
|
+
const RED_FLAGS = [
|
|
394
|
+
'chest pain', 'difficulty breathing', 'severe bleeding',
|
|
395
|
+
'loss of consciousness', 'suicidal', 'kill myself',
|
|
396
|
+
'severe pain', 'can\'t breathe', 'heart attack'
|
|
397
|
+
];
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## ๐ Security
|
|
403
|
+
|
|
404
|
+
### Authentication Flow
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
1. Doctor signs up/in
|
|
408
|
+
โ
|
|
409
|
+
2. Firebase Auth creates user
|
|
410
|
+
โ
|
|
411
|
+
3. Frontend gets ID token
|
|
412
|
+
โ
|
|
413
|
+
4. Token sent in Authorization header
|
|
414
|
+
โ
|
|
415
|
+
5. Backend verifies token
|
|
416
|
+
โ
|
|
417
|
+
6. Request proceeds if valid
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Firestore Security Rules
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
423
|
+
rules_version = '2';
|
|
424
|
+
service cloud.firestore {
|
|
425
|
+
match /databases/{database}/documents {
|
|
426
|
+
|
|
427
|
+
// Helper functions
|
|
428
|
+
function isSignedIn() {
|
|
429
|
+
return request.auth != null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function isOwner(uid) {
|
|
433
|
+
return isSignedIn() && request.auth.uid == uid;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Providers collection
|
|
437
|
+
match /providers/{providerId} {
|
|
438
|
+
allow read: if true; // Public read
|
|
439
|
+
allow create: if isSignedIn();
|
|
440
|
+
allow update, delete: if isOwner(resource.data.ownerId);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Conversations collection
|
|
444
|
+
match /conversations/{conversationId} {
|
|
445
|
+
allow read: if isSignedIn(); // Doctors can read all
|
|
446
|
+
allow create: if true; // Anyone can create (patients)
|
|
447
|
+
allow update, delete: if false; // No direct updates
|
|
448
|
+
|
|
449
|
+
// Messages subcollection
|
|
450
|
+
match /messages/{messageId} {
|
|
451
|
+
allow read: if isSignedIn();
|
|
452
|
+
allow create: if true;
|
|
453
|
+
allow update, delete: if false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Safety events (admin only)
|
|
458
|
+
match /safetyEvents/{eventId} {
|
|
459
|
+
allow read: if isSignedIn();
|
|
460
|
+
allow create: if true;
|
|
461
|
+
allow update, delete: if false;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Data Protection
|
|
468
|
+
|
|
469
|
+
1. **PII Redaction**: Automatically removes sensitive info from logs
|
|
470
|
+
2. **Encrypted Storage**: All Firestore data encrypted at rest
|
|
471
|
+
3. **Token Validation**: Every protected request validates Firebase token
|
|
472
|
+
4. **Rate Limiting**: Monthly chat limits per provider
|
|
473
|
+
5. **Session Management**: Anonymous sessions for patient privacy
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## ๐ Deployment
|
|
478
|
+
|
|
479
|
+
### Local Development
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
# 1. Install dependencies
|
|
483
|
+
npm install
|
|
484
|
+
|
|
485
|
+
# 2. Set environment variables
|
|
486
|
+
cp .env.example .env
|
|
487
|
+
# Edit .env with your API keys
|
|
488
|
+
|
|
489
|
+
# 3. Start development server
|
|
490
|
+
npm run dev
|
|
491
|
+
# Server runs on http://localhost:8080
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Environment Variables
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
# .env file
|
|
498
|
+
DEEPSEEK_API_KEY=your_deepseek_key
|
|
499
|
+
GEMINI_API_KEY=your_gemini_key
|
|
500
|
+
FIREBASE_SERVICE_ACCOUNT=path/to/service-account.json
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Production Deployment
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
# 1. Build and deploy to Firebase
|
|
507
|
+
firebase deploy
|
|
508
|
+
|
|
509
|
+
# This deploys:
|
|
510
|
+
# - Hosting (static files in public/)
|
|
511
|
+
# - Cloud Functions (functions/src/index.js)
|
|
512
|
+
# - Firestore rules (firestore.rules)
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Hosting Configuration (`firebase.json`)
|
|
516
|
+
|
|
517
|
+
```json
|
|
518
|
+
{
|
|
519
|
+
"hosting": {
|
|
520
|
+
"public": "public",
|
|
521
|
+
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
|
|
522
|
+
"rewrites": [
|
|
523
|
+
{
|
|
524
|
+
"source": "**",
|
|
525
|
+
"function": "api"
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
},
|
|
529
|
+
"functions": {
|
|
530
|
+
"source": "functions"
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## ๐ Data Flow
|
|
538
|
+
|
|
539
|
+
### Patient Chat Flow
|
|
540
|
+
|
|
541
|
+
```
|
|
542
|
+
1. Patient opens doctor's unique link
|
|
543
|
+
โ GET /api/provider?handle=dr-sarah-amina
|
|
544
|
+
|
|
545
|
+
2. Page loads with doctor's branding and topics
|
|
546
|
+
|
|
547
|
+
3. Patient selects topic and types message
|
|
548
|
+
|
|
549
|
+
4. Frontend sends POST /api/chat
|
|
550
|
+
{
|
|
551
|
+
handle: "dr-sarah-amina",
|
|
552
|
+
sessionId: "anon-uuid",
|
|
553
|
+
message: "What should I do about fever?",
|
|
554
|
+
topic: "general_health_info"
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
5. Backend processes:
|
|
558
|
+
a. Validates provider exists and is published
|
|
559
|
+
b. Checks monthly usage limits
|
|
560
|
+
c. Analyzes message for safety (PII, red flags)
|
|
561
|
+
d. Saves user message to Firestore
|
|
562
|
+
e. Calls AI (DeepSeek โ Gemini fallback)
|
|
563
|
+
f. Analyzes AI response for safety
|
|
564
|
+
g. Saves AI response to Firestore
|
|
565
|
+
h. Returns response to patient
|
|
566
|
+
|
|
567
|
+
6. Patient sees AI response instantly
|
|
568
|
+
|
|
569
|
+
7. If escalated:
|
|
570
|
+
a. Safety event logged
|
|
571
|
+
b. Conversation marked as escalated
|
|
572
|
+
c. Doctor sees alert in inbox
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Doctor Inbox Flow
|
|
576
|
+
|
|
577
|
+
```
|
|
578
|
+
1. Doctor signs in
|
|
579
|
+
โ Firebase Auth validates
|
|
580
|
+
|
|
581
|
+
2. Opens inbox
|
|
582
|
+
โ GET /api/conversations
|
|
583
|
+
|
|
584
|
+
3. Backend returns:
|
|
585
|
+
- All conversations for this doctor
|
|
586
|
+
- Sorted by last message time
|
|
587
|
+
- With escalation flags
|
|
588
|
+
|
|
589
|
+
4. Doctor clicks conversation
|
|
590
|
+
โ GET /api/conversation/:id
|
|
591
|
+
|
|
592
|
+
5. Backend returns:
|
|
593
|
+
- Full conversation details
|
|
594
|
+
- All messages (user + AI)
|
|
595
|
+
- Patient contact info if provided
|
|
596
|
+
|
|
597
|
+
6. Doctor reviews and can reply (coming soon)
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## ๐จ Frontend Architecture
|
|
603
|
+
|
|
604
|
+
### Tech Stack
|
|
605
|
+
- **Vanilla JavaScript**: No frameworks, fast loading
|
|
606
|
+
- **CSS3**: Modern styling with CSS Grid and Flexbox
|
|
607
|
+
- **Firebase SDK**: Client-side auth and real-time updates
|
|
608
|
+
|
|
609
|
+
### Key Components
|
|
610
|
+
|
|
611
|
+
#### Patient Chat (`public/chat.html` + `public/js/chat.js`)
|
|
612
|
+
- Topic selection dropdown
|
|
613
|
+
- Message composer
|
|
614
|
+
- Chat message display
|
|
615
|
+
- Session management
|
|
616
|
+
- AI response rendering
|
|
617
|
+
|
|
618
|
+
#### Doctor Dashboard (`public/app/index.html` + `public/app/app.js`)
|
|
619
|
+
- Authentication UI
|
|
620
|
+
- Profile onboarding
|
|
621
|
+
- Topic configuration
|
|
622
|
+
- Branding customization
|
|
623
|
+
- Link sharing tools
|
|
624
|
+
|
|
625
|
+
#### Doctor Inbox (`public/app/inbox.html` + `public/app/inbox.js`)
|
|
626
|
+
- Conversation list with filters
|
|
627
|
+
- Message history viewer
|
|
628
|
+
- Patient contact display
|
|
629
|
+
- Escalation alerts
|
|
630
|
+
- Reply interface (coming soon)
|
|
631
|
+
|
|
632
|
+
#### Analytics (`public/app/analytics.html` + `public/app/analytics.js`)
|
|
633
|
+
- Summary statistics cards
|
|
634
|
+
- Doctor performance table
|
|
635
|
+
- Time period filtering
|
|
636
|
+
- Data visualization
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## ๐ง Configuration
|
|
641
|
+
|
|
642
|
+
### Topics Configuration
|
|
643
|
+
|
|
644
|
+
Topics are defined in server code and can be enabled/disabled per doctor:
|
|
645
|
+
|
|
646
|
+
```javascript
|
|
647
|
+
const TOPICS = {
|
|
648
|
+
medication_info_safety: {
|
|
649
|
+
name: "Medication Information & Safety",
|
|
650
|
+
systemPrompt: "You are a helpful medical assistant...",
|
|
651
|
+
disclaimer: "This is not medical advice...",
|
|
652
|
+
redFlags: ["chest pain", "difficulty breathing", ...]
|
|
653
|
+
},
|
|
654
|
+
general_health_info: {
|
|
655
|
+
name: "General Health Information",
|
|
656
|
+
...
|
|
657
|
+
},
|
|
658
|
+
...
|
|
659
|
+
};
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### AI Model Configuration
|
|
663
|
+
|
|
664
|
+
```javascript
|
|
665
|
+
// DeepSeek Configuration
|
|
666
|
+
{
|
|
667
|
+
apiKey: process.env.DEEPSEEK_API_KEY,
|
|
668
|
+
model: 'deepseek-chat',
|
|
669
|
+
temperature: 0.7,
|
|
670
|
+
maxTokens: 800
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Gemini Configuration
|
|
674
|
+
{
|
|
675
|
+
apiKey: process.env.GEMINI_API_KEY,
|
|
676
|
+
model: 'gemini-1.5-flash',
|
|
677
|
+
temperature: 0.7,
|
|
678
|
+
maxOutputTokens: 800
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## ๐ Scalability Considerations
|
|
685
|
+
|
|
686
|
+
### Current Limits
|
|
687
|
+
- **Monthly chats per doctor**: Configurable (default: 1000)
|
|
688
|
+
- **Message history**: 100 messages per conversation
|
|
689
|
+
- **Concurrent users**: Limited by Firebase Spark plan
|
|
690
|
+
|
|
691
|
+
### Scaling Strategy
|
|
692
|
+
1. **Horizontal Scaling**: Firebase auto-scales Cloud Functions
|
|
693
|
+
2. **Database Sharding**: Firestore automatically distributes data
|
|
694
|
+
3. **CDN**: Static assets served via Firebase CDN
|
|
695
|
+
4. **Caching**: Implement Redis for frequently accessed data
|
|
696
|
+
5. **Load Balancing**: Firebase handles automatically
|
|
697
|
+
|
|
698
|
+
### Performance Optimizations
|
|
699
|
+
- Lazy loading of conversation messages
|
|
700
|
+
- Pagination for large datasets
|
|
701
|
+
- Debounced search inputs
|
|
702
|
+
- Optimistic UI updates
|
|
703
|
+
- Service worker for offline support (future)
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## ๐งช Testing Strategy
|
|
708
|
+
|
|
709
|
+
### Manual Testing Checklist
|
|
710
|
+
- [ ] Patient can open doctor link
|
|
711
|
+
- [ ] Chat interface loads correctly
|
|
712
|
+
- [ ] AI responds to messages
|
|
713
|
+
- [ ] Messages saved to database
|
|
714
|
+
- [ ] Doctor inbox shows conversations
|
|
715
|
+
- [ ] Escalations flagged correctly
|
|
716
|
+
- [ ] Analytics display accurately
|
|
717
|
+
|
|
718
|
+
### Future Automated Testing
|
|
719
|
+
- Unit tests for API endpoints
|
|
720
|
+
- Integration tests for AI service
|
|
721
|
+
- E2E tests for critical user flows
|
|
722
|
+
- Load testing for scalability
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## ๐ Monitoring & Logging
|
|
727
|
+
|
|
728
|
+
### Current Logging
|
|
729
|
+
- Console logs in server.js
|
|
730
|
+
- Firebase Functions logs
|
|
731
|
+
- Client-side error tracking (future)
|
|
732
|
+
|
|
733
|
+
### Key Metrics to Track
|
|
734
|
+
- Response time (API latency)
|
|
735
|
+
- AI success/failure rates
|
|
736
|
+
- Escalation frequency
|
|
737
|
+
- User engagement (messages per session)
|
|
738
|
+
- Doctor response times
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
## ๐ฎ Future Architecture Plans
|
|
743
|
+
|
|
744
|
+
### Planned Enhancements
|
|
745
|
+
|
|
746
|
+
1. **Real-time Updates**: WebSocket for live inbox refresh
|
|
747
|
+
2. **Push Notifications**: FCM for doctor alerts
|
|
748
|
+
3. **Payment Integration**: Stripe for subscriptions
|
|
749
|
+
4. **Advanced Analytics**: BigQuery for complex queries
|
|
750
|
+
5. **Multi-language**: i18n support
|
|
751
|
+
6. **Microservices**: Separate AI service
|
|
752
|
+
7. **CDN Optimization**: Cloudflare integration
|
|
753
|
+
8. **Monitoring**: Sentry for error tracking
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## ๐ Related Documentation
|
|
758
|
+
|
|
759
|
+
- [PLATFORM_OVERVIEW.md](./PLATFORM_OVERVIEW.md) - High-level platform description
|
|
760
|
+
- [DOCTOR_TUTORIAL.md](./DOCTOR_TUTORIAL.md) - Doctor user guide
|
|
761
|
+
- [PATIENT_GUIDE.md](./PATIENT_GUIDE.md) - Patient user guide
|
|
762
|
+
- [Firebase Documentation](https://firebase.google.com/docs)
|
|
763
|
+
- [DeepSeek API Docs](https://platform.deepseek.com/docs)
|
|
764
|
+
- [Gemini API Docs](https://ai.google.dev/docs)
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
*Last Updated: January 2026*
|
|
769
|
+
*Version: 1.0*
|