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,373 @@
|
|
|
1
|
+
# EvalDoc Thread System - Deployment Steps
|
|
2
|
+
|
|
3
|
+
## ✅ What's Been Implemented
|
|
4
|
+
|
|
5
|
+
### Frontend
|
|
6
|
+
- ✅ [public/chat.html](public/chat.html) - Updated with Google Sign-In modal and Firebase Auth scripts
|
|
7
|
+
- ✅ [public/js/chat-threads.js](public/js/chat-threads.js) - NEW: Thread-based chat system with Google authentication
|
|
8
|
+
- ✅ [public/app/inbox.html](public/app/inbox.html) - Updated with doctor reply styling
|
|
9
|
+
- ✅ [public/app/inbox-threads.js](public/app/inbox-threads.js) - NEW: Thread-based inbox with manual reply feature
|
|
10
|
+
|
|
11
|
+
### Backend
|
|
12
|
+
- ✅ [functions/src/patient-api.js](functions/src/patient-api.js) - NEW: Patient API handlers
|
|
13
|
+
- ✅ [functions/src/index.js](functions/src/index.js) - Updated with patient and doctor thread endpoints
|
|
14
|
+
|
|
15
|
+
### Security
|
|
16
|
+
- ✅ [firestore.rules](firestore.rules) - Updated with patients and threads collection rules
|
|
17
|
+
|
|
18
|
+
### Documentation
|
|
19
|
+
- ✅ [THREAD_IMPLEMENTATION_GUIDE.md](THREAD_IMPLEMENTATION_GUIDE.md) - Complete implementation guide
|
|
20
|
+
- ✅ [ARCHITECTURE_SUMMARY.md](ARCHITECTURE_SUMMARY.md) - Architecture overview
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🚀 Deployment Checklist
|
|
25
|
+
|
|
26
|
+
### Step 1: Enable Google Sign-In (5 minutes)
|
|
27
|
+
|
|
28
|
+
1. Go to [Firebase Console](https://console.firebase.google.com)
|
|
29
|
+
2. Select your project
|
|
30
|
+
3. Go to **Authentication** → **Sign-in method**
|
|
31
|
+
4. Click **Google** and enable it
|
|
32
|
+
5. Add authorized domains:
|
|
33
|
+
- `localhost` (for testing)
|
|
34
|
+
- Your production domain (e.g., `evaldoc.com`)
|
|
35
|
+
6. Click **Save**
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### Step 2: Deploy Firestore Rules (1 minute)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# From your project root
|
|
43
|
+
firebase deploy --only firestore:rules
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Expected output:**
|
|
47
|
+
```
|
|
48
|
+
✔ Deploy complete!
|
|
49
|
+
✔ firestore: deployed database security rules
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### Step 3: Deploy Firebase Functions (5 minutes)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Make sure you're in the project root
|
|
58
|
+
cd functions
|
|
59
|
+
npm install # Install any new dependencies
|
|
60
|
+
cd ..
|
|
61
|
+
|
|
62
|
+
# Deploy functions
|
|
63
|
+
firebase deploy --only functions
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Expected output:**
|
|
67
|
+
```
|
|
68
|
+
✔ Deploy complete!
|
|
69
|
+
✔ functions[api]: Successful update operation
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Note:** First deployment may take 5-10 minutes. Subsequent deploys are faster.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### Step 4: Deploy Hosting (1 minute)
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
firebase deploy --only hosting
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Expected output:**
|
|
83
|
+
```
|
|
84
|
+
✔ Deploy complete!
|
|
85
|
+
✔ hosting: deployed new version
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### Step 5: Verify Deployment (2 minutes)
|
|
91
|
+
|
|
92
|
+
#### Test Patient Flow:
|
|
93
|
+
|
|
94
|
+
1. Go to your deployed URL: `https://your-domain.com/dr-john-cardiology` (replace with actual doctor handle)
|
|
95
|
+
2. Should see the chat interface
|
|
96
|
+
3. Try sending a message
|
|
97
|
+
4. Should see "Sign in to continue" modal
|
|
98
|
+
5. Click "Continue with Google"
|
|
99
|
+
6. Sign in with Google account
|
|
100
|
+
7. Message should send successfully
|
|
101
|
+
8. AI should respond
|
|
102
|
+
9. **Refresh the page** - conversation should persist!
|
|
103
|
+
|
|
104
|
+
#### Test Doctor Inbox:
|
|
105
|
+
|
|
106
|
+
1. Go to `https://your-domain.com/app`
|
|
107
|
+
2. Sign in as doctor (provider account)
|
|
108
|
+
3. Go to "Inbox" tab
|
|
109
|
+
4. Should see threads instead of old conversations
|
|
110
|
+
5. Click on a thread
|
|
111
|
+
6. Should see patient name/email
|
|
112
|
+
7. Type a reply and click "Send Reply"
|
|
113
|
+
8. Message should appear in thread
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🧪 Testing Scenarios
|
|
118
|
+
|
|
119
|
+
### Scenario 1: New Patient
|
|
120
|
+
```
|
|
121
|
+
1. Clear browser data (to simulate new patient)
|
|
122
|
+
2. Visit doctor link
|
|
123
|
+
3. Send message → Should prompt for Google Sign-In
|
|
124
|
+
4. Sign in with Google
|
|
125
|
+
5. Message should send + AI responds
|
|
126
|
+
6. Refresh page → Should see conversation history
|
|
127
|
+
7. Send another message → Should continue thread
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Scenario 2: Returning Patient
|
|
131
|
+
```
|
|
132
|
+
1. Visit doctor link (already signed in)
|
|
133
|
+
2. Should immediately see chat interface with history
|
|
134
|
+
3. Send message → AI responds
|
|
135
|
+
4. Conversation continues in same thread
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Scenario 3: Patient with Multiple Doctors
|
|
139
|
+
```
|
|
140
|
+
1. Patient chats with Dr. A
|
|
141
|
+
2. Patient visits Dr. B's link
|
|
142
|
+
3. New thread created for Dr. B
|
|
143
|
+
4. Both conversations are separate
|
|
144
|
+
5. Patient can switch between doctors
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Scenario 4: Doctor Manual Reply
|
|
148
|
+
```
|
|
149
|
+
1. Doctor logs into inbox
|
|
150
|
+
2. Sees patient thread with unread indicator (green dot)
|
|
151
|
+
3. Clicks on thread
|
|
152
|
+
4. Types reply in text box
|
|
153
|
+
5. Clicks "Send Reply"
|
|
154
|
+
6. Message appears in thread
|
|
155
|
+
7. Patient receives message (doctor's name shown)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Scenario 5: Doctor Takes Over (Manual Mode)
|
|
159
|
+
```
|
|
160
|
+
1. Doctor clicks "👨⚕️ Take Over (Manual Mode)" button
|
|
161
|
+
2. Thread marked as manual mode
|
|
162
|
+
3. AI stops responding
|
|
163
|
+
4. All messages from doctor are manual
|
|
164
|
+
5. Doctor can toggle back to AI mode
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 📋 Post-Deployment Verification
|
|
170
|
+
|
|
171
|
+
### Check Firebase Console
|
|
172
|
+
|
|
173
|
+
1. **Authentication:**
|
|
174
|
+
- Go to Authentication → Users
|
|
175
|
+
- Should see new users signing in via Google
|
|
176
|
+
|
|
177
|
+
2. **Firestore:**
|
|
178
|
+
- Go to Firestore Database
|
|
179
|
+
- Should see new collections:
|
|
180
|
+
- `patients` - Patient profiles
|
|
181
|
+
- `threads` - Conversation threads
|
|
182
|
+
- Inside threads: `messages` subcollection
|
|
183
|
+
|
|
184
|
+
3. **Functions:**
|
|
185
|
+
- Go to Functions → Dashboard
|
|
186
|
+
- Check `/api/patient/*` endpoints are deployed
|
|
187
|
+
- Check logs for any errors
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 🐛 Troubleshooting
|
|
192
|
+
|
|
193
|
+
### Issue: "Unauthorized" error when sending message
|
|
194
|
+
|
|
195
|
+
**Fix:**
|
|
196
|
+
1. Check Firebase Auth is enabled for Google
|
|
197
|
+
2. Verify token is being sent: Open browser DevTools → Network → Check request headers for `Authorization: Bearer ...`
|
|
198
|
+
3. Re-deploy Firestore rules: `firebase deploy --only firestore:rules`
|
|
199
|
+
|
|
200
|
+
### Issue: "Thread not found" error
|
|
201
|
+
|
|
202
|
+
**Fix:**
|
|
203
|
+
1. Check Firestore Database has `threads` collection
|
|
204
|
+
2. Verify thread ID format: `thread_{patientId}_{doctorId}`
|
|
205
|
+
3. Check Firebase console for error logs
|
|
206
|
+
|
|
207
|
+
### Issue: Google Sign-In popup blocked
|
|
208
|
+
|
|
209
|
+
**Fix:**
|
|
210
|
+
1. Check browser isn't blocking popups
|
|
211
|
+
2. Add domain to Firebase Console → Authentication → Authorized domains
|
|
212
|
+
3. Clear browser cache
|
|
213
|
+
|
|
214
|
+
### Issue: Messages not showing in doctor inbox
|
|
215
|
+
|
|
216
|
+
**Fix:**
|
|
217
|
+
1. Verify doctor is using [inbox-threads.js](public/app/inbox-threads.js) (not old inbox.js)
|
|
218
|
+
2. Check API endpoint: `/api/doctor/threads` is working
|
|
219
|
+
3. Check browser console for errors
|
|
220
|
+
|
|
221
|
+
### Issue: Payment not working with threads
|
|
222
|
+
|
|
223
|
+
**Fix:**
|
|
224
|
+
1. Thread-based payment integration is in [chat-threads.js](public/js/chat-threads.js)
|
|
225
|
+
2. Verify Stripe keys are configured
|
|
226
|
+
3. Check `thread.isPaid` status in Firestore
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 🔄 Rollback Plan (If Needed)
|
|
231
|
+
|
|
232
|
+
If something goes wrong, you can quickly rollback:
|
|
233
|
+
|
|
234
|
+
### Rollback Frontend:
|
|
235
|
+
```bash
|
|
236
|
+
# In public/chat.html, change:
|
|
237
|
+
<script src="/js/chat-threads.js?v=1"></script>
|
|
238
|
+
# Back to:
|
|
239
|
+
<script src="/js/chat.js?v=3"></script>
|
|
240
|
+
|
|
241
|
+
# In public/app/inbox.html, change:
|
|
242
|
+
<script src="/app/inbox-threads.js"></script>
|
|
243
|
+
# Back to:
|
|
244
|
+
<script src="/app/inbox.js"></script>
|
|
245
|
+
|
|
246
|
+
# Deploy:
|
|
247
|
+
firebase deploy --only hosting
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Rollback Functions:
|
|
251
|
+
```bash
|
|
252
|
+
# Comment out patient API routes in functions/src/index.js:
|
|
253
|
+
// if (req.path.startsWith("/patient/")) {
|
|
254
|
+
// const user = await requireAuth(req, res);
|
|
255
|
+
// if (!user) return;
|
|
256
|
+
// await handlePatientAPI(req, res, user);
|
|
257
|
+
// return;
|
|
258
|
+
// }
|
|
259
|
+
|
|
260
|
+
firebase deploy --only functions
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Note:** Old conversations in `conversations` collection are unaffected. They'll still work with old system.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 📊 Monitoring & Analytics
|
|
268
|
+
|
|
269
|
+
### Key Metrics to Watch:
|
|
270
|
+
|
|
271
|
+
1. **Patient Sign-Ups:**
|
|
272
|
+
- Firebase Console → Authentication → Users
|
|
273
|
+
- Should see growth over time
|
|
274
|
+
|
|
275
|
+
2. **Thread Creation Rate:**
|
|
276
|
+
- Firestore → `threads` collection
|
|
277
|
+
- Count of new documents
|
|
278
|
+
|
|
279
|
+
3. **Message Volume:**
|
|
280
|
+
- Firestore → `threads/{id}/messages`
|
|
281
|
+
- Average messages per thread
|
|
282
|
+
|
|
283
|
+
4. **Doctor Response Time:**
|
|
284
|
+
- Check `lastMessageAt` timestamps
|
|
285
|
+
- Time between patient message and doctor reply
|
|
286
|
+
|
|
287
|
+
5. **API Performance:**
|
|
288
|
+
- Functions → Dashboard → Metrics
|
|
289
|
+
- Check latency and error rates
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 🎯 Success Criteria
|
|
294
|
+
|
|
295
|
+
You'll know deployment is successful when:
|
|
296
|
+
|
|
297
|
+
- ✅ Patients can sign in with Google
|
|
298
|
+
- ✅ Messages persist after browser refresh
|
|
299
|
+
- ✅ Doctor inbox shows patient names (not sessionIds)
|
|
300
|
+
- ✅ Doctor can send manual replies
|
|
301
|
+
- ✅ Manual mode (override AI) works
|
|
302
|
+
- ✅ No errors in Firebase Functions logs
|
|
303
|
+
- ✅ No errors in browser console
|
|
304
|
+
- ✅ Multiple patients can chat with same doctor
|
|
305
|
+
- ✅ Single patient can chat with multiple doctors
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 📞 Next Steps After Deployment
|
|
310
|
+
|
|
311
|
+
### Phase 3: Web Push Notifications (Future)
|
|
312
|
+
|
|
313
|
+
Once everything is stable, implement push notifications:
|
|
314
|
+
|
|
315
|
+
1. Add FCM (Firebase Cloud Messaging) to frontend
|
|
316
|
+
2. Request notification permission from patients
|
|
317
|
+
3. Save FCM token to patient profile
|
|
318
|
+
4. Send push notification when doctor replies
|
|
319
|
+
|
|
320
|
+
See [THREAD_IMPLEMENTATION_GUIDE.md](THREAD_IMPLEMENTATION_GUIDE.md#phase-4-web-push-notifications) for details.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 🔐 Security Reminders
|
|
325
|
+
|
|
326
|
+
- ✅ Patient data is private (only they can access)
|
|
327
|
+
- ✅ Doctors can only see their own threads
|
|
328
|
+
- ✅ All writes go through authenticated backend
|
|
329
|
+
- ✅ Firestore rules enforce access control
|
|
330
|
+
- ✅ Google Sign-In tokens are verified server-side
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 📝 Deployment Log Template
|
|
335
|
+
|
|
336
|
+
Use this to track your deployment:
|
|
337
|
+
|
|
338
|
+
```
|
|
339
|
+
Date: _____________
|
|
340
|
+
Deployed by: _____________
|
|
341
|
+
|
|
342
|
+
Step 1: Google Sign-In Enabled ✅ / ❌
|
|
343
|
+
Step 2: Firestore Rules Deployed ✅ / ❌
|
|
344
|
+
Step 3: Functions Deployed ✅ / ❌
|
|
345
|
+
Step 4: Hosting Deployed ✅ / ❌
|
|
346
|
+
Step 5: Testing Complete ✅ / ❌
|
|
347
|
+
|
|
348
|
+
Test Results:
|
|
349
|
+
- New patient flow: ✅ / ❌
|
|
350
|
+
- Returning patient: ✅ / ❌
|
|
351
|
+
- Doctor inbox: ✅ / ❌
|
|
352
|
+
- Manual reply: ✅ / ❌
|
|
353
|
+
|
|
354
|
+
Issues Encountered:
|
|
355
|
+
__________________________________________
|
|
356
|
+
__________________________________________
|
|
357
|
+
|
|
358
|
+
Notes:
|
|
359
|
+
__________________________________________
|
|
360
|
+
__________________________________________
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 🎉 You're Ready!
|
|
366
|
+
|
|
367
|
+
Follow the steps above and you'll have the thread-based system live in under 15 minutes!
|
|
368
|
+
|
|
369
|
+
**Need help?** Check:
|
|
370
|
+
1. [THREAD_IMPLEMENTATION_GUIDE.md](THREAD_IMPLEMENTATION_GUIDE.md)
|
|
371
|
+
2. [ARCHITECTURE_SUMMARY.md](ARCHITECTURE_SUMMARY.md)
|
|
372
|
+
3. Firebase Console logs
|
|
373
|
+
4. Browser developer console
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Deploy Firestore Security Rules Manually
|
|
2
|
+
|
|
3
|
+
## The Issue
|
|
4
|
+
Firebase CLI is broken, so we need to deploy Firestore rules manually through the Firebase Console.
|
|
5
|
+
|
|
6
|
+
## Quick Fix - Update Firestore Rules in Firebase Console
|
|
7
|
+
|
|
8
|
+
### Step 1: Go to Firebase Console
|
|
9
|
+
1. Open https://console.firebase.google.com/
|
|
10
|
+
2. Select project: **evaldocplatform**
|
|
11
|
+
3. Click **Firestore Database** in the left sidebar
|
|
12
|
+
4. Click the **Rules** tab
|
|
13
|
+
|
|
14
|
+
### Step 2: Copy and Paste These Rules
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
rules_version = '2';
|
|
18
|
+
service cloud.firestore {
|
|
19
|
+
match /databases/{database}/documents {
|
|
20
|
+
function isSignedIn() {
|
|
21
|
+
return request.auth != null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isOwner(ownerUid) {
|
|
25
|
+
return isSignedIn() && request.auth.uid == ownerUid;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Provider documents
|
|
29
|
+
match /providers/{providerId} {
|
|
30
|
+
// Public: Anyone can read published providers
|
|
31
|
+
allow read: if resource.data.status == "published";
|
|
32
|
+
|
|
33
|
+
// Providers can only be created via backend API (Admin SDK)
|
|
34
|
+
allow create: if false;
|
|
35
|
+
|
|
36
|
+
// Providers can update their own profile
|
|
37
|
+
allow update: if isOwner(resource.data.ownerUid);
|
|
38
|
+
|
|
39
|
+
// Only backend can delete
|
|
40
|
+
allow delete: if false;
|
|
41
|
+
|
|
42
|
+
// Analytics subcollection
|
|
43
|
+
match /analyticsDaily/{dayId} {
|
|
44
|
+
allow read: if isOwner(providerId);
|
|
45
|
+
allow write: if false; // Only backend can write analytics
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Handle lookup (used to check if handle is taken)
|
|
50
|
+
match /handles/{handle} {
|
|
51
|
+
allow read: if true; // Anyone can check if handle exists
|
|
52
|
+
allow write: if false; // Only backend can manage handles
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Conversations (chat data)
|
|
56
|
+
match /conversations/{conversationId} {
|
|
57
|
+
// Only backend API can manage conversations
|
|
58
|
+
allow read, write: if false;
|
|
59
|
+
|
|
60
|
+
match /messages/{messageId} {
|
|
61
|
+
allow read, write: if false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Safety events (for monitoring)
|
|
66
|
+
match /safetyEvents/{eventId} {
|
|
67
|
+
allow read, write: if false; // Only backend
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Platform configuration
|
|
71
|
+
match /platformConfig/{docId} {
|
|
72
|
+
allow read: if true; // Public config can be read
|
|
73
|
+
allow write: if false; // Only backend can write
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Payment-related collections
|
|
77
|
+
match /subscriptions/{subscriptionId} {
|
|
78
|
+
allow read: if isSignedIn(); // Users can read their subscriptions
|
|
79
|
+
allow write: if false; // Only backend manages subscriptions
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
match /transactions/{transactionId} {
|
|
83
|
+
allow read: if isSignedIn(); // Users can read their transactions
|
|
84
|
+
allow write: if false; // Only backend manages transactions
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Step 3: Publish the Rules
|
|
91
|
+
1. Click the **Publish** button in the Firebase Console
|
|
92
|
+
2. Wait for confirmation that rules were published
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## What These Rules Do
|
|
97
|
+
|
|
98
|
+
### ✅ Provider Management
|
|
99
|
+
- **Read**: Anyone can read published providers (for patient search)
|
|
100
|
+
- **Create**: Blocked on client (must use backend API)
|
|
101
|
+
- **Update**: Providers can update their own profile
|
|
102
|
+
- **Delete**: Only backend can delete
|
|
103
|
+
|
|
104
|
+
### ✅ Handles Collection
|
|
105
|
+
- **Read**: Public (to check if handle is available)
|
|
106
|
+
- **Write**: Backend only
|
|
107
|
+
|
|
108
|
+
### ✅ Conversations & Messages
|
|
109
|
+
- **All access**: Backend only (sensitive medical data)
|
|
110
|
+
|
|
111
|
+
### ✅ Payment Collections
|
|
112
|
+
- **Read**: Authenticated users can read their own data
|
|
113
|
+
- **Write**: Backend only (Stripe webhooks)
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Security Architecture
|
|
118
|
+
|
|
119
|
+
This is a **backend-first architecture**:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Frontend → Backend API → Firebase Admin SDK → Firestore
|
|
123
|
+
↓
|
|
124
|
+
(bypasses security rules)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Why this is secure:**
|
|
128
|
+
1. ✅ All writes go through authenticated API endpoints
|
|
129
|
+
2. ✅ API validates data before writing
|
|
130
|
+
3. ✅ Admin SDK bypasses Firestore rules (backend has full access)
|
|
131
|
+
4. ✅ Client-side direct writes are blocked
|
|
132
|
+
5. ✅ Only necessary reads are allowed from client
|
|
133
|
+
|
|
134
|
+
**What the frontend can do directly:**
|
|
135
|
+
- ✅ Read published provider profiles
|
|
136
|
+
- ✅ Check if handles are available
|
|
137
|
+
- ✅ Read public platform config
|
|
138
|
+
- ✅ Read their own subscriptions/transactions
|
|
139
|
+
|
|
140
|
+
**What requires backend API:**
|
|
141
|
+
- ✅ Create provider profiles
|
|
142
|
+
- ✅ Update provider data
|
|
143
|
+
- ✅ Manage conversations
|
|
144
|
+
- ✅ Process payments
|
|
145
|
+
- ✅ Write analytics
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Testing After Deployment
|
|
150
|
+
|
|
151
|
+
### Test 1: Public Provider Read
|
|
152
|
+
```javascript
|
|
153
|
+
// In browser console at http://localhost:8080
|
|
154
|
+
firebase.firestore()
|
|
155
|
+
.collection('providers')
|
|
156
|
+
.where('status', '==', 'published')
|
|
157
|
+
.limit(1)
|
|
158
|
+
.get()
|
|
159
|
+
.then(snap => console.log('✅ Can read published providers'))
|
|
160
|
+
.catch(err => console.error('❌ Error:', err));
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Test 2: Handle Availability Check
|
|
164
|
+
```javascript
|
|
165
|
+
// Check if handle is available
|
|
166
|
+
firebase.firestore()
|
|
167
|
+
.collection('handles')
|
|
168
|
+
.doc('test-doctor')
|
|
169
|
+
.get()
|
|
170
|
+
.then(doc => console.log('✅ Can check handles'))
|
|
171
|
+
.catch(err => console.error('❌ Error:', err));
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Test 3: Direct Create (Should Fail)
|
|
175
|
+
```javascript
|
|
176
|
+
// This should be blocked
|
|
177
|
+
firebase.firestore()
|
|
178
|
+
.collection('providers')
|
|
179
|
+
.add({ test: true })
|
|
180
|
+
.then(() => console.error('❌ Security rules not working!'))
|
|
181
|
+
.catch(err => console.log('✅ Direct create blocked:', err.code));
|
|
182
|
+
// Expected: permission-denied
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Common Issues
|
|
188
|
+
|
|
189
|
+
### "Missing or insufficient permissions"
|
|
190
|
+
✅ **This is expected** for operations that must go through the backend API
|
|
191
|
+
- Provider creation
|
|
192
|
+
- Conversation management
|
|
193
|
+
- Payment processing
|
|
194
|
+
|
|
195
|
+
Use the API endpoints instead:
|
|
196
|
+
- `POST /api/provider` - Create provider
|
|
197
|
+
- `POST /api/provider/update` - Update provider
|
|
198
|
+
- `POST /api/payment/update-pricing` - Update pricing
|
|
199
|
+
|
|
200
|
+
### Rules not taking effect
|
|
201
|
+
1. Clear browser cache
|
|
202
|
+
2. Sign out and sign back in
|
|
203
|
+
3. Wait 1-2 minutes for rules to propagate
|
|
204
|
+
4. Check Firebase Console shows the new rules
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Verify Rules Are Active
|
|
209
|
+
|
|
210
|
+
After publishing, check the Firebase Console:
|
|
211
|
+
1. Go to **Firestore Database** → **Rules**
|
|
212
|
+
2. Verify the rules match what you pasted
|
|
213
|
+
3. Check "Last updated" timestamp is recent
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Production Considerations
|
|
218
|
+
|
|
219
|
+
### Current Rules (Development-Friendly)
|
|
220
|
+
✅ Public can read published providers
|
|
221
|
+
✅ Public can check handle availability
|
|
222
|
+
✅ Authenticated users can read config
|
|
223
|
+
|
|
224
|
+
### For Production Hardening
|
|
225
|
+
Consider adding:
|
|
226
|
+
- Rate limiting (via Firebase App Check)
|
|
227
|
+
- Geolocation restrictions
|
|
228
|
+
- More granular provider update rules
|
|
229
|
+
- Audit logging for sensitive operations
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Status
|
|
234
|
+
|
|
235
|
+
✅ **Rules Created**: firestore.rules file updated
|
|
236
|
+
⚠️ **Rules Deployed**: Manual deployment needed
|
|
237
|
+
📋 **Next Step**: Copy rules to Firebase Console and publish
|
|
238
|
+
|
|
239
|
+
**Deploy now**: https://console.firebase.google.com/project/evaldocplatform/firestore/rules
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Deploy Firebase Storage Rules Manually
|
|
2
|
+
|
|
3
|
+
## The Issue
|
|
4
|
+
Firebase CLI is broken, so we need to deploy storage rules manually through the Firebase Console.
|
|
5
|
+
|
|
6
|
+
## Quick Fix - Update Storage Rules in Firebase Console
|
|
7
|
+
|
|
8
|
+
### Step 1: Go to Firebase Console
|
|
9
|
+
1. Open https://console.firebase.google.com/
|
|
10
|
+
2. Select project: **evaldocplatform**
|
|
11
|
+
3. Click **Storage** in the left sidebar
|
|
12
|
+
4. Click the **Rules** tab
|
|
13
|
+
|
|
14
|
+
### Step 2: Copy and Paste These Rules
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
rules_version = '2';
|
|
18
|
+
service firebase.storage {
|
|
19
|
+
match /b/{bucket}/o {
|
|
20
|
+
|
|
21
|
+
// Doctor certificates - allow authenticated users to upload their own
|
|
22
|
+
match /certificates/{userId}/{allPaths=**} {
|
|
23
|
+
// Users can only upload their own certificates
|
|
24
|
+
allow write: if request.auth != null
|
|
25
|
+
&& request.auth.uid == userId
|
|
26
|
+
&& request.resource.size < 10 * 1024 * 1024; // 10MB max
|
|
27
|
+
|
|
28
|
+
// Authenticated users can read (for admin verification)
|
|
29
|
+
allow read: if request.auth != null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Fallback for development - allow authenticated users
|
|
33
|
+
match /{allPaths=**} {
|
|
34
|
+
allow read, write: if request.auth != null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Step 3: Publish the Rules
|
|
41
|
+
1. Click the **Publish** button in the Firebase Console
|
|
42
|
+
2. Wait for confirmation that rules were published
|
|
43
|
+
|
|
44
|
+
### Step 4: Test Upload Again
|
|
45
|
+
1. Go back to http://localhost:8080/app
|
|
46
|
+
2. Try uploading a certificate again
|
|
47
|
+
3. Should work now!
|
|
48
|
+
|
|
49
|
+
## What These Rules Do
|
|
50
|
+
|
|
51
|
+
✅ **Allow authenticated users to upload to their own folder**
|
|
52
|
+
- Path: `certificates/{userId}/filename.pdf`
|
|
53
|
+
- User can only write to their own `userId` folder
|
|
54
|
+
- Max file size: 10MB
|
|
55
|
+
|
|
56
|
+
✅ **Allow authenticated users to read certificates**
|
|
57
|
+
- Needed for admin verification
|
|
58
|
+
|
|
59
|
+
✅ **Development fallback**
|
|
60
|
+
- Any authenticated user can read/write anywhere
|
|
61
|
+
- This is permissive for development - tighten for production
|
|
62
|
+
|
|
63
|
+
## Production Rules (Future)
|
|
64
|
+
|
|
65
|
+
For production, replace the fallback with explicit deny:
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
match /{allPaths=**} {
|
|
69
|
+
allow read, write: if false; // Deny all other access
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Verify Rules Are Active
|
|
74
|
+
|
|
75
|
+
After publishing, the upload error should change from:
|
|
76
|
+
- ❌ `storage/unauthorized` → ✅ Upload succeeds
|
|
77
|
+
|
|
78
|
+
If you still get permission errors:
|
|
79
|
+
1. Make sure you're logged in (check Firebase Auth)
|
|
80
|
+
2. Verify the userId in the path matches your auth.uid
|
|
81
|
+
3. Check file size is under 10MB
|
|
82
|
+
4. Clear browser cache and try again
|