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.
Files changed (139) hide show
  1. package/.env.staging.example +19 -0
  2. package/.firebaserc +6 -0
  3. package/.github/workflows/auto-merge-to-main.yml +28 -0
  4. package/.github/workflows/ci.yml +27 -0
  5. package/.github/workflows/npxhub-publish.yml +170 -0
  6. package/.prettierignore +4 -0
  7. package/.prettierrc.json +7 -0
  8. package/README.md +142 -0
  9. package/SRS.md +448 -0
  10. package/apphosting.staging.yaml +48 -0
  11. package/apphosting.yaml +50 -0
  12. package/bin/evaldoc.cjs +105 -0
  13. package/cors.json +8 -0
  14. package/docs/ARCHITECTURE.md +769 -0
  15. package/docs/ARCHITECTURE_SUMMARY.md +323 -0
  16. package/docs/DEPLOYMENT.md +86 -0
  17. package/docs/DEPLOYMENT_STEPS.md +373 -0
  18. package/docs/DEPLOY_FIRESTORE_RULES.md +239 -0
  19. package/docs/DEPLOY_STORAGE_RULES.md +82 -0
  20. package/docs/DOCTOR_TUTORIAL.md +467 -0
  21. package/docs/FIREBASE_STORAGE_CORS_FIX.md +131 -0
  22. package/docs/FIXES_APPLIED.md +128 -0
  23. package/docs/IMPLEMENTATION.md +498 -0
  24. package/docs/IMPLEMENTATION_COMPLETE.md +317 -0
  25. package/docs/LLM-SETUP.md +216 -0
  26. package/docs/MANUAL_TEST_GUIDE.md +327 -0
  27. package/docs/PATIENT_GUIDE.md +451 -0
  28. package/docs/PLATFORM_OVERVIEW.md +194 -0
  29. package/docs/QUICKSTART.md +252 -0
  30. package/docs/QUICK_REFERENCE.md +222 -0
  31. package/docs/READY_TO_TEST.md +383 -0
  32. package/docs/RUN.md +237 -0
  33. package/docs/START_TESTING.md +130 -0
  34. package/docs/STRIPE_CONNECT_SETUP.md +454 -0
  35. package/docs/SYSTEM_READY.md +345 -0
  36. package/docs/THREADS_IMPLEMENTATION_COMPLETE.md +431 -0
  37. package/docs/THREAD_IMPLEMENTATION_GUIDE.md +345 -0
  38. package/docs/firebasefiles.md +21 -0
  39. package/docs/homepage.md +1208 -0
  40. package/docs/payments.md +159 -0
  41. package/eslint.config.js +76 -0
  42. package/firebase.json +27 -0
  43. package/firestore.indexes.json +88 -0
  44. package/firestore.rules +125 -0
  45. package/functions/package-lock.json +2884 -0
  46. package/functions/package.json +20 -0
  47. package/functions/src/analytics.js +101 -0
  48. package/functions/src/audit.js +28 -0
  49. package/functions/src/auth.js +19 -0
  50. package/functions/src/drafts.js +128 -0
  51. package/functions/src/feedback.js +164 -0
  52. package/functions/src/firebase-init.js +29 -0
  53. package/functions/src/i18n.js +134 -0
  54. package/functions/src/limits.js +27 -0
  55. package/functions/src/llm.js +271 -0
  56. package/functions/src/ner.js +162 -0
  57. package/functions/src/notifications.js +273 -0
  58. package/functions/src/orgs.js +127 -0
  59. package/functions/src/patient-api.js +545 -0
  60. package/functions/src/payment.js +830 -0
  61. package/functions/src/safety.js +188 -0
  62. package/functions/src/stripe-config.js +33 -0
  63. package/functions/src/topics.js +94 -0
  64. package/functions/src/triage.js +191 -0
  65. package/functions/src/utils.js +28 -0
  66. package/functions/src/validate.js +177 -0
  67. package/functions/test-firebase.js +36 -0
  68. package/jest.config.js +18 -0
  69. package/package.json +52 -0
  70. package/public/404.html +93 -0
  71. package/public/app/analytics.html +336 -0
  72. package/public/app/analytics.js +177 -0
  73. package/public/app/app.css +1400 -0
  74. package/public/app/app.js +1754 -0
  75. package/public/app/config.js +14 -0
  76. package/public/app/inbox-threads.js +843 -0
  77. package/public/app/inbox.html +598 -0
  78. package/public/app/inbox.js +397 -0
  79. package/public/app/index.html +612 -0
  80. package/public/assets/logo.jpg +0 -0
  81. package/public/chat.html +137 -0
  82. package/public/css/chat.css +870 -0
  83. package/public/css/landing-enhance.css +298 -0
  84. package/public/css/styles.css +1198 -0
  85. package/public/favicon.svg +5 -0
  86. package/public/find-doctor.html +220 -0
  87. package/public/index.html +399 -0
  88. package/public/js/chat-threads.js +513 -0
  89. package/public/js/chat.js +832 -0
  90. package/public/js/search.js +41 -0
  91. package/public/privacy.html +101 -0
  92. package/public/robots.txt +6 -0
  93. package/public/site.webmanifest +12 -0
  94. package/public/terms.html +110 -0
  95. package/scripts/create-test-provider.js +55 -0
  96. package/scripts/deploy-staging.sh +51 -0
  97. package/scripts/fix-provider.js +39 -0
  98. package/scripts/quick-test.sh +37 -0
  99. package/scripts/test-chat.sh +54 -0
  100. package/scripts/test-multi-turn.js +137 -0
  101. package/scripts/test-ner-simple.js +28 -0
  102. package/scripts/test-ner.js +60 -0
  103. package/scripts/test-stripe-connect.js +304 -0
  104. package/scripts/test-webhook-secret.sh +24 -0
  105. package/server.js +3864 -0
  106. package/storage.rules +22 -0
  107. package/test-api.json +1 -0
  108. package/tests/emulator/README.md +38 -0
  109. package/tests/emulator/counters.emulator.test.js +81 -0
  110. package/tests/integration/api-account-selfserve.test.js +312 -0
  111. package/tests/integration/api-admin-digest.test.js +202 -0
  112. package/tests/integration/api-chat-satisfaction.test.js +259 -0
  113. package/tests/integration/api-doctor-drafts.test.js +236 -0
  114. package/tests/integration/api-doctor-inbox.test.js +401 -0
  115. package/tests/integration/api-org.test.js +328 -0
  116. package/tests/integration/api-payment.test.js +664 -0
  117. package/tests/integration/api-provider-settings.test.js +475 -0
  118. package/tests/integration/api-qr.test.js +121 -0
  119. package/tests/integration/api-security.test.js +241 -0
  120. package/tests/integration/api-stripe-search.test.js +303 -0
  121. package/tests/integration/api-webhook-deletion.test.js +231 -0
  122. package/tests/mocks/firebase-admin.js +220 -0
  123. package/tests/unit/analytics.test.js +151 -0
  124. package/tests/unit/audit-bugs.test.js +203 -0
  125. package/tests/unit/chat-ui-logic.test.js +283 -0
  126. package/tests/unit/drafts.test.js +104 -0
  127. package/tests/unit/feedback.test.js +148 -0
  128. package/tests/unit/i18n.test.js +229 -0
  129. package/tests/unit/llm-retry.test.js +122 -0
  130. package/tests/unit/notifications.test.js +155 -0
  131. package/tests/unit/orgs.test.js +328 -0
  132. package/tests/unit/payment.test.js +889 -0
  133. package/tests/unit/safety-edge-cases.test.js +509 -0
  134. package/tests/unit/safety-srs-compliance.test.js +252 -0
  135. package/tests/unit/safety.test.js +291 -0
  136. package/tests/unit/server-helpers.test.js +774 -0
  137. package/tests/unit/topics-limits.test.js +158 -0
  138. package/tests/unit/triage.test.js +152 -0
  139. package/tests/unit/validate.test.js +408 -0
@@ -0,0 +1,323 @@
1
+ # EvalDoc Thread-Based Architecture
2
+
3
+ ## System Overview
4
+
5
+ ```
6
+ ┌─────────────────────────────────────────────────────────────┐
7
+ │ PATIENT EXPERIENCE │
8
+ └─────────────────────────────────────────────────────────────┘
9
+
10
+ Patient clicks → evaldoc.com/dr-john-cardiology
11
+ ↓
12
+ Prompted to "Continue with Google"
13
+ ↓
14
+ Signs in with Google account
15
+ ↓
16
+ Thread created: thread_googleuid_drjohn
17
+ ↓
18
+ Patient sends message → AI responds
19
+ ↓
20
+ Conversation persists forever (accessible anytime)
21
+
22
+
23
+ ┌─────────────────────────────────────────────────────────────┐
24
+ │ DOCTOR EXPERIENCE │
25
+ └─────────────────────────────────────────────────────────────┘
26
+
27
+ Doctor logs into dashboard
28
+ ↓
29
+ Sees inbox with all threads
30
+ ↓
31
+ Threads grouped by patient (not sessionId)
32
+ ↓
33
+ Can view conversation history
34
+ ↓
35
+ Can reply manually (overrides AI)
36
+ ↓
37
+ Gets notifications for new messages
38
+ ```
39
+
40
+ ## Data Flow
41
+
42
+ ```
43
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
44
+ │ Patient │ ◄─────► │ Thread │ ◄─────► │ Doctor │
45
+ │ (Google) │ │ │ │(Provider)│
46
+ └──────────┘ └──────────┘ └──────────┘
47
+ │ │ │
48
+ ├── email ├── patientId ├── handle
49
+ ├── name ├── doctorId ├── displayName
50
+ ├── photo ├── status ├── specialty
51
+ ├── doctorIds[] ├── messages[] ├── pricingModel
52
+ └── fcmToken └── unreadCounts └── stripeAccount
53
+ ```
54
+
55
+ ## Collections Structure
56
+
57
+ ```
58
+ Firestore
59
+ ├── patients/{patientId}
60
+ │ └── Profile data (email, name, photo)
61
+ │
62
+ ├── providers/{doctorId}
63
+ │ └── Doctor profile (existing)
64
+ │
65
+ └── threads/{thread_patientId_doctorId}
66
+ ├── Thread metadata
67
+ └── messages (subcollection)
68
+ └── {messageId}
69
+ ├── role: patient | doctor | ai
70
+ ├── message: "..."
71
+ ├── createdAt
72
+ └── readStatus
73
+ ```
74
+
75
+ ## Authentication Flow
76
+
77
+ ```
78
+ ┌──────────────────┐
79
+ │ Firebase Auth │
80
+ └────────┬─────────┘
81
+ │
82
+ ┌────────▼─────────┐
83
+ │ Google Sign-In │
84
+ └────────┬─────────┘
85
+ │
86
+ ┌────────────────┴────────────────┐
87
+ │ │
88
+ ┌───────▼────────┐ ┌────────▼───────┐
89
+ │ Patient Token │ │ Doctor Token │
90
+ │ (uid) │ │ (custom claim) │
91
+ └───────┬────────┘ └────────┬───────┘
92
+ │ │
93
+ ┌───────▼────────┐ ┌────────▼───────┐
94
+ │ Read own │ │ Read doctor │
95
+ │ threads │ │ threads │
96
+ └────────────────┘ └────────────────┘
97
+ ```
98
+
99
+ ## API Endpoints
100
+
101
+ ### Patient APIs (NEW)
102
+ ```
103
+ POST /api/patient/create
104
+ → Create patient profile on first sign-in
105
+
106
+ POST /api/patient/thread
107
+ → Get or create thread with doctor
108
+ Body: { doctorHandle: "dr-john-cardiology" }
109
+
110
+ GET /api/patient/threads
111
+ → Get all threads for this patient
112
+
113
+ POST /api/patient/message
114
+ → Send message to doctor
115
+ Body: { threadId, message, topic }
116
+ Response: { response, escalation }
117
+
118
+ GET /api/patient/thread/:id/messages
119
+ → Load conversation history
120
+ ```
121
+
122
+ ### Doctor APIs (UPDATED)
123
+ ```
124
+ GET /api/doctor/threads
125
+ → Get all threads (patients)
126
+
127
+ GET /api/doctor/thread/:id
128
+ → View specific conversation
129
+
130
+ POST /api/doctor/message
131
+ → Manual reply to patient
132
+ Body: { threadId, message, override }
133
+ ```
134
+
135
+ ## Key Features
136
+
137
+ ### ✅ Implemented
138
+ - Google Sign-In authentication
139
+ - Thread-based conversations
140
+ - Persistent message history
141
+ - AI-powered responses
142
+ - Safety filters & escalation
143
+ - Firestore security rules
144
+ - Payment integration ready
145
+
146
+ ### 🚧 Pending (Phase 2)
147
+ - Doctor inbox UI update
148
+ - Doctor manual reply UI
149
+ - Web push notifications
150
+ - Real-time message updates
151
+ - Thread search & filters
152
+ - Patient contact info display
153
+
154
+ ### 📋 Future Enhancements
155
+ - Multi-language support
156
+ - Voice messages
157
+ - Image attachments
158
+ - Video consultations
159
+ - Appointment scheduling
160
+ - Prescription handling
161
+
162
+ ## Billing Model
163
+
164
+ ```
165
+ Per-Chat Pricing
166
+ ├── Patient sends first message
167
+ ├── Payment required before AI responds
168
+ ├── Thread marked as "paid"
169
+ └── Unlimited messages in thread
170
+
171
+ Subscription Pricing
172
+ ├── Patient pays monthly
173
+ ├── Unlimited threads
174
+ └── Unlimited messages
175
+
176
+ Free Model
177
+ └── No payment required
178
+ ```
179
+
180
+ ## Security Model
181
+
182
+ ```
183
+ Firestore Rules
184
+ ├── patients/{id}
185
+ │ └── Only patient can read/update own profile
186
+ │
187
+ ├── threads/{id}
188
+ │ └── Patient OR doctor can read
189
+ │ └── Only backend can write
190
+ │
191
+ └── threads/{id}/messages/{msgId}
192
+ └── Same as parent thread
193
+ └── Only backend can write
194
+ ```
195
+
196
+ ## Advantages Over Previous System
197
+
198
+ | Feature | Old (sessionId) | New (Threads) |
199
+ |---------|----------------|---------------|
200
+ | **Identity** | Anonymous session | Google account |
201
+ | **Cross-device** | ❌ Lost on new device | ✅ Works everywhere |
202
+ | **History** | ❌ Lost if cleared | ✅ Persistent forever |
203
+ | **Multiple doctors** | ❌ Messy | ✅ Clean separation |
204
+ | **Doctor inbox** | ❌ Shows sessionIds | ✅ Shows patient names |
205
+ | **Notifications** | ❌ Not possible | ✅ Push notifications |
206
+ | **Billing** | Per conversation | Per thread (cleaner) |
207
+
208
+ ## Migration Path
209
+
210
+ ```
211
+ Phase 1: Core (COMPLETED) ✅
212
+ ├── Patient authentication
213
+ ├── Thread creation
214
+ ├── Message sending
215
+ ├── API endpoints
216
+ └── Security rules
217
+
218
+ Phase 2: Doctor UI (PENDING)
219
+ ├── Update inbox to show threads
220
+ ├── Add manual reply capability
221
+ ├── Show patient profiles
222
+ └── Add thread management
223
+
224
+ Phase 3: Enhancements (FUTURE)
225
+ ├── Web push notifications
226
+ ├── Real-time updates
227
+ ├── Advanced search
228
+ └── Analytics dashboard
229
+ ```
230
+
231
+ ## Performance & Scale
232
+
233
+ **Reads per chat session:**
234
+ - Load provider: 1 read
235
+ - Load thread: 1 read
236
+ - Load messages: N reads (50 max)
237
+ - **Total: ~52 reads**
238
+
239
+ **Writes per message:**
240
+ - Patient message: 3 writes (message + thread + patient)
241
+ - AI response: 2 writes (message + thread)
242
+ - **Total: 5 writes per exchange**
243
+
244
+ **Estimated costs (1000 users, 10 msgs each/month):**
245
+ - Writes: 50,000 × $0.18/100k = **$0.09**
246
+ - Reads: 100,000 × $0.06/100k = **$0.06**
247
+ - **Total: ~$0.15/month** (very cheap!)
248
+
249
+ ## Firestore Indexes Required
250
+
251
+ ```bash
252
+ # Create these in Firebase Console
253
+ threads
254
+ - (patientId, lastMessageAt DESC)
255
+ - (doctorId, lastMessageAt DESC)
256
+ - (doctorId, status, lastMessageAt DESC)
257
+
258
+ messages
259
+ - (threadId, createdAt ASC)
260
+ ```
261
+
262
+ ## Testing Scenarios
263
+
264
+ 1. **New patient flow:**
265
+ - Visit doctor link → Sign in → Send message → Get response
266
+
267
+ 2. **Returning patient:**
268
+ - Visit doctor link → Already signed in → See history → Continue chat
269
+
270
+ 3. **Multiple doctors:**
271
+ - Patient talks to Dr. A → Separate thread
272
+ - Patient talks to Dr. B → New thread
273
+ - Both conversations independent
274
+
275
+ 4. **Doctor view:**
276
+ - Doctor logs in → Sees all patients
277
+ - Clicks patient → Sees full conversation
278
+ - Can reply manually
279
+
280
+ ## Quick Start Commands
281
+
282
+ ```bash
283
+ # Deploy security rules
284
+ firebase deploy --only firestore:rules
285
+
286
+ # Deploy functions
287
+ firebase deploy --only functions
288
+
289
+ # Deploy hosting
290
+ firebase deploy --only hosting
291
+
292
+ # Test locally
293
+ firebase emulators:start
294
+ ```
295
+
296
+ ## Support & Debugging
297
+
298
+ **Common issues:**
299
+
300
+ 1. **"Unauthorized" error**
301
+ - Check Firebase Auth is enabled
302
+ - Verify token is sent in header
303
+
304
+ 2. **Messages not saving**
305
+ - Check Firestore rules deployed
306
+ - Verify API endpoint integration
307
+
308
+ 3. **Google Sign-In fails**
309
+ - Check authorized domains in Firebase
310
+ - Verify API keys configured
311
+
312
+ **Debug checklist:**
313
+ - [ ] Firebase Console → Authentication → Google enabled
314
+ - [ ] Firestore rules deployed
315
+ - [ ] Functions deployed
316
+ - [ ] `/app/config.js` has correct Firebase config
317
+ - [ ] Browser console shows no errors
318
+
319
+ ---
320
+
321
+ **Status**: Phase 1 Complete ✅
322
+ **Next Steps**: Update doctor inbox UI
323
+ **Timeline**: Ready for testing
@@ -0,0 +1,86 @@
1
+ # Firebase Deployment Guide
2
+
3
+ ## Prerequisites
4
+
5
+ Make sure you have:
6
+ - Firebase CLI installed (`npm install -g firebase-tools`)
7
+ - Logged in to Firebase (`firebase login`)
8
+ - Your API keys ready (Gemini and DeepSeek)
9
+
10
+ ## Step 1: Set Environment Variables (Secrets)
11
+
12
+ Run these commands to configure your API keys:
13
+
14
+ ```bash
15
+ # Set Gemini API Key (required)
16
+ firebase functions:secrets:set GEMINI_API_KEY
17
+
18
+ # Set DeepSeek API Key (optional fallback)
19
+ firebase functions:secrets:set DEEPSEEK_API_KEY
20
+ ```
21
+
22
+ When prompted, paste your API key values.
23
+
24
+ ## Step 2: Install Dependencies
25
+
26
+ ```bash
27
+ cd functions
28
+ npm install
29
+ cd ..
30
+ ```
31
+
32
+ ## Step 3: Deploy to Firebase
33
+
34
+ Deploy everything (Hosting + Functions + Firestore rules):
35
+
36
+ ```bash
37
+ firebase deploy
38
+ ```
39
+
40
+ Or deploy individually:
41
+
42
+ ```bash
43
+ # Deploy only Cloud Functions
44
+ firebase deploy --only functions
45
+
46
+ # Deploy only Hosting
47
+ firebase deploy --only hosting
48
+
49
+ # Deploy only Firestore rules
50
+ firebase deploy --only firestore:rules
51
+ ```
52
+
53
+ ## Configuration Files
54
+
55
+ ### apphosting.yaml
56
+ Defines runtime configuration and environment variables for Firebase App Hosting.
57
+ - Sets runtime resources (CPU, memory, instances)
58
+ - References secrets (GEMINI_API_KEY, DEEPSEEK_API_KEY)
59
+
60
+ ### functions/src/index.js
61
+ The Cloud Function is configured to use secrets via:
62
+ ```javascript
63
+ exports.api = functions
64
+ .runWith({
65
+ secrets: ['GEMINI_API_KEY', 'DEEPSEEK_API_KEY']
66
+ })
67
+ .https.onRequest(async (req, res) => { ... });
68
+ ```
69
+
70
+ ## Current Status
71
+ - Production URL: https://evaldoc--evaldocplatform.us-east4.hosted.app/
72
+ - Functions endpoint: https://us-central1-evaldocplatform.cloudfunctions.net/api
73
+
74
+ ## Troubleshooting
75
+
76
+ ### If functions fail to deploy:
77
+ ```bash
78
+ # Check Firebase logs
79
+ firebase functions:log
80
+
81
+ # Check if secrets are set
82
+ firebase functions:secrets:access GEMINI_API_KEY
83
+ ```
84
+
85
+ ### If secrets are not accessible:
86
+ Make sure you've set them using `firebase functions:secrets:set` and that your functions code includes them in `runWith({ secrets: [...] })`