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,137 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
+ <title>Safe Health Chat · EvalDoc</title>
7
+ <meta name="description" content="Ask general health questions in a safe, private, topic-based chat with your provider. No diagnosis, no dosing — safety first." />
8
+ <meta name="theme-color" content="#0e1a14" />
9
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
10
+ <link rel="apple-touch-icon" href="/favicon.svg" />
11
+ <link rel="manifest" href="/site.webmanifest" />
12
+ <meta property="og:type" content="website" />
13
+ <meta property="og:title" content="Safe Health Chat · EvalDoc" />
14
+ <meta property="og:description" content="A safe, private, topic-based health chat with your provider." />
15
+ <meta name="twitter:card" content="summary" />
16
+ <meta name="robots" content="noindex" />
17
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
18
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
19
+ <link
20
+ href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap"
21
+ rel="stylesheet"
22
+ />
23
+ <link rel="stylesheet" href="/css/chat.css" />
24
+ <script src="https://js.stripe.com/v3/"></script>
25
+ <!-- Google tag (gtag.js) -->
26
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-NPWYSPFSVG"></script>
27
+ <script>
28
+ window.dataLayer = window.dataLayer || [];
29
+ function gtag(){dataLayer.push(arguments);}
30
+ gtag("js", new Date());
31
+
32
+ gtag("config", "G-NPWYSPFSVG");
33
+ </script>
34
+ </head>
35
+ <body>
36
+ <a href="#messages" class="skip-link">Skip to chat</a>
37
+ <div class="background"></div>
38
+
39
+ <!-- Screen-reader live region for new messages -->
40
+ <div id="srAnnouncer" class="sr-only" aria-live="assertive" aria-atomic="true"></div>
41
+
42
+ <!-- Payment Modal -->
43
+ <div id="paymentModal" class="payment-modal" style="display: none;" role="dialog" aria-modal="true" aria-labelledby="paymentTitle">
44
+ <div class="payment-modal-content">
45
+ <h2 id="paymentTitle">Payment Required</h2>
46
+ <p id="paymentDescription">Please complete payment to continue chatting.</p>
47
+ <div id="paymentForm">
48
+ <div id="card-element"></div>
49
+ <div id="card-errors" role="alert"></div>
50
+ <button id="paymentSubmitBtn" class="payment-submit-btn">Pay Now</button>
51
+ <button id="paymentCancelBtn" class="payment-cancel-btn">Cancel</button>
52
+ </div>
53
+ <div id="paymentProcessing" style="display: none; text-align: center;">
54
+ <p>Processing payment...</p>
55
+ </div>
56
+ <div id="paymentSuccess" style="display: none; text-align: center;">
57
+ <p>✓ Payment successful!</p>
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <main class="page" role="main">
63
+ <header class="header">
64
+ <div>
65
+ <p class="eyebrow">EvalDoc Link-First</p>
66
+ <h1 class="title" id="providerName">Provider</h1>
67
+ <p class="subtitle" id="providerMeta">Safe, topic-based chat</p>
68
+ </div>
69
+ <div class="brand" id="brandBlock">
70
+ <img src="/assets/logo.jpg" alt="Logo" id="brandLogo" class="logo-img" />
71
+ </div>
72
+ </header>
73
+
74
+ <div class="emergency-banner" id="emergencyBanner" role="note" aria-label="Emergency guidance">
75
+ ⚠️ <strong>Emergency?</strong> Call <a href="tel:911" id="emergencyNumber">911</a> or your local emergency number. This chat is not a substitute for emergency care.
76
+ </div>
77
+
78
+ <section class="info" id="welcomeCard">
79
+ <div class="provider-details" id="providerDetails" style="display:none;">
80
+ <span class="provider-status" id="providerStatus"></span>
81
+ <span class="provider-hours" id="providerHours"></span>
82
+ </div>
83
+ <p class="welcome" id="welcomeMessage">Welcome. Choose a topic to get started.</p>
84
+ <div class="badges" role="list" aria-label="Safety guarantees">
85
+ <span class="badge" role="listitem">No diagnosis</span>
86
+ <span class="badge" role="listitem">No dosing</span>
87
+ <span class="badge" role="listitem">Safety first</span>
88
+ </div>
89
+ <div class="provider-contact-info" id="providerContactInfo" style="display:none;" aria-label="Provider contact information"></div>
90
+ </section>
91
+
92
+ <section class="chat" aria-label="Chat conversation">
93
+ <div class="chat-header">
94
+ <label for="topicSelect">Topic</label>
95
+ <select id="topicSelect" aria-label="Select a conversation topic"></select>
96
+ <span id="autoDetectedTopic" class="auto-detected-topic" style="display:none" aria-live="polite"></span>
97
+ </div>
98
+
99
+ <div class="messages" id="messages" role="log" aria-live="polite" aria-label="Chat messages"></div>
100
+ <div class="suggestions" id="suggestions" aria-label="Suggested questions"></div>
101
+ <div class="composer" role="form" aria-label="Send a message">
102
+ <textarea
103
+ id="messageInput"
104
+ rows="1"
105
+ placeholder="Ask a question… (Enter to send, Shift+Enter for a new line)"
106
+ autocomplete="off"
107
+ maxlength="5000"
108
+ aria-label="Type your message"
109
+ ></textarea>
110
+ <button id="sendBtn" aria-label="Send message">Send</button>
111
+ </div>
112
+ <div id="charCounter" style="text-align:right;font-size:0.75rem;color:#999;padding:0 1rem;display:none;" aria-live="polite"></div>
113
+ <div class="rating hidden" id="ratingPanel" aria-label="Rate this response">
114
+ <span>Was this helpful?</span>
115
+ <span class="rating-scale-label" aria-hidden="true">Not helpful</span>
116
+ <div class="rating-buttons" role="group" aria-label="Rating from 1 (not helpful) to 5 (very helpful)">
117
+ <button data-rating="1" type="button" aria-label="Rate 1 out of 5, not helpful">1</button>
118
+ <button data-rating="2" type="button" aria-label="Rate 2 out of 5">2</button>
119
+ <button data-rating="3" type="button" aria-label="Rate 3 out of 5">3</button>
120
+ <button data-rating="4" type="button" aria-label="Rate 4 out of 5">4</button>
121
+ <button data-rating="5" type="button" aria-label="Rate 5 out of 5, very helpful">5</button>
122
+ </div>
123
+ <span class="rating-scale-label" aria-hidden="true">Very helpful</span>
124
+ </div>
125
+ <p class="disclaimer" id="topicDisclaimer">This is not medical advice. For urgent concerns, contact local emergency services.</p>
126
+ <div class="privacy-notice" id="privacyNotice">
127
+ <small>Your conversation is anonymous and logged for quality purposes. No personal health data is stored without redaction.</small>
128
+ </div>
129
+ <p class="disclaimer legal-links">
130
+ <a href="/privacy.html" style="color:#999;font-size:0.75rem;">Privacy</a> · <a href="/terms.html" style="color:#999;font-size:0.75rem;">Terms</a> · <a href="mailto:helpme@evaldoctor.ai" style="color:#999;font-size:0.75rem;">Help</a>
131
+ </p>
132
+ </section>
133
+ </main>
134
+
135
+ <script src="/js/chat.js?v=4"></script>
136
+ </body>
137
+ </html>