@talkpilot/core-db 1.3.38 → 1.3.39

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 (233) hide show
  1. package/.cursor/rules/development.mdc +65 -65
  2. package/DEVELOPMENT.md +141 -141
  3. package/README.md +721 -721
  4. package/dist/talkpilot/clientsConfig/clientsConfig.constants.d.ts +3 -0
  5. package/dist/talkpilot/clientsConfig/clientsConfig.constants.d.ts.map +1 -0
  6. package/dist/talkpilot/clientsConfig/clientsConfig.constants.js +6 -0
  7. package/dist/talkpilot/clientsConfig/clientsConfig.constants.js.map +1 -0
  8. package/dist/talkpilot/clientsConfig/clientsConfig.getters.d.ts +39 -0
  9. package/dist/talkpilot/clientsConfig/clientsConfig.getters.d.ts.map +1 -1
  10. package/dist/talkpilot/clientsConfig/clientsConfig.getters.js +92 -1
  11. package/dist/talkpilot/clientsConfig/clientsConfig.getters.js.map +1 -1
  12. package/dist/talkpilot/clientsConfig/clientsConfig.types.d.ts +4 -0
  13. package/dist/talkpilot/clientsConfig/clientsConfig.types.d.ts.map +1 -1
  14. package/dist/talkpilot/clientsConfig/index.d.ts +1 -0
  15. package/dist/talkpilot/clientsConfig/index.d.ts.map +1 -1
  16. package/dist/talkpilot/clientsConfig/index.js +1 -0
  17. package/dist/talkpilot/clientsConfig/index.js.map +1 -1
  18. package/jest.config.js +20 -20
  19. package/package.json +46 -46
  20. package/src/__tests__/setup.ts +20 -20
  21. package/src/bulkWrite/__tests__/bulkWrite.spec.ts +65 -65
  22. package/src/bulkWrite/bulkWrite.ops.ts +45 -45
  23. package/src/bulkWrite/bulkWrite.types.ts +4 -4
  24. package/src/bulkWrite/index.ts +2 -2
  25. package/src/config.ts +9 -9
  26. package/src/configuration/index.ts +17 -17
  27. package/src/configuration/internalModels/index.ts +3 -3
  28. package/src/configuration/internalModels/internalModels.constants.ts +1 -1
  29. package/src/configuration/internalModels/internalModels.getters.ts +33 -33
  30. package/src/configuration/internalModels/internalModels.types.ts +12 -12
  31. package/src/configuration/models/index.ts +25 -25
  32. package/src/configuration/models/models.constants.ts +13 -13
  33. package/src/configuration/models/models.getters.ts +53 -53
  34. package/src/configuration/models/models.types.ts +79 -79
  35. package/src/configuration/mongodb-client.ts +62 -62
  36. package/src/configuration/prompts/index.ts +2 -2
  37. package/src/configuration/prompts/prompts.getters.ts +49 -49
  38. package/src/configuration/prompts/prompts.types.ts +11 -11
  39. package/src/connection.ts +81 -81
  40. package/src/index.ts +42 -42
  41. package/src/municipal/__tests__/validation.spec.ts +62 -62
  42. package/src/municipal/cities/cities.getters.ts +50 -50
  43. package/src/municipal/cities/cities.types.ts +11 -11
  44. package/src/municipal/cities/index.ts +2 -2
  45. package/src/municipal/departmentsSubjects/__tests__/departmentsSubjects.spec.ts +272 -272
  46. package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +317 -317
  47. package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +73 -73
  48. package/src/municipal/departmentsSubjects/index.ts +9 -9
  49. package/src/municipal/index.ts +22 -22
  50. package/src/municipal/mongodb-client.ts +61 -61
  51. package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +94 -94
  52. package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +92 -92
  53. package/src/municipal/muniIssues/index.ts +17 -17
  54. package/src/municipal/muniIssues/muniIssues.constants.ts +18 -18
  55. package/src/municipal/muniIssues/muniIssues.getters.ts +24 -24
  56. package/src/municipal/muniIssues/muniIssues.schema.ts +66 -66
  57. package/src/municipal/muniIssues/muniIssues.setters.ts +24 -24
  58. package/src/municipal/muniIssues/muniIssues.setup.ts +65 -65
  59. package/src/municipal/muniIssues/muniIssues.types.ts +37 -37
  60. package/src/municipal/streets/__tests__/streets.spec.ts +253 -253
  61. package/src/municipal/streets/index.ts +2 -2
  62. package/src/municipal/streets/streets.getters.ts +140 -140
  63. package/src/municipal/streets/streets.types.ts +19 -19
  64. package/src/municipal/systemInstructions/__tests__/getters.spec.ts +113 -113
  65. package/src/municipal/systemInstructions/__tests__/setters.spec.ts +274 -274
  66. package/src/municipal/systemInstructions/index.ts +7 -7
  67. package/src/municipal/systemInstructions/instructions.getters.ts +57 -57
  68. package/src/municipal/systemInstructions/instructions.setters.ts +119 -119
  69. package/src/municipal/systemInstructions/instructions.types.ts +30 -30
  70. package/src/municipal/tickets/__tests__/tickets.getters.spec.ts +30 -30
  71. package/src/municipal/tickets/__tests__/tickets.statistics.spec.ts +99 -99
  72. package/src/municipal/tickets/index.ts +9 -9
  73. package/src/municipal/tickets/tickets.constants.ts +8 -8
  74. package/src/municipal/tickets/tickets.getters.ts +121 -121
  75. package/src/municipal/tickets/tickets.statistics.aggregation.ts +110 -110
  76. package/src/municipal/tickets/tickets.statistics.getters.ts +145 -145
  77. package/src/municipal/tickets/tickets.types.ts +54 -54
  78. package/src/municipal/utils/types.ts +11 -11
  79. package/src/talkpilot/__tests__/db.spec.ts +38 -38
  80. package/src/talkpilot/__tests__/mongodb-client.spec.ts +18 -18
  81. package/src/talkpilot/__tests__/validation.spec.ts +68 -68
  82. package/src/talkpilot/agents/__tests__/agents.getters.spec.ts +29 -29
  83. package/src/talkpilot/agents/agents.getters.ts +34 -34
  84. package/src/talkpilot/agents/agents.types.ts +14 -14
  85. package/src/talkpilot/agents/index.ts +2 -2
  86. package/src/talkpilot/backgroundToolResults/__tests__/backgroundToolResults.getters.spec.ts +147 -147
  87. package/src/talkpilot/backgroundToolResults/backgroundToolResults.getters.ts +65 -65
  88. package/src/talkpilot/backgroundToolResults/backgroundToolResults.types.ts +23 -23
  89. package/src/talkpilot/backgroundToolResults/index.ts +2 -2
  90. package/src/talkpilot/calls/__tests__/callStats.utils.spec.ts +128 -128
  91. package/src/talkpilot/calls/__tests__/calls.dashboard.spec.ts +229 -229
  92. package/src/talkpilot/calls/__tests__/calls.spec.ts +471 -471
  93. package/src/talkpilot/calls/__tests__/calls.statistics.spec.ts +483 -483
  94. package/src/talkpilot/calls/calls.constants.ts +49 -49
  95. package/src/talkpilot/calls/calls.getters.ts +277 -277
  96. package/src/talkpilot/calls/calls.statistics.getters.ts +668 -668
  97. package/src/talkpilot/calls/calls.statistics.types.ts +48 -48
  98. package/src/talkpilot/calls/calls.types.ts +134 -134
  99. package/src/talkpilot/calls/dashboard/calls.dashboard.ts +295 -295
  100. package/src/talkpilot/calls/dashboard/calls.dashboard.types.ts +57 -57
  101. package/src/talkpilot/calls/index.ts +6 -6
  102. package/src/talkpilot/clientAudioBuffers/__tests__/clientAudioBuffer.getters.spec.ts +160 -160
  103. package/src/talkpilot/clientAudioBuffers/clientAudioBuffer.getters.ts +117 -117
  104. package/src/talkpilot/clientAudioBuffers/clientsAudioBuffers.types.ts +25 -25
  105. package/src/talkpilot/clientAudioBuffers/index.ts +2 -2
  106. package/src/talkpilot/clients/__tests__/clients.quota.spec.ts +123 -123
  107. package/src/talkpilot/clients/clients.getters.ts +16 -16
  108. package/src/talkpilot/clients/clients.quota.getters.ts +119 -119
  109. package/src/talkpilot/clients/clients.quota.types.ts +27 -27
  110. package/src/talkpilot/clients/clients.types.ts +18 -18
  111. package/src/talkpilot/clients/index.ts +4 -4
  112. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.getters.spec.ts +318 -0
  113. package/src/talkpilot/clientsConfig/__tests__/clientsConfig.spec.ts +212 -212
  114. package/src/talkpilot/clientsConfig/clientsConfig.constants.ts +2 -0
  115. package/src/talkpilot/clientsConfig/clientsConfig.getters.ts +116 -2
  116. package/src/talkpilot/clientsConfig/clientsConfig.types.ts +4 -0
  117. package/src/talkpilot/clientsConfig/index.ts +3 -2
  118. package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +217 -217
  119. package/src/talkpilot/contextNotes/contextNotes.getters.ts +85 -85
  120. package/src/talkpilot/contextNotes/contextNotes.types.ts +20 -20
  121. package/src/talkpilot/contextNotes/index.ts +2 -2
  122. package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +99 -99
  123. package/src/talkpilot/flows/flows.getter.ts +14 -14
  124. package/src/talkpilot/flows/flows.schema.ts +155 -155
  125. package/src/talkpilot/flows/flows.types.ts +189 -189
  126. package/src/talkpilot/flows/index.ts +2 -2
  127. package/src/talkpilot/groups/__tests__/groups.spec.ts +90 -90
  128. package/src/talkpilot/groups/__tests__/phone.utils.spec.ts +32 -32
  129. package/src/talkpilot/groups/groups.getters.ts +30 -30
  130. package/src/talkpilot/groups/groups.types.ts +29 -29
  131. package/src/talkpilot/groups/index.ts +3 -3
  132. package/src/talkpilot/groups/phone.utils.ts +46 -46
  133. package/src/talkpilot/index.ts +31 -31
  134. package/src/talkpilot/leads/index.ts +2 -2
  135. package/src/talkpilot/leads/leads.getter.ts +6 -6
  136. package/src/talkpilot/leads/leads.schema.ts +33 -33
  137. package/src/talkpilot/leads/leads.types.ts +20 -20
  138. package/src/talkpilot/mongodb-client.ts +78 -78
  139. package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +282 -282
  140. package/src/talkpilot/phone_numbers/index.ts +2 -2
  141. package/src/talkpilot/phone_numbers/phone_numbers.getter.ts +176 -176
  142. package/src/talkpilot/phone_numbers/phone_numbers.schema.ts +17 -17
  143. package/src/talkpilot/phone_numbers/phone_numbers.types.ts +30 -30
  144. package/src/talkpilot/plans/__tests__/plans.spec.ts +70 -70
  145. package/src/talkpilot/plans/index.ts +2 -2
  146. package/src/talkpilot/plans/plans.getters.ts +132 -132
  147. package/src/talkpilot/plans/plans.types.ts +89 -89
  148. package/src/talkpilot/products/__tests__/products.getters.spec.ts +44 -44
  149. package/src/talkpilot/products/index.ts +2 -2
  150. package/src/talkpilot/products/products.getters.ts +12 -12
  151. package/src/talkpilot/products/products.types.ts +9 -9
  152. package/src/talkpilot/results/index.ts +7 -7
  153. package/src/talkpilot/results/results.getter.ts +39 -39
  154. package/src/talkpilot/results/results.schema.ts +25 -25
  155. package/src/talkpilot/results/results.types.ts +34 -34
  156. package/src/talkpilot/retry_analyze/__tests__/retryAnalyze.getters.spec.ts +156 -156
  157. package/src/talkpilot/retry_analyze/index.ts +2 -2
  158. package/src/talkpilot/retry_analyze/retryAnalyze.getters.ts +84 -84
  159. package/src/talkpilot/retry_analyze/retryAnalyze.types.ts +13 -13
  160. package/src/talkpilot/sessions/__tests__/sessions.spec.ts +147 -147
  161. package/src/talkpilot/sessions/index.ts +2 -2
  162. package/src/talkpilot/sessions/sessions.getter.ts +92 -92
  163. package/src/talkpilot/sessions/sessions.schema.ts +34 -34
  164. package/src/talkpilot/sessions/sessions.types.ts +30 -30
  165. package/src/talkpilot/subscriptions/__tests__/subscriptions.getters.utils.spec.ts +45 -45
  166. package/src/talkpilot/subscriptions/index.ts +3 -3
  167. package/src/talkpilot/subscriptions/subscriptions.getters.ts +146 -146
  168. package/src/talkpilot/subscriptions/subscriptions.getters.utils.ts +33 -33
  169. package/src/talkpilot/subscriptions/subscriptions.types.ts +66 -66
  170. package/src/talkpilot/utils/__tests__/query.utils.spec.ts +49 -49
  171. package/src/talkpilot/utils/query.utils.ts +21 -21
  172. package/src/test-utils/db-utils.ts +33 -33
  173. package/src/test-utils/factories/index.ts +16 -16
  174. package/src/test-utils/factories/municipal/cities.ts +16 -16
  175. package/src/test-utils/factories/municipal/departmentsSubjects.ts +37 -37
  176. package/src/test-utils/factories/municipal/muniIssues.ts +32 -32
  177. package/src/test-utils/factories/municipal/streets.ts +22 -22
  178. package/src/test-utils/factories/municipal/tickets.ts +39 -39
  179. package/src/test-utils/factories/talkpilot/agents.ts +19 -19
  180. package/src/test-utils/factories/talkpilot/calls.ts +37 -37
  181. package/src/test-utils/factories/talkpilot/clientAudioBuffers.ts +20 -20
  182. package/src/test-utils/factories/talkpilot/clientsConfig.ts +18 -18
  183. package/src/test-utils/factories/talkpilot/contextNotes.ts +40 -40
  184. package/src/test-utils/factories/talkpilot/flows.ts +33 -33
  185. package/src/test-utils/factories/talkpilot/groups.ts +33 -33
  186. package/src/test-utils/factories/talkpilot/phone_numbers.ts +22 -22
  187. package/src/test-utils/factories/talkpilot/sessions.ts +35 -35
  188. package/src/test-utils/factories/websitalk/scans.ts +24 -24
  189. package/src/test-utils/factories/websitalk/websiteUrls.ts +17 -17
  190. package/src/utils/date.utils.ts +126 -126
  191. package/src/utils/shared.types.ts +4 -4
  192. package/src/utils/validation.ts +23 -23
  193. package/src/websitalk/index.ts +16 -16
  194. package/src/websitalk/mongodb-client.ts +61 -61
  195. package/src/websitalk/scans/__tests__/scans.spec.ts +313 -313
  196. package/src/websitalk/scans/index.ts +4 -4
  197. package/src/websitalk/scans/scans.constants.ts +15 -15
  198. package/src/websitalk/scans/scans.getters.ts +160 -160
  199. package/src/websitalk/scans/scans.types.ts +45 -45
  200. package/src/websitalk/scans/scans.utils.ts +5 -5
  201. package/src/websitalk/websiteUrls/__tests__/websiteUrls.spec.ts +77 -77
  202. package/src/websitalk/websiteUrls/index.ts +2 -2
  203. package/src/websitalk/websiteUrls/websiteUrls.getters.ts +65 -65
  204. package/src/websitalk/websiteUrls/websiteUrls.types.ts +13 -13
  205. package/tsconfig.json +23 -23
  206. package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.d.ts +0 -10
  207. package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.d.ts.map +0 -1
  208. package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.js +0 -15
  209. package/dist/municipal/departmentsSubjects/departmentsSubjects.setters.js.map +0 -1
  210. package/dist/municipal/streets/streets.setters.d.ts +0 -10
  211. package/dist/municipal/streets/streets.setters.d.ts.map +0 -1
  212. package/dist/municipal/streets/streets.setters.js +0 -15
  213. package/dist/municipal/streets/streets.setters.js.map +0 -1
  214. package/dist/reconcile/index.d.ts +0 -5
  215. package/dist/reconcile/index.d.ts.map +0 -1
  216. package/dist/reconcile/index.js +0 -21
  217. package/dist/reconcile/index.js.map +0 -1
  218. package/dist/reconcile/reconcile.diff.d.ts +0 -4
  219. package/dist/reconcile/reconcile.diff.d.ts.map +0 -1
  220. package/dist/reconcile/reconcile.diff.js +0 -36
  221. package/dist/reconcile/reconcile.diff.js.map +0 -1
  222. package/dist/reconcile/reconcile.execute.d.ts +0 -7
  223. package/dist/reconcile/reconcile.execute.d.ts.map +0 -1
  224. package/dist/reconcile/reconcile.execute.js +0 -20
  225. package/dist/reconcile/reconcile.execute.js.map +0 -1
  226. package/dist/reconcile/reconcile.ops.d.ts +0 -12
  227. package/dist/reconcile/reconcile.ops.d.ts.map +0 -1
  228. package/dist/reconcile/reconcile.ops.js +0 -24
  229. package/dist/reconcile/reconcile.ops.js.map +0 -1
  230. package/dist/reconcile/reconcile.types.d.ts +0 -32
  231. package/dist/reconcile/reconcile.types.d.ts.map +0 -1
  232. package/dist/reconcile/reconcile.types.js +0 -3
  233. package/dist/reconcile/reconcile.types.js.map +0 -1
package/README.md CHANGED
@@ -1,721 +1,721 @@
1
- L1:# @talkpilot/core-db
2
-
3
- [NPM Version](https://www.npmjs.com/package/@talkpilot/core-db)
4
- `@talkpilot/core-db` is the shared TypeScript database package that wires TalkPilot APIs, municipal CRM integrations, and internal tools to a single, type-safe MongoDB surface. Every repo (MIS, CIS, TalkPilot Server, etc.) imports this package to avoid re-implementing connections, collections, or validation helpers.
5
-
6
- ## Purpose
7
-
8
- - Provide a reliable, multi-domain MongoDB layer for TalkPilot and municipal data.
9
- - Export typed getters, vector search helpers, and document factories so services can focus on behavior instead of schema wiring.
10
- - Manage connection lifecycles, environment configuration, and test helpers from one place so every repo reuses the same plumbing.
11
-
12
- ## Main Concepts
13
-
14
- - **Multi-domain clients** – `src/connection.ts` exposes `mongodbClient` (TalkPilot) and `municipalDataMongodbClient`, each of which resolves `MONGO_URI`, DB overrides, and default names.
15
- - **Domain-specific getters** – `src/talkpilot/` and `src/municipal/` host typed getters (agents, calls, streets, tickets, etc.), vector-search helpers, and service-friendly adapters that keep caller code DRY.
16
- - **Product-specific clients (future)** – While the package currently exposes the shared TalkPilot + municipal clients, we expect each product (CIS, MIS, TalkPilot Server) to eventually get its own domain-specific client helpers or wrappers so the shared core can remain stable while new consumers add targeted extensions.
17
- - **Test helpers** – `src/test-utils/` plus `src/__tests__/` reuse `MongoMemoryServer` and shared factories so tests start with clean data regardless of the consuming repo.
18
- - **Utility layers** – `src/utils/` contains shared validation, pagination, and environment helpers that complement the getters.
19
- - **Bulk-write helpers** – `src/bulkWrite/` exposes small, domain-agnostic functions (`buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp`) that construct correctly-shaped MongoDB bulk-write operations from a filter and field values — no collection- or domain-specific knowledge required.
20
- - **Configuration domain** – `src/configuration/` hosts the `configuration` database (a `prompts` collection so far) — a place for cross-service settings that used to be hardcoded in consuming repos, editable without a deploy.
21
- - **Environment awareness** – Defaults, fallbacks, and `process.env` lookups ensure local, CI, and Cloud Run clients all connect using the right URI/DB names.
22
-
23
- ## Key Components
24
-
25
- - `src/connection.ts` – Central connection logic that resolves URIs/DB names from env vars (`MONGO_URI`, `MONGODB_URI`, `TALKPILOT_DB_NAME`, `MUNICIPAL_DB_NAME`) and reuses a single `MongoClient`.
26
- - `src/talkpilot/` – Call history, agents, flows, sessions, leads, subscriptions, and support helpers exposed as getters plus helper enums/types for each collection.
27
- - `src/municipal/` – Municipal-specific collections (`cities`, `streets`, `departmentsSubjects`, `tickets`, etc.) plus vector search helpers and Ash Bina helpers used by MIS.
28
- - `src/utils/` – Shared helpers such as `resolveConnection`, pagination utilities, and schema validation helper functions.
29
- - `src/bulkWrite/` – Generic bulk-write op constructors (`buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp`) usable with any collection's document type.
30
- - `src/configuration/` – `configurationMongodbClient` plus the `prompts` collection (`Prompt` type, `getPromptByName`, `findPrompts`, `getAllPrompts`, `getPromptsByProduct`).
31
- - `src/config.ts` – Centralized `process.env` reads for the configuration domain — add new env-backed fields here instead of reading `process.env` inline elsewhere.
32
- - `src/test-utils/` and `src/__tests__/` – Utilities that bootstrap `MongoMemoryServer`, expose factories, and make sure Jest environments can stub database calls predictably.
33
- - `dist/` – Compiled output consumed by downstream repos (CJS + ESM + type defs).
34
-
35
- ## Domain APIs
36
-
37
- - **TalkPilot domain** – Imports like `findAgents`, `getFlows`, `findCalls`, and `vectorSearchCalls` live in `src/talkpilot`. These functions are the canonical access pattern for call history, session metadata, and provider configs.
38
- - **Municipal domain** – Helpers such as `findStreets`, `getMunicipalCities`, `findDepartmentSubjects`, and `createTicket` live under `src/municipal` and feed MIS workflows (street hints, subject matching, Ash Bina tickets).
39
- - **Configuration domain** – `getPromptByName`, `findPrompts`, `getAllPrompts`, and `getPromptsByProduct` live under `src/configuration` and back MIS's `moked_106` prompt lookups (defaults, overridable per-client via `clientConfig.toolsPrompts`).
40
-
41
- ## Environment variables
42
-
43
- | Variable | Purpose | Required |
44
- |---------------------|-----------------------------------------------------------------------------------|----------|
45
- | `MONGO_URI` | Primary MongoDB connection string for every domain (overridden by `MONGODB_URI`). | ✅ |
46
- | `MONGODB_URI` | Alternate connection string used when Mongo needs a second URI parameter. | ✅ |
47
- | `TALKPILOT_DB_NAME` | Optional override for the TalkPilot database name (defaults from URI path). | ❌ |
48
- | `MUNICIPAL_DB_NAME` | Optional override for the municipal database name (defaults to `municipal-data`). | ❌ |
49
- | `CONFIGURATION_DB_NAME` | Optional override for the configuration database name (defaults to `configuration`). | ❌ |
50
- | `ENV` | Free-form label used in logs/validators (defaults to `unknown`). | ❌ |
51
-
52
- If you pass a `uri` directly to `mongodbClient.connect()` or `municipalDataMongodbClient.connect()`, the client will prefer that value over the env vars.
53
-
54
- ## Getting Started
55
-
56
- ### Prerequisites
57
-
58
- - Node.js 22.x+ (aligns with downstream services).
59
- - npm 11+ or Yarn.
60
- - MongoDB accessible from your environment or a `MongoMemoryServer` for tests.
61
-
62
- ### Setup
63
-
64
- 1. Clone the repo and install dependencies:
65
-
66
- ```bash
67
- git clone https://github.com/talkpilot/core-db.git
68
- cd core-db
69
- npm install
70
- ```
71
-
72
- 2. Build the package before using it locally:
73
-
74
- ```bash
75
- npm run build
76
- ```
77
-
78
- 3. Import `@talkpilot/core-db` from another project by pointing `package.json` at the local path during development or installing the published release.
79
-
80
- ## Sample `.env`
81
-
82
- ```
83
- MONGO_URI=mongodb://localhost:27017
84
- TALKPILOT_DB_NAME=talkpilot-dev
85
- MUNICIPAL_DB_NAME=municipal-dev
86
- CONFIGURATION_DB_NAME=configuration-dev
87
- ENV=development
88
- ```
89
-
90
- Adjust `MONGO_URI` to match the running Mongo instance and configure `talkpilot`/`municipal`/`configuration` DB names if you want to keep them separate.
91
-
92
- ## Local development
93
-
94
- 1. Run `npm install`.
95
- 2. Build the compiled output: `npm run build`.
96
- 3. Execute tests: `npm run test`.
97
- 4. Use `npm link` or `npm pack` to consume the freshly built package from other repos (`CIS`, `MIS`, `TalkPilot Server`).
98
-
99
- ## Development guide
100
-
101
- `DEVELOPMENT.md` contains the tactical steps for contributors. At a glance:
102
-
103
- - Node 18+/TypeScript is required (aligns with downstream services).
104
- - Run `npm install` → `npm run build` after cloning.
105
- - Use `npm link`/`npm link @talkpilot/core-db` to test the package locally before publishing.
106
- - When adding getters, define types, implement the function, export it through the domain `index.ts`, and add a corresponding test under the domain’s `__tests__` folder.
107
- - Always rely on the provided test factories (`src/test-utils/factories`) to seed data so tests remain consistent.
108
- - Jest with `mongodb-memory-server` is the only execution path we have to verify this core utility—unit tests are the safety net for every change.
109
-
110
- Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and factory samples.
111
-
112
- ## 🧪 Testing
113
-
114
- - `npm run test` – Jest suite (factories, utils, integration mocks) powered by `mongodb-memory-server`.
115
- - Tests rely on `src/__tests__/setup.ts` to bootstrap the in-memory Mongo instances and wire shared factories/helpers before each run.
116
- - When adding getters, helpers, or domain logic, create focused coverage inside the consuming domain’s `__tests__/` folder and use the provided factories to keep fixtures consistent.
117
-
118
- `@talkpilot/core-db` does not run in a product UI or feature branch—unit tests are the *only* reliable execution path to ensure your changes work. Every change must ship with a unit test so downstream repos can upgrade without surprises; treat the test suite as the canonical safety net for this core utility package.
119
-
120
- ## 🧹 Lint & build verification
121
-
122
- - `npm run lint` – Run ESLint over `src/**/*.{ts,tsx}`.
123
- - `npm run format` – Format the source files with Prettier.
124
- - `npm run build` – Compile TypeScript and emit `dist/` (used by downstream consumers).
125
-
126
- ## ✅ Pre-push checklist
127
-
128
- 1. `npm run build`.
129
- 2. `npm run test`.
130
- 3. `npm run format`.
131
-
132
- ## Publishing & release notes
133
-
134
- - Releases are handled by `npm version <patch|minor|major>` followed by `npm publish`. The package is a **private `@talkpilot` dependency**, so every contributor must install the shared npm automation token into their global `~/.npmrc` before running publish or `npm install`.
135
- - The shared token is rotated periodically—if you see authentication failures, request the refreshed token, update your `~/.npmrc`, and retry. Never commit credentials to source control.
136
- - After publishing, downstream repos (`CIS`, `MIS`, `TalkPilot Server`, etc.) should run `npm update @talkpilot/core-db` so they receive the latest helpers/bug fixes.
137
- - Cloud Build & Cloud Run jobs that depend on this package pick up the new version the next time they rebuild their container; the services pull the compiled `dist/` output and type definitions when installing the dependency.
138
-
139
- - Release process, when to publish, branch hygiene, and the function-signature versioning policy: see [`DEVELOPMENT.md`](./DEVELOPMENT.md).
140
-
141
- ### Version history
142
-
143
- | Version | Note |
144
- |---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
145
- | 1.1.9 | Maintenance release (build, test, format). |
146
- | 1.3.4 | Added new statistics getters for call & ticket dashboards (CP-149): summary, trend, hourly, and routing for calls, plus open/draft/subject ticket stats. **Removed** the legacy getters `getTicketsCountByCityAndDateRange` and `getTicketsSubjectStats`. |
147
- | 1.3.5 | Added the `muniIssues` collection & module (CP-1115): the `MuniIssue` document type, `createMuniIssue` (accepts a caller-supplied `_id` for a two-way Jira link), `generateMuniIssueId`, `getMuniIssueById` / `getMuniIssueByJiraKey`, a `$jsonSchema` validator with indexes (unique `jira.key`), and `ensureMuniIssuesCollection` to provision it at boot. |
148
- | 1.3.6 | Added `contextNotes` and `products` modules under `src/talkpilot/`. |
149
- | 1.3.7 | Added `disableGenericPrompt` optional boolean field to the `Flow` type and schema (CP-704). |
150
- | 1.3.8 | Ticket-count Map getters (CP-1200): deprecated `string[]` ticket getters and `CallsStatsFilter` fields, added `Map<string, number>` replacements; fixed ticket counting in `aggregateCallsSummary`. |
151
- | 1.3.9 | Fixed wrap-around hour filter boundary guards (CP-1166): excluded first-day morning calls and last-day evening calls from wrap-around windows. |
152
- | 1.3.10 | Added optional `isDraft` flag to `Ticket` (CP-1390): explicit draft marking with legacy fallback for existing tickets. |
153
- | 1.3.11 | Fixed pre-existing broken type declaration import in `clientsConfig.types.d.ts` that caused consumer `tsc` builds to fail. |
154
- | 1.3.12 | Added `callsWithTickets` to `CallsSummaryAggregation` (CP-1200): distinct call count with at least one open ticket, enabling accurate `ticketOpenRate` and `not_opened` calculations in consumers. |
155
- | 1.3.13 | Faulty release (redundant). Published with `Flow.useRedisTranscription` at the flow level; superseded by 1.3.14. |
156
- | 1.3.14 | Added `FlowTool.useRedisTranscription` optional flag to control whether cached Redis transcriptions are used (defaults to `false`). |
157
- | 1.3.15 | Multi-scan support for WebsiteTalk (CP-1372): `websiteUrls` collection, `Scan.websiteUrlId`, `OVERWRITTEN` status, `activeScanId` on `WebsiteTalkProduct`. **Breaking:** `Scan.baseUrl` removed; `getActiveScanStatus` removed. |
158
- | 1.3.16 | Refactored WebsiteTalk scan status constants (CP-1372): `SCAN_STATUSES` object map, `FINISHED_SCAN_STATUSES` derived from it, `isInProgressScan` moved to `scans.utils`. No breaking API changes. |
159
- | 1.3.17 | Twilio call-status semantics for Websitalk dashboard: `inCallCount` KPI (`in-progress` + `answered`), `busy` is line-busy only; `updateCallStatusByCallSid`; expanded `CallStatus` union; `timeSavedMinutes` from `completed` only. |
160
- | 1.3.18 | WebsiteTalk multi-website API (CP-1372): ships `websiteUrls` module, scan getters by `websiteUrlId`, `activeScanId` getters on `clientsConfig`. **Note:** 1.3.17 did not include these — they landed after merge. **Breaking:** `WebsiteTalkProduct.defaultBaseUrl` removed from type. |
161
- | 1.3.19 | WebsiteTalk flow provisioning (WTIS activate-scan): optional `flowId` on `WebsiteTalkProduct`; `bindClientPhoneToFlow(clientId, flowId)` sets `flow_id` on the client's primary `phone_numbers` document so inbound calls route to the provisioned TalkPilot flow. |
162
- | 1.3.20 | `FINAL_STATUSES` constant for terminal Twilio call statuses (`no-answer`, `completed`, `busy`, `failed`, `canceled`) in `calls.constants`. |
163
- | 1.3.21 | Added `ToolExecutionStep` type, `steps` field to `ToolExecution`, and `pushToolExecution` getter (CP-1093). Added `ToolExecutionStepLevel` named type and `TOOL_EXECUTIONS_DEFAULT_LIMIT`/`SKIP` constants. Widened `ToolExecutionStep.data` to `Record<string, unknown> \| string` — allows plain string steps alongside structured JSON. Added optional `ToolExecutionStep.payload` for structured drill-down data. |
164
- | 1.3.22 | `CallsFilterParams.status` typed as `CallStatus` instead of `string` — aligns call-query filters with the Twilio status union from 1.3.17. |
165
- | 1.3.23 | Merge of 1.3.21 and 1.3.22 — combines the `ToolExecutionStep`/`steps`/`pushToolExecution` work (CP-1093) with the `CallsFilterParams.status: CallStatus` fix. Adds `CallStatusValues` (const object) with `CallStatus` and `ALL_CALL_STATUSES` derived from it. `CallStatus` still does not include `"redirected"` — tracked separately. |
166
- | 1.3.24 | **Breaking:** removed `flowId` from `WebsiteTalkProduct` — flow source of truth is `phone_numbers.flow_id`. Added `getPrimaryPhoneFlowId(clientId)`. |
167
- | 1.3.25 | Added `disconnectDb()` to close all MongoDB clients opened by `ensureDbConnected()` — for one-shot scripts that must exit cleanly. |
168
- | 1.3.28 | Soft-delete (`isActive`) on Streets/DepartmentSubjects, new bulk-write getters, MongoDB type re-exports, and the generic `bulkWrite` op-builder module. |
169
- | 1.3.29 | Added client call-quota module (CP-1500): `ClientConfig.quota` for usage limits (`totalQuota`, `usedQuota`, `expiresAt`), alert settings on `clients`, and getters for state, increment/reset, threshold alerts, and expiry notification tracking. |
170
- | 1.3.32 | `clientDisplayName` lives on `clientsConfig.quota` (not top-level). `getClientDisplayName` returns `"-"` when unset; never exposes `clientId`. |
171
- | 1.3.33 | Added `configuration` database module (CP-1560): `configurationMongodbClient` + a read-only `Prompts`-style collection for prompts previously hardcoded in consuming repos (e.g. MIS). |
172
- | 1.3.35 | Fixed the configuration collection name (`Prompts` → `prompts`, matches the lowercase convention used elsewhere). **Breaking** if you inserted documents into a collection literally named `Prompts`. Added `Prompt.productName` (required) + `getPromptsByProduct`. Centralized configuration-DB env var reads into `src/config.ts`. |
173
- | 1.3.36 | Publish combining the 1.3.33/1.3.35 configuration-DB work with the latest `main` (client quota + `clientDisplayName` + bulk-write/streets/departmentSubjects updates — see 1.3.28/1.3.29/1.3.32). No new code of its own. |
174
- | 1.3.37 | Added `models` and `internalModels` collections under `configuration` (CP-1624): realtime/stt model catalog (`ModelDoc`, `getModelByModelId`, `getModelsByProvider`, `getModelsByType`, `getAvailableModelsByType`) and a name-keyed settings store (`InternalModel`, `getInternalModelByName`) for cross-service config previously hardcoded in consuming repos (e.g. TalkPilot Server's realtime/STT catalogs and its live transcription model). Read-only, same as `prompts` — documents are seeded/managed manually. |
175
- | 1.3.38 | Added optional `transcriptionComparison` field to `Call` (CP-1594): per-`{provider}-{model}` side-channel transcription comparison results, same segment shape as `Call.transcription`. |
176
-
177
- ### 1.1.9
178
-
179
- 1. `npm run build`.
180
- 2. `npm run test`.
181
- 3. `npm run format`.
182
-
183
- ### 1.3.4 — Call & ticket statistics (CP-149)
184
-
185
- New call statistics getters for dashboards (summary, trend, hourly, routing) and ticket statistics scoped to the same date range (open tickets, draft tickets, subject breakdowns).
186
-
187
- **Removed**
188
-
189
- | Removed | Replacement |
190
- |-------------------------------------|-----------------------------------------------------------------------------------------------------------------|
191
- | `getTicketsCountByCityAndDateRange` | `aggregateCallsSummary` + `findCallSidTicketCountsByCity` — note: returns `Map<string, number>`, not `string[]` |
192
- | `getTicketsSubjectStats` | `findSubjectsByCityAndDateRange` |
193
- | `SubjectStatsItem` | `SubjectItem` |
194
-
195
- **Do I need to update my app?**
196
-
197
- Yes — if you used any of the removed functions above.
198
-
199
- ### 1.3.5 — Muni issues (CP-1115)
200
-
201
- New `muniIssues` module under `src/municipal/` for issues reported from the call-log screen. The document is written to the municipal DB after its Jira ticket is created.
202
-
203
- **Added**
204
-
205
- | Export | Purpose |
206
- |----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
207
- | `MuniIssue` / `CreateMuniIssueInput` | Document type and insert-input type (`issueContent` + `jira` domains). |
208
- | `createMuniIssue(input, id)` | Insert an issue; requires a caller-supplied `_id` from MIS (via `generateMuniIssueId`) so it matches the id embedded in the Jira ticket (two-way link). |
209
- | `generateMuniIssueId()` | Pre-generate the `_id` to pass to `createMuniIssue`. |
210
- | `getMuniIssueById` / `getMuniIssueByJiraKey` | Lookups by our id or by the Jira key. |
211
- | `ensureMuniIssuesCollection()` | Provision the `$jsonSchema` validator and indexes (unique `jira.key`); run once at MIS boot. |
212
-
213
- **Do I need to update my app?**
214
-
215
- No — purely additive. New consumers (MIS) import these from `@talkpilot/core-db`.
216
-
217
- ### 1.3.6 — Context Notes & Products
218
-
219
- **Context Notes** — new `contextNotes` collection under `src/talkpilot/` for per-client, per-product notes injected into AI calls at runtime. Each document holds a `systemPrompt` and a list of time-bounded entries (`activeFrom`, `expiresAt`). Two setters with split ownership: `setContextNoteEntries` for the notes list and `setContextNoteConfig` for `systemPrompt` and `product`.
220
-
221
- **Products** — new `products` collection under `src/talkpilot/` cataloguing TalkPilot products. Each document has a stable `name` and an optional `displayName` locale map (`Record<string, string>`) for UI display.
222
-
223
- **Added**
224
-
225
- | Export | Purpose |
226
- |----------------------------------------------|-----------------------------------------------------------------|
227
- | `getContextNotes(clientId, product)` | Fetch context note documents for a client/product pair. |
228
- | `createContextNote(input)` | Insert a new context note document. |
229
- | `setContextNoteEntries(id, clientId, notes)` | Replace the notes list on an existing document. |
230
- | `setContextNoteConfig(id, clientId, config)` | Update `systemPrompt` and/or `product` on an existing document. |
231
- | `getAllProducts()` | Fetch the full product catalogue. |
232
-
233
- **Do I need to update my app?**
234
-
235
- No — purely additive.
236
-
237
- ### 1.3.7 — Generic prompt control (CP-704)
238
-
239
- Added an optional boolean field to the `Flow` type and MongoDB schema.
240
-
241
- **Added**
242
-
243
- | Export | Purpose |
244
- |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
245
- | `Flow.disableGenericPrompt` | Optional `boolean`. When `true`, disables the generic prompt for the flow. Existing flows without this field continue to work unchanged. |
246
-
247
- **Do I need to update my app?**
248
-
249
- No — the field is optional and fully backwards-compatible.
250
-
251
- ### 1.3.8 — Ticket-count Map getters (CP-1200)
252
-
253
- Adds `Map<string, number>` ticket getters that return per-call ticket counts. The old `string[]` getters and filter fields are kept and marked `@deprecated`.
254
-
255
- **Deprecated → Replacement**
256
-
257
- | Deprecated | Replacement |
258
- |---------------------------------------------|--------------------------------------------------------------|
259
- | `findCallSidsWithTicketsByCity` | `findCallSidTicketCountsByCity` → `Map<string, number>` |
260
- | `findCallSidsWithDraftTicketsByCity` | `findCallSidDraftTicketCountsByCity` → `Map<string, number>` |
261
- | `CallsStatsFilter.callSidsWithTickets` | `CallsStatsFilter.callSidTicketCounts` |
262
- | `CallsStatsFilter.callSidsWithDraftTickets` | `CallsStatsFilter.callSidDraftTicketCounts` |
263
-
264
- **Do I need to update my app?**
265
-
266
- No — the old fields still compile. Migrate when convenient.
267
-
268
- ### 1.3.9 — Wrap-around hour filter boundary guards (CP-1166)
269
-
270
- When `hourFrom` > `hourTo` (e.g. 23:00–13:00), two silent miscounting bugs existed:
271
-
272
- - **First-day morning**: calls before `hourTo` on the first day (e.g. 08:00 on Jun 8) were counted even though the window starts at `hourFrom` that day. Fixed by adding `dateLocal > startStr` to the after-midnight leg.
273
- - **Last-day evening**: calls at or after `hourFrom` on the last day (e.g. 23:30 on Jun 9) were counted even though the window ends at `hourTo` that day. Fixed by adding `dateLocal < endStr` to the before-midnight leg.
274
-
275
- **Affects:** `aggregateCallsTrend`, `aggregateCallsSummary`, `aggregateCallsHourlyByRange`, `aggregateCallsRouting`, `findFilteredCallSids`, `findSubjectsByCityAndDateRange`.
276
-
277
- **Do I need to update my app?**
278
-
279
- No API changes — both fixes correct silent miscounting. Upgrading is recommended if you use a wrap-around hour window.
280
-
281
- ### 1.3.10 — Ticket draft flag (CP-1390)
282
-
283
- Added an optional `isDraft` boolean field to the `Ticket` type.
284
-
285
- **Added**
286
-
287
- | Export | Purpose |
288
- |------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
289
- | `Ticket.isDraft` | Optional `boolean`. When `true`, the ticket is a draft. When `false`, it is not. When absent (legacy tickets), draft detection falls back to the previous `event_subject_id` heuristic. |
290
-
291
- **Affects:** `findCallSidDraftTicketCountsByCity`, `findCallSidsWithDraftTicketsByCity` (draft filtering in ticket statistics).
292
-
293
- **Do I need to update my app?**
294
-
295
- No — purely additive. Existing tickets without `isDraft` continue to work unchanged. New consumers (MIS) can pass `isDraft: true` when creating a draft ticket.
296
-
297
- ### 1.3.11 — Fix clientsConfig type declaration import
298
-
299
- Fixed a pre-existing broken import path in the published `clientsConfig.types.d.ts` (introduced in an earlier release, unrelated to 1.3.10). Consumer TypeScript builds could fail with:
300
-
301
- `Cannot find module 'src/utils/shared.types' or its corresponding type declarations.`
302
-
303
- The import now uses a relative path (`../../utils/shared.types`) so `tsc` resolves it correctly from `node_modules/@talkpilot/core-db/dist/`.
304
-
305
- **Do I need to update my app?**
306
-
307
- Yes — upgrade to 1.3.11 if your build failed with the error above (affects any version that shipped the broken declaration). No API or behavior changes otherwise.
308
-
309
- ### 1.3.12 — Calls-with-tickets count (CP-1200)
310
-
311
- Added `callsWithTickets` to `CallsSummaryAggregation` — the number of distinct calls that opened at least one ticket. Use this field (instead of `openTickets`) to compute call-level rates and "calls without a ticket" counts.
312
-
313
- **Do I need to update my app?**
314
-
315
- Yes — replace `openTickets` with `callsWithTickets` wherever you compute `ticketOpenRate` or `not_opened`.
316
-
317
- ### 1.3.13 — Faulty release
318
-
319
- This release incorrectly placed `useRedisTranscription` on `Flow` instead of `FlowTool`. It is redundant and should be skipped.
320
-
321
- ### 1.3.14 — Redis transcription flag
322
-
323
- Added an optional `FlowTool.useRedisTranscription` boolean that tells consumers whether to read transcriptions from Redis. Defaults to `false` when omitted.
324
-
325
- **Do I need to update my app?**
326
-
327
- No — this flag is optional. Only update if you want to opt into the Redis transcription path.
328
-
329
- ### 1.3.15 — Multi-scan configuration (CP-1372)
330
-
331
- Adds `websiteUrls` collection (CRUD getters), migrates scans from `baseUrl` to `websiteUrlId`, adds `OVERWRITTEN` scan status, and replaces `defaultBaseUrl`/`logoUrl` on `WebsiteTalkProduct` with `activeScanId` (+ getters).
332
-
333
- **Breaking**
334
-
335
- | Removed / changed | Replacement |
336
- | --- | --- |
337
- | `Scan.baseUrl` | `Scan.websiteUrlId` |
338
- | `WebsiteTalkProduct.defaultBaseUrl` | `websiteUrls` collection |
339
- | `getActiveScanStatus(clientId)` | `getInProgressScanByWebsiteUrl`, `findInProgressScansByClient` |
340
-
341
- **Do I need to update my app?**
342
-
343
- Yes — WTIS, CoreBrain, and CoreCrawler must adopt `websiteUrlId` and the new getters before upgrading.
344
-
345
- ### 1.3.16 — Scan status constants refactor (CP-1372)
346
-
347
- Centralizes scan status values under a single `SCAN_STATUSES` object map and derives terminal statuses from it.
348
-
349
- **Changed**
350
-
351
- | Area | What |
352
- | --- | --- |
353
- | `SCAN_STATUSES` | Object map (`SCAN_STATUSES.CHECKING`, `SCAN_STATUSES.COMPLETED`, …) instead of separate exported string constants. |
354
- | `FINISHED_SCAN_STATUSES` | Derived from `SCAN_STATUSES` (`COMPLETED`, `FAILED`, `OVERWRITTEN`). |
355
- | `isInProgressScan` | Moved to `scans.utils.ts` (exported from `scans` index). |
356
- | `ScanStatus` type | Derived from `(typeof SCAN_STATUSES)[keyof typeof SCAN_STATUSES]`. |
357
-
358
- **Do I need to update my app?**
359
-
360
- No — behavior is unchanged. If you imported removed aliases like `COMPLETED_SCAN_STATUS`, switch to `SCAN_STATUSES.COMPLETED` (or keep using string literals / `ScanStatus` type).
361
-
362
- ### 1.3.17 — Twilio call-status semantics (CP-1521)
363
-
364
- Aligns dashboard KPIs and call-status updates with Twilio semantics so in-call counts update in real time.
365
-
366
- **Added**
367
-
368
- | Export | Purpose |
369
- | --- | --- |
370
- | `updateCallStatusByCallSid(callSid, status)` | Set the current call status by `callSid`. |
371
- | `IN_CALL_STATUSES` | `["in-progress", "answered"]` — statuses counted as in-call. |
372
- | `DashboardSummaryMetrics.inCallCount` | Replaces `busyCount`; counts in-progress + answered calls. |
373
-
374
- **Changed**
375
-
376
- | Area | What |
377
- | --- | --- |
378
- | Dashboard KPIs | `busyCount` → `inCallCount`; `busy` is line-busy only, not in-call. |
379
- | `timeSavedMinutes` | Computed from `completed` calls only. |
380
- | `CallStatus` union | Expanded for Twilio-aligned statuses. |
381
-
382
- **Do I need to update my app?**
383
-
384
- Yes — if you read `busyCount` from dashboard KPIs, switch to `inCallCount`.
385
-
386
- ### 1.3.18 — WebsiteTalk multi-website API (CP-1372)
387
-
388
- Ships the full persistence API for multi-website / multi-scan. Versions 1.3.15–1.3.16 documented the design; **1.3.17 did not export these symbols** (CP-1372 merged into main after the 1.3.17 release). Upgrade to **1.3.18** if you see missing-export errors such as `getActiveScanId`, `getWebsiteUrlById`, or `WebsiteUrlDoc`.
389
-
390
- **`websiteUrls` module**
391
-
392
- | Export | Purpose |
393
- | --- | --- |
394
- | `WebsiteUrl` / `WebsiteUrlDoc` / `CreateWebsiteUrlInput` | Document types. |
395
- | `getWebsiteUrlsCollection()` | Collection access. |
396
- | `getWebsiteUrlsByClient(clientId)` | All websites for a client. |
397
- | `getWebsiteUrlById(id)` | Lookup by id. |
398
- | `findWebsiteUrls(filter?)` | Flexible query. |
399
- | `createWebsiteUrl({ clientId, name, baseUrl })` | Create. |
400
- | `updateWebsiteUrl(id, updates)` | Update `name` / `baseUrl`. |
401
- | `deleteWebsiteUrl(id)` | Delete by id. |
402
-
403
- **`clientsConfig` — selected scan**
404
-
405
- | Export | Purpose |
406
- | --- | --- |
407
- | `getActiveScanId(clientId)` | Read `products.websiteTalk.activeScanId`. |
408
- | `updateActiveScanId(clientId, scanId)` | Set the active scan for search. |
409
- | `clearActiveScanId(clientId)` | Unset `activeScanId`. |
410
-
411
- **`scans` — by `websiteUrlId`**
412
-
413
- | Export | Purpose |
414
- | --- | --- |
415
- | `getScanById(id)` | Lookup by id. |
416
- | `getScansByWebsiteUrl(websiteUrlId)` | All scans for a website. |
417
- | `getLatestScanByWebsiteUrl(websiteUrlId)` | Most recent scan. |
418
- | `getInProgressScanByWebsiteUrl(websiteUrlId)` | Latest scan if still in progress. |
419
- | `findInProgressScansByClient(clientId)` | All in-progress scans for a client. |
420
- | `hasScansForWebsiteUrl(websiteUrlId)` | Whether any scans exist. |
421
- | `getLatestCompletedScanByWebsiteUrl(websiteUrlId)` | Most recent `COMPLETED` scan. |
422
- | `updateScanDoc(scanId, updates)` | Partial update (e.g. mark `OVERWRITTEN`). |
423
- | `deleteScansByWebsiteUrl(websiteUrlId)` | Delete all scans for a website. |
424
-
425
- **Breaking / type changes**
426
-
427
- | Removed | Replacement |
428
- | --- | --- |
429
- | `WebsiteTalkProduct.defaultBaseUrl` | `websiteUrls` collection (`name`, `baseUrl`) |
430
- | `Scan.baseUrl` | `Scan.websiteUrlId` (see 1.3.15) |
431
-
432
- **`OVERWRITTEN` scan status**
433
-
434
- - `OVERWRITTEN` is part of `ScanStatus` / `SCAN_STATUSES`.
435
- - Marking previous `COMPLETED` scans as overwritten is **not** done in `createScanDoc` — implement in the service layer (e.g. via `updateScanDoc`).
436
-
437
- **Not in core-db (service layer)**
438
-
439
- - `resolveActiveWebsiteContext` — join `activeScanId` → scan → websiteUrl.
440
- - Migration from legacy `defaultBaseUrl`.
441
-
442
- **Do I need to update my app?**
443
-
444
- Yes — WTIS, CoreBrain, and CoreCrawler should upgrade to **1.3.18** and import the symbols above from `@talkpilot/core-db`. Stop reading `defaultBaseUrl` from `WebsiteTalkProduct`; use `websiteUrls` instead.
445
-
446
- ### 1.3.19 — WebsiteTalk flow provisioning (WTIS activate-scan)
447
-
448
- Persists the TalkPilot flow id on the client product config and links the client's primary phone number to that flow so inbound calls use the WebsiteTalk flow after `activate-scan`.
449
-
450
- **`clientsConfig` — `WebsiteTalkProduct`**
451
-
452
- | Field | Purpose |
453
- | --- | --- |
454
- | `WebsiteTalkProduct.flowId?` | Optional TalkPilot flow `_id` (hex string). Set by WTIS after `POST /flows/add_new_flow`; reused on later activations via `PUT /flows/edit_flow/:id`. |
455
-
456
- **`phone_numbers`**
457
-
458
- | Export | Purpose |
459
- | --- | --- |
460
- | `bindClientPhoneToFlow(clientId, flowId)` | Updates the **primary** `phone_numbers` row for `clientId`, setting `flow_id` to the given TalkPilot flow. Throws if no primary phone exists. |
461
-
462
- **Typical service-layer flow (WTIS)**
463
-
464
- 1. Build flow payload from template + `companyInfo` (generated at activate time).
465
- 2. Create or update the flow via TalkPilot Server API (`add_new_flow` / `edit_flow`).
466
- 3. On first create: `updateProductConfig(clientId, "websiteTalk", { flowId })`.
467
- 4. `bindClientPhoneToFlow(clientId, flowId)` — ensure the phone routes to the flow.
468
- 5. `updateActiveScanId(clientId, scanId)` — point search at the activated scan.
469
-
470
- **Not in core-db (service layer)**
471
-
472
- - Flow template substitution, Claude `companyInfo` generation, Firebase Storage template download, TalkPilot flow create/update HTTP calls.
473
-
474
- **Do I need to update my app?**
475
-
476
- No — purely additive. **WTIS** should upgrade to **1.3.19** (or later) and import `bindClientPhoneToFlow` plus `WebsiteTalkProduct.flowId` when implementing activate-scan flow provisioning.
477
-
478
- ### 1.3.20 — `FINAL_STATUSES` call-status constant
479
-
480
- Centralizes terminal Twilio call statuses so consumers (e.g. TalkPilot Server `callResultService`) don't duplicate the list locally.
481
-
482
- **Added**
483
-
484
- | Export | Purpose |
485
- | --- | --- |
486
- | `FINAL_STATUSES` | `["no-answer", "completed", "busy", "failed", "canceled"]` — statuses where no further Twilio callbacks are expected. Pair with `IN_CALL_STATUSES` for live vs terminal semantics. |
487
-
488
- **Do I need to update my app?**
489
-
490
- No — purely additive. Replace local `FINAL_STATUSES` arrays with `import { FINAL_STATUSES } from "@talkpilot/core-db"` when convenient.
491
-
492
- ### 1.3.21 — Tool execution steps & push getter (CP-1093)
493
-
494
- Added `ToolExecutionStep` type, `steps` field on `ToolExecution`, `pushToolExecution` getter, named `ToolExecutionStepLevel` type, and pagination constants.
495
-
496
- **Added**
497
-
498
- | Export | Purpose |
499
- | --- | --- |
500
- | `ToolExecutionStepLevel` | Named type: `"info" \| "warn" \| "error"`. |
501
- | `ToolExecution.steps` | Optional `ToolExecutionStep[]`. Ordered log of intermediate steps within a tool call (e.g. `audio_enrichment`, `google_places`, `subject_classification`). Absent on executions recorded before this version. |
502
- | `ToolExecutionStep.payload` | Optional `Record<string, unknown>`. Structured data for UI drill-down, alongside the human-readable `data` field. |
503
- | `pushToolExecution(callSid, execution)` | Append a `ToolExecution` to the call's `toolExecutions` array via `$push`. |
504
- | `getToolExecutionsByCallSid(callSid, opts?)` | Fetch the `toolExecutions` array for a call. `opts.skip` and `opts.limit` (default `TOOL_EXECUTIONS_DEFAULT_LIMIT` = 50) support pagination. Returns `[]` when the call has no executions or does not exist. |
505
- | `TOOL_EXECUTIONS_DEFAULT_LIMIT` | `50` — default page size for `getToolExecutionsByCallSid`. |
506
- | `TOOL_EXECUTIONS_DEFAULT_SKIP` | `0` — default skip for `getToolExecutionsByCallSid`. |
507
-
508
- **Do I need to update my app?**
509
-
510
- No — purely additive. All new fields are optional and existing documents continue to work unchanged.
511
-
512
- ### 1.3.22 — `CallsFilterParams.status` type alignment
513
-
514
- Tightens the `status` filter field on `CallsFilterParams` from `string` to `CallStatus` so call-query consumers get compile-time validation against the Twilio-aligned status union introduced in 1.3.17.
515
-
516
- **Changed**
517
-
518
- | Area | What |
519
- | --- | --- |
520
- | `CallsFilterParams.status` | `string` → `CallStatus` |
521
-
522
- **Do I need to update my app?**
523
-
524
- Only if you pass a non-`CallStatus` string to `CallsFilterParams.status` — fix the value or cast. No runtime behavior change.
525
-
526
- ### 1.3.23 — Merge of 1.3.21 and 1.3.22, plus `CallStatusValues`
527
-
528
- Combines the CP-1093 tool-execution-steps work (1.3.21) with the `CallsFilterParams.status` type fix (1.3.22); both were published independently from diverging branches.
529
-
530
- **Added**
531
-
532
- | Export | Purpose |
533
- | --- | --- |
534
- | `CallStatusValues` | `as const` object mapping named keys (`Completed`, `Failed`, ...) to the 9 raw Twilio-aligned status strings — gives enum-like dot access (`CallStatusValues.Completed`) while `CallStatus` stays a plain string-literal union (no breaking change for existing `status === "completed"` comparisons). |
535
- | `CallStatus` | Now derived from `CallStatusValues` (`(typeof CallStatusValues)[keyof typeof CallStatusValues]`) instead of a hand-written union — single source of truth. |
536
- | `ALL_CALL_STATUSES` | `CallStatus[]` — `Object.values(CallStatusValues)`, for runtime validation of raw input (e.g. HTTP query params) against `CallStatus`. |
537
-
538
- **Do I need to update my app?** No — `CallStatus` is structurally identical to before (same 9 string literals); this is a source-only refactor.
539
-
540
- `CallStatus` still does not include `"redirected"` — tracked separately.
541
-
542
- ### 1.3.28 — Soft-delete support and generic bulk-write helpers
543
-
544
- Adds an `isActive` soft-delete convention, bulk-write getters for Streets/DepartmentSubjects, MongoDB type re-exports, and a generic bulk-write op-builder module.
545
-
546
- **Added**
547
-
548
- | Export | Purpose |
549
- | --- | --- |
550
- | `Street.isActive` / `DepartmentSubject.isActive` | Optional soft-delete flag; `createStreet` defaults it to `true`. |
551
- | `bulkWriteStreets` / `bulkWriteDepartmentsSubjects` | Passthrough bulk-write for each collection. |
552
- | `findDepartmentSubjectsByFilter` | Query subjects by an arbitrary filter. |
553
- | `updateDepartmentSubjectActive` | Set `isActive` on a subject by `_id`. |
554
- | `ObjectId`, `Filter`, `BulkWriteOp`, `BulkWriteError`, `OptionalUnlessRequiredId` | Re-exported from `mongodb`. |
555
- | `buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp` | Generic bulk-write op builders — filter/fields in, a shaped op out. |
556
-
557
- **Do I need to update my app?**
558
-
559
- No — purely additive.
560
-
561
- ### 1.3.29 — Client call quota (CP-1500)
562
-
563
- Per-client call quota with usage counters, optional expiration, and configurable threshold/expiry email alerts. Usage lives on clientsConfig; alert config and send-tracking live on clients. TalkPilot Server consumes these getters to block calls when quota is exceeded or expired and to send notification emails.
564
-
565
- **Data model**
566
-
567
- | Location | Field | Purpose |
568
- | --- | --- | --- |
569
- | `clientsConfig.quota` | `totalQuota`, `usedQuota`, `expiresAt?` | Call allowance and consumption. `getClientQuotaState` returns `null` when `totalQuota` is unset (quota disabled for that client). |
570
- | `clients.quota` | `alerts?`, `expiredSent?` | Up to 3 threshold alerts (each with up to 3 recipient emails) and a flag set after the expiry email is sent. |
571
-
572
- **Added**
573
-
574
- | Export | Purpose |
575
- | --- | --- |
576
- | `ClientQuotaUsage` | Usage shape: `totalQuota`, `usedQuota`, optional `expiresAt`. |
577
- | `ClientQuotaSettings` | Alert settings on the `clients` doc: `alerts`, `expiredSent`. |
578
- | `ClientQuotaState` | Merged view returned by `getClientQuotaState` (usage + settings). |
579
- | `QuotaThresholdAlert` / `QuotaAlertInput` | Threshold alert with `thresholdPct`, `recipientEmails`, and optional `thresholdSent` send-tracking. |
580
- | `getClientQuotaState(clientId)` | Read combined quota state; `null` when no quota is configured. |
581
- | `incrementClientQuotaUsage(clientId, amount?)` | Atomically increment `clientsConfig.quota.usedQuota` (default `amount = 1`). No-op when `quota.totalQuota` is absent. |
582
- | `resetClientQuotaUsage(clientId)` | Reset `usedQuota` to `0` and clear alert/expiry send flags via `resetClientQuotaSettings`. |
583
- | `updateQuotaAlertsConfig(clientId, alerts)` | Replace threshold alert config; preserves `thresholdSent` for unchanged thresholds. |
584
- | `markQuotaAlertSent(clientId, alertIndex)` | Idempotently mark a threshold alert as sent; returns whether the update applied. |
585
- | `markQuotaExpiredSent(clientId)` | Idempotently mark the expiry notification as sent; returns whether the update applied. |
586
- | `resetClientQuotaSettings(clientId)` | Clear `expiredSent` and strip `thresholdSent` from alerts (keeps alert definitions). |
587
-
588
- **Do I need to update my app?**
589
-
590
- No — purely additive. TalkPilot Server should upgrade to 1.3.29 (or later) to enforce quota on inbound/outbound calls and to drive threshold/expiry emails via the new getters.
591
-
592
- ### 1.3.32 — Quota `clientDisplayName`
593
-
594
- Optional human-readable account label stored on `clientsConfig.quota` for quota notification emails. TalkPilot Server uses `getClientDisplayName` instead of exposing raw `clientId` in alert/expiry email copy.
595
-
596
- **Changed**
597
-
598
- | Area | What |
599
- | --- | --- |
600
- | `ClientQuotaUsage.clientDisplayName?` | Optional display name on `clientsConfig.quota` — e.g. `"Acme Corp"`. Included in `ClientQuotaState` via `getClientQuotaState`. |
601
-
602
- **Added**
603
-
604
- | Export | Purpose |
605
- | --- | --- |
606
- | `getClientDisplayName(clientId)` | Returns trimmed `quota.clientDisplayName`, or `"-"` when unset, missing, or blank. Never falls back to `clientId`. |
607
-
608
- **Do I need to update my app?**
609
-
610
- No — purely additive. Set `clientsConfig.quota.clientDisplayName` when provisioning quota for a client. **TalkPilot Server** should upgrade to **1.3.32** (or later) to use the label in quota emails.
611
-
612
- ### 1.3.33 — Configuration database & Prompts collection (CP-1560)
613
-
614
- New `configuration` database with a prompts collection, so prompts previously hardcoded in consuming repos (e.g. MIS's `moked_106` street/subject search and transcription prompts) can be stored centrally and edited without a deploy. Ships the **read** path only — documents are seeded/managed manually (e.g. via Compass), not through this package.
615
-
616
- **Added**
617
-
618
- | Export | Purpose |
619
- | --- | --- |
620
- | `configurationMongodbClient` | MongoDB client for the `configuration` database (default name `configuration`, override with `CONFIGURATION_DB_NAME`). |
621
- | `getConfigurationDb` / `setConfigurationDb` / `ConfigurationObjectId` | DB handle accessors and `ObjectId`, matching the other domains. |
622
- | `Prompt` | Document type: `{ _id, name, content, createdAt, updatedAt }`, keyed by unique `name`. |
623
- | `getPromptByName(name)` | Fetch a single prompt by its unique `name`. Returns `null` if absent. |
624
- | `findPrompts(filter?)` | Flexible query over the collection. |
625
- | `getAllPrompts()` | Fetch every prompt. |
626
- | `getPromptsCollection()` | Raw collection access. |
627
-
628
- `ensureDbConnected()` / `disconnectDb()` now also connect/disconnect the configuration client alongside talkpilot/municipal/websitalk.
629
-
630
- **Do I need to update my app?**
631
-
632
- No — purely additive. Consumers opt in by importing the getters above.
633
-
634
- ### 1.3.35 — Prompts fixes: collection name, `productName`, centralized config
635
-
636
- **Breaking**
637
-
638
- | Changed | What |
639
- | --- | --- |
640
- | Collection name | `"Prompts"` → `"prompts"` (lowercase, matching every other collection in core-db). MongoDB collection names are case-sensitive — if you inserted documents into a collection literally named `Prompts` under 1.3.33, move them to `prompts`. |
641
-
642
- **Added**
643
-
644
- | Export | Purpose |
645
- | --- | --- |
646
- | `Prompt.productName` | Required `KnownProductKey` (`"municipal" \| "clinics" \| "websiteTalk"`). Existing documents need this field backfilled. |
647
- | `getPromptsByProduct(productName)` | Fetch all prompts for a given product. |
648
-
649
- **Internal**
650
-
651
- - Configuration-DB env var reads (`MONGO_URI`, `MONGODB_URI`, `CONFIGURATION_DB_NAME`) centralized into `src/config.ts` (`configurationDbConfig`) — no consumer-facing change.
652
-
653
- **Do I need to update my app?**
654
-
655
- Only if you inserted documents into the old `Prompts` (capital P) collection — move them to `prompts`. Also backfill `productName` on any existing prompt documents (e.g. `"municipal"`), since it's now a required field on the type.
656
-
657
- ### 1.3.36 — Merge with `main`
658
-
659
- Publishes the 1.3.33/1.3.35 configuration-DB work alongside the latest `main` — client call-quota, `clientDisplayName`, and bulk-write/streets/departmentSubjects updates (see 1.3.28, 1.3.29, 1.3.32). No new code of its own; this version exists to ship both branches' work together.
660
-
661
- **Do I need to update my app?**
662
-
663
- No — purely additive, same as the versions it combines.
664
-
665
- ### 1.3.37 — Model catalog & internal model settings (CP-1624)
666
-
667
- New `models` and `internalModels` collections under the `configuration` database, so AI model catalogs and cross-service settings previously hardcoded in consuming repos (e.g. TalkPilot Server's realtime/STT model lists and its live transcription model) can be stored centrally and edited without a deploy. Ships the **read** path only, same as `prompts` — documents are seeded/managed manually (e.g. via Compass).
668
-
669
- **Added — `models`**
670
-
671
- | Export | Purpose |
672
- | --- | --- |
673
- | `ModelDoc` (`RealtimeModelDoc \| SttModelDoc`) | Document type discriminated by `type`: `{ _id, modelId, name, description?, available, features?, configDefaults?, createdAt, updatedAt }`, plus `provider` (`RealtimeModelProvider` for `type: "realtime"`, `SttModelProvider` for `type: "stt"`). |
674
- | `MODEL_TYPES`, `REALTIME_MODEL_PROVIDERS`, `STT_MODEL_PROVIDERS` | Known `type`/`provider` value lists the types above are derived from. |
675
- | `getModelByModelId(modelId, type?)` | Fetch a single model by its `modelId`, optionally scoped to a `type`. |
676
- | `getModelsByProvider(provider, type?)` | Fetch all models for a given `provider`, optionally scoped to a `type`. |
677
- | `getModelsByType(type)` | Fetch all models of a given `type`. |
678
- | `getAvailableModelsByType(type)` | Same as above, pre-filtered to `available: true`. |
679
- | `findModels(filter?)` | Flexible query over the collection. |
680
- | `getModelsCollection()` | Raw collection access. |
681
-
682
- **Added — `internalModels`**
683
-
684
- | Export | Purpose |
685
- | --- | --- |
686
- | `InternalModel` | Document type: `{ _id, name, provider, model, config?, createdAt, updatedAt }`, keyed by unique `name` — e.g. a `"transcriptionModel"` document. |
687
- | `getInternalModelByName(name)` | Fetch a single internal model config by its unique `name`. Returns `null` if absent. |
688
- | `findInternalModels(filter?)` | Flexible query over the collection. |
689
- | `getAllInternalModels()` | Fetch every internal model. |
690
- | `getInternalModelsCollection()` | Raw collection access. |
691
-
692
- `ensureDbConnected()` / `disconnectDb()` already covered the configuration client from 1.3.33 — no change there.
693
-
694
- **Do I need to update my app?**
695
-
696
- No — purely additive. Consumers opt in by importing the getters above.
697
-
698
- ### 1.3.38 — Transcription comparison field (CP-1594)
699
-
700
- Added an optional `transcriptionComparison` field to `Call`, for consumers that run side-channel transcription comparisons across multiple providers/models alongside the real `transcription` field.
701
-
702
- **Added**
703
-
704
- | Export | Purpose |
705
- | --- | --- |
706
- | `Call.transcriptionComparison` | Optional `Record<string, TranscriptionSegment[]>` — one entry per `{provider}-{model}` key, each an array of `TranscriptionSegment` in the same shape as `Call.transcription`. |
707
-
708
- **Do I need to update my app?**
709
-
710
- No — purely additive. Existing documents and consumers continue to work unchanged.
711
-
712
- ## 🛠 CI/CD & deployment
713
-
714
- - This package is consumed by Cloud Build-based services (TalkPilot Server, MIS, CIS) as a dependency when Docker images are built. Keep `dist/` in sync with your builds because the compiled artifact is what downstream services install.
715
- - Releases require the shared npm token documented in `DEVELOPMENT.md`; consult that guide for contribution, linking, and token rotation procedures.
716
-
717
- ## Resources
718
-
719
- - [DEVELOPMENT.md](./DEVELOPMENT.md) (setup, tooling, publishing, token management)
720
- - [src/test-utils](src/test-utils) and the `__tests__` folder for examples of `MongoMemoryServer` wiring.
721
-
1
+ L1:# @talkpilot/core-db
2
+
3
+ [NPM Version](https://www.npmjs.com/package/@talkpilot/core-db)
4
+ `@talkpilot/core-db` is the shared TypeScript database package that wires TalkPilot APIs, municipal CRM integrations, and internal tools to a single, type-safe MongoDB surface. Every repo (MIS, CIS, TalkPilot Server, etc.) imports this package to avoid re-implementing connections, collections, or validation helpers.
5
+
6
+ ## Purpose
7
+
8
+ - Provide a reliable, multi-domain MongoDB layer for TalkPilot and municipal data.
9
+ - Export typed getters, vector search helpers, and document factories so services can focus on behavior instead of schema wiring.
10
+ - Manage connection lifecycles, environment configuration, and test helpers from one place so every repo reuses the same plumbing.
11
+
12
+ ## Main Concepts
13
+
14
+ - **Multi-domain clients** – `src/connection.ts` exposes `mongodbClient` (TalkPilot) and `municipalDataMongodbClient`, each of which resolves `MONGO_URI`, DB overrides, and default names.
15
+ - **Domain-specific getters** – `src/talkpilot/` and `src/municipal/` host typed getters (agents, calls, streets, tickets, etc.), vector-search helpers, and service-friendly adapters that keep caller code DRY.
16
+ - **Product-specific clients (future)** – While the package currently exposes the shared TalkPilot + municipal clients, we expect each product (CIS, MIS, TalkPilot Server) to eventually get its own domain-specific client helpers or wrappers so the shared core can remain stable while new consumers add targeted extensions.
17
+ - **Test helpers** – `src/test-utils/` plus `src/__tests__/` reuse `MongoMemoryServer` and shared factories so tests start with clean data regardless of the consuming repo.
18
+ - **Utility layers** – `src/utils/` contains shared validation, pagination, and environment helpers that complement the getters.
19
+ - **Bulk-write helpers** – `src/bulkWrite/` exposes small, domain-agnostic functions (`buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp`) that construct correctly-shaped MongoDB bulk-write operations from a filter and field values — no collection- or domain-specific knowledge required.
20
+ - **Configuration domain** – `src/configuration/` hosts the `configuration` database (a `prompts` collection so far) — a place for cross-service settings that used to be hardcoded in consuming repos, editable without a deploy.
21
+ - **Environment awareness** – Defaults, fallbacks, and `process.env` lookups ensure local, CI, and Cloud Run clients all connect using the right URI/DB names.
22
+
23
+ ## Key Components
24
+
25
+ - `src/connection.ts` – Central connection logic that resolves URIs/DB names from env vars (`MONGO_URI`, `MONGODB_URI`, `TALKPILOT_DB_NAME`, `MUNICIPAL_DB_NAME`) and reuses a single `MongoClient`.
26
+ - `src/talkpilot/` – Call history, agents, flows, sessions, leads, subscriptions, and support helpers exposed as getters plus helper enums/types for each collection.
27
+ - `src/municipal/` – Municipal-specific collections (`cities`, `streets`, `departmentsSubjects`, `tickets`, etc.) plus vector search helpers and Ash Bina helpers used by MIS.
28
+ - `src/utils/` – Shared helpers such as `resolveConnection`, pagination utilities, and schema validation helper functions.
29
+ - `src/bulkWrite/` – Generic bulk-write op constructors (`buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp`) usable with any collection's document type.
30
+ - `src/configuration/` – `configurationMongodbClient` plus the `prompts` collection (`Prompt` type, `getPromptByName`, `findPrompts`, `getAllPrompts`, `getPromptsByProduct`).
31
+ - `src/config.ts` – Centralized `process.env` reads for the configuration domain — add new env-backed fields here instead of reading `process.env` inline elsewhere.
32
+ - `src/test-utils/` and `src/__tests__/` – Utilities that bootstrap `MongoMemoryServer`, expose factories, and make sure Jest environments can stub database calls predictably.
33
+ - `dist/` – Compiled output consumed by downstream repos (CJS + ESM + type defs).
34
+
35
+ ## Domain APIs
36
+
37
+ - **TalkPilot domain** – Imports like `findAgents`, `getFlows`, `findCalls`, and `vectorSearchCalls` live in `src/talkpilot`. These functions are the canonical access pattern for call history, session metadata, and provider configs.
38
+ - **Municipal domain** – Helpers such as `findStreets`, `getMunicipalCities`, `findDepartmentSubjects`, and `createTicket` live under `src/municipal` and feed MIS workflows (street hints, subject matching, Ash Bina tickets).
39
+ - **Configuration domain** – `getPromptByName`, `findPrompts`, `getAllPrompts`, and `getPromptsByProduct` live under `src/configuration` and back MIS's `moked_106` prompt lookups (defaults, overridable per-client via `clientConfig.toolsPrompts`).
40
+
41
+ ## Environment variables
42
+
43
+ | Variable | Purpose | Required |
44
+ |---------------------|-----------------------------------------------------------------------------------|----------|
45
+ | `MONGO_URI` | Primary MongoDB connection string for every domain (overridden by `MONGODB_URI`). | ✅ |
46
+ | `MONGODB_URI` | Alternate connection string used when Mongo needs a second URI parameter. | ✅ |
47
+ | `TALKPILOT_DB_NAME` | Optional override for the TalkPilot database name (defaults from URI path). | ❌ |
48
+ | `MUNICIPAL_DB_NAME` | Optional override for the municipal database name (defaults to `municipal-data`). | ❌ |
49
+ | `CONFIGURATION_DB_NAME` | Optional override for the configuration database name (defaults to `configuration`). | ❌ |
50
+ | `ENV` | Free-form label used in logs/validators (defaults to `unknown`). | ❌ |
51
+
52
+ If you pass a `uri` directly to `mongodbClient.connect()` or `municipalDataMongodbClient.connect()`, the client will prefer that value over the env vars.
53
+
54
+ ## Getting Started
55
+
56
+ ### Prerequisites
57
+
58
+ - Node.js 22.x+ (aligns with downstream services).
59
+ - npm 11+ or Yarn.
60
+ - MongoDB accessible from your environment or a `MongoMemoryServer` for tests.
61
+
62
+ ### Setup
63
+
64
+ 1. Clone the repo and install dependencies:
65
+
66
+ ```bash
67
+ git clone https://github.com/talkpilot/core-db.git
68
+ cd core-db
69
+ npm install
70
+ ```
71
+
72
+ 2. Build the package before using it locally:
73
+
74
+ ```bash
75
+ npm run build
76
+ ```
77
+
78
+ 3. Import `@talkpilot/core-db` from another project by pointing `package.json` at the local path during development or installing the published release.
79
+
80
+ ## Sample `.env`
81
+
82
+ ```
83
+ MONGO_URI=mongodb://localhost:27017
84
+ TALKPILOT_DB_NAME=talkpilot-dev
85
+ MUNICIPAL_DB_NAME=municipal-dev
86
+ CONFIGURATION_DB_NAME=configuration-dev
87
+ ENV=development
88
+ ```
89
+
90
+ Adjust `MONGO_URI` to match the running Mongo instance and configure `talkpilot`/`municipal`/`configuration` DB names if you want to keep them separate.
91
+
92
+ ## Local development
93
+
94
+ 1. Run `npm install`.
95
+ 2. Build the compiled output: `npm run build`.
96
+ 3. Execute tests: `npm run test`.
97
+ 4. Use `npm link` or `npm pack` to consume the freshly built package from other repos (`CIS`, `MIS`, `TalkPilot Server`).
98
+
99
+ ## Development guide
100
+
101
+ `DEVELOPMENT.md` contains the tactical steps for contributors. At a glance:
102
+
103
+ - Node 18+/TypeScript is required (aligns with downstream services).
104
+ - Run `npm install` → `npm run build` after cloning.
105
+ - Use `npm link`/`npm link @talkpilot/core-db` to test the package locally before publishing.
106
+ - When adding getters, define types, implement the function, export it through the domain `index.ts`, and add a corresponding test under the domain’s `__tests__` folder.
107
+ - Always rely on the provided test factories (`src/test-utils/factories`) to seed data so tests remain consistent.
108
+ - Jest with `mongodb-memory-server` is the only execution path we have to verify this core utility—unit tests are the safety net for every change.
109
+
110
+ Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and factory samples.
111
+
112
+ ## 🧪 Testing
113
+
114
+ - `npm run test` – Jest suite (factories, utils, integration mocks) powered by `mongodb-memory-server`.
115
+ - Tests rely on `src/__tests__/setup.ts` to bootstrap the in-memory Mongo instances and wire shared factories/helpers before each run.
116
+ - When adding getters, helpers, or domain logic, create focused coverage inside the consuming domain’s `__tests__/` folder and use the provided factories to keep fixtures consistent.
117
+
118
+ `@talkpilot/core-db` does not run in a product UI or feature branch—unit tests are the *only* reliable execution path to ensure your changes work. Every change must ship with a unit test so downstream repos can upgrade without surprises; treat the test suite as the canonical safety net for this core utility package.
119
+
120
+ ## 🧹 Lint & build verification
121
+
122
+ - `npm run lint` – Run ESLint over `src/**/*.{ts,tsx}`.
123
+ - `npm run format` – Format the source files with Prettier.
124
+ - `npm run build` – Compile TypeScript and emit `dist/` (used by downstream consumers).
125
+
126
+ ## ✅ Pre-push checklist
127
+
128
+ 1. `npm run build`.
129
+ 2. `npm run test`.
130
+ 3. `npm run format`.
131
+
132
+ ## Publishing & release notes
133
+
134
+ - Releases are handled by `npm version <patch|minor|major>` followed by `npm publish`. The package is a **private `@talkpilot` dependency**, so every contributor must install the shared npm automation token into their global `~/.npmrc` before running publish or `npm install`.
135
+ - The shared token is rotated periodically—if you see authentication failures, request the refreshed token, update your `~/.npmrc`, and retry. Never commit credentials to source control.
136
+ - After publishing, downstream repos (`CIS`, `MIS`, `TalkPilot Server`, etc.) should run `npm update @talkpilot/core-db` so they receive the latest helpers/bug fixes.
137
+ - Cloud Build & Cloud Run jobs that depend on this package pick up the new version the next time they rebuild their container; the services pull the compiled `dist/` output and type definitions when installing the dependency.
138
+
139
+ - Release process, when to publish, branch hygiene, and the function-signature versioning policy: see [`DEVELOPMENT.md`](./DEVELOPMENT.md).
140
+
141
+ ### Version history
142
+
143
+ | Version | Note |
144
+ |---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
145
+ | 1.1.9 | Maintenance release (build, test, format). |
146
+ | 1.3.4 | Added new statistics getters for call & ticket dashboards (CP-149): summary, trend, hourly, and routing for calls, plus open/draft/subject ticket stats. **Removed** the legacy getters `getTicketsCountByCityAndDateRange` and `getTicketsSubjectStats`. |
147
+ | 1.3.5 | Added the `muniIssues` collection & module (CP-1115): the `MuniIssue` document type, `createMuniIssue` (accepts a caller-supplied `_id` for a two-way Jira link), `generateMuniIssueId`, `getMuniIssueById` / `getMuniIssueByJiraKey`, a `$jsonSchema` validator with indexes (unique `jira.key`), and `ensureMuniIssuesCollection` to provision it at boot. |
148
+ | 1.3.6 | Added `contextNotes` and `products` modules under `src/talkpilot/`. |
149
+ | 1.3.7 | Added `disableGenericPrompt` optional boolean field to the `Flow` type and schema (CP-704). |
150
+ | 1.3.8 | Ticket-count Map getters (CP-1200): deprecated `string[]` ticket getters and `CallsStatsFilter` fields, added `Map<string, number>` replacements; fixed ticket counting in `aggregateCallsSummary`. |
151
+ | 1.3.9 | Fixed wrap-around hour filter boundary guards (CP-1166): excluded first-day morning calls and last-day evening calls from wrap-around windows. |
152
+ | 1.3.10 | Added optional `isDraft` flag to `Ticket` (CP-1390): explicit draft marking with legacy fallback for existing tickets. |
153
+ | 1.3.11 | Fixed pre-existing broken type declaration import in `clientsConfig.types.d.ts` that caused consumer `tsc` builds to fail. |
154
+ | 1.3.12 | Added `callsWithTickets` to `CallsSummaryAggregation` (CP-1200): distinct call count with at least one open ticket, enabling accurate `ticketOpenRate` and `not_opened` calculations in consumers. |
155
+ | 1.3.13 | Faulty release (redundant). Published with `Flow.useRedisTranscription` at the flow level; superseded by 1.3.14. |
156
+ | 1.3.14 | Added `FlowTool.useRedisTranscription` optional flag to control whether cached Redis transcriptions are used (defaults to `false`). |
157
+ | 1.3.15 | Multi-scan support for WebsiteTalk (CP-1372): `websiteUrls` collection, `Scan.websiteUrlId`, `OVERWRITTEN` status, `activeScanId` on `WebsiteTalkProduct`. **Breaking:** `Scan.baseUrl` removed; `getActiveScanStatus` removed. |
158
+ | 1.3.16 | Refactored WebsiteTalk scan status constants (CP-1372): `SCAN_STATUSES` object map, `FINISHED_SCAN_STATUSES` derived from it, `isInProgressScan` moved to `scans.utils`. No breaking API changes. |
159
+ | 1.3.17 | Twilio call-status semantics for Websitalk dashboard: `inCallCount` KPI (`in-progress` + `answered`), `busy` is line-busy only; `updateCallStatusByCallSid`; expanded `CallStatus` union; `timeSavedMinutes` from `completed` only. |
160
+ | 1.3.18 | WebsiteTalk multi-website API (CP-1372): ships `websiteUrls` module, scan getters by `websiteUrlId`, `activeScanId` getters on `clientsConfig`. **Note:** 1.3.17 did not include these — they landed after merge. **Breaking:** `WebsiteTalkProduct.defaultBaseUrl` removed from type. |
161
+ | 1.3.19 | WebsiteTalk flow provisioning (WTIS activate-scan): optional `flowId` on `WebsiteTalkProduct`; `bindClientPhoneToFlow(clientId, flowId)` sets `flow_id` on the client's primary `phone_numbers` document so inbound calls route to the provisioned TalkPilot flow. |
162
+ | 1.3.20 | `FINAL_STATUSES` constant for terminal Twilio call statuses (`no-answer`, `completed`, `busy`, `failed`, `canceled`) in `calls.constants`. |
163
+ | 1.3.21 | Added `ToolExecutionStep` type, `steps` field to `ToolExecution`, and `pushToolExecution` getter (CP-1093). Added `ToolExecutionStepLevel` named type and `TOOL_EXECUTIONS_DEFAULT_LIMIT`/`SKIP` constants. Widened `ToolExecutionStep.data` to `Record<string, unknown> \| string` — allows plain string steps alongside structured JSON. Added optional `ToolExecutionStep.payload` for structured drill-down data. |
164
+ | 1.3.22 | `CallsFilterParams.status` typed as `CallStatus` instead of `string` — aligns call-query filters with the Twilio status union from 1.3.17. |
165
+ | 1.3.23 | Merge of 1.3.21 and 1.3.22 — combines the `ToolExecutionStep`/`steps`/`pushToolExecution` work (CP-1093) with the `CallsFilterParams.status: CallStatus` fix. Adds `CallStatusValues` (const object) with `CallStatus` and `ALL_CALL_STATUSES` derived from it. `CallStatus` still does not include `"redirected"` — tracked separately. |
166
+ | 1.3.24 | **Breaking:** removed `flowId` from `WebsiteTalkProduct` — flow source of truth is `phone_numbers.flow_id`. Added `getPrimaryPhoneFlowId(clientId)`. |
167
+ | 1.3.25 | Added `disconnectDb()` to close all MongoDB clients opened by `ensureDbConnected()` — for one-shot scripts that must exit cleanly. |
168
+ | 1.3.28 | Soft-delete (`isActive`) on Streets/DepartmentSubjects, new bulk-write getters, MongoDB type re-exports, and the generic `bulkWrite` op-builder module. |
169
+ | 1.3.29 | Added client call-quota module (CP-1500): `ClientConfig.quota` for usage limits (`totalQuota`, `usedQuota`, `expiresAt`), alert settings on `clients`, and getters for state, increment/reset, threshold alerts, and expiry notification tracking. |
170
+ | 1.3.32 | `clientDisplayName` lives on `clientsConfig.quota` (not top-level). `getClientDisplayName` returns `"-"` when unset; never exposes `clientId`. |
171
+ | 1.3.33 | Added `configuration` database module (CP-1560): `configurationMongodbClient` + a read-only `Prompts`-style collection for prompts previously hardcoded in consuming repos (e.g. MIS). |
172
+ | 1.3.35 | Fixed the configuration collection name (`Prompts` → `prompts`, matches the lowercase convention used elsewhere). **Breaking** if you inserted documents into a collection literally named `Prompts`. Added `Prompt.productName` (required) + `getPromptsByProduct`. Centralized configuration-DB env var reads into `src/config.ts`. |
173
+ | 1.3.36 | Publish combining the 1.3.33/1.3.35 configuration-DB work with the latest `main` (client quota + `clientDisplayName` + bulk-write/streets/departmentSubjects updates — see 1.3.28/1.3.29/1.3.32). No new code of its own. |
174
+ | 1.3.37 | Added `models` and `internalModels` collections under `configuration` (CP-1624): realtime/stt model catalog (`ModelDoc`, `getModelByModelId`, `getModelsByProvider`, `getModelsByType`, `getAvailableModelsByType`) and a name-keyed settings store (`InternalModel`, `getInternalModelByName`) for cross-service config previously hardcoded in consuming repos (e.g. TalkPilot Server's realtime/STT catalogs and its live transcription model). Read-only, same as `prompts` — documents are seeded/managed manually. |
175
+ | 1.3.38 | Added optional `transcriptionComparison` field to `Call` (CP-1594): per-`{provider}-{model}` side-channel transcription comparison results, same segment shape as `Call.transcription`. |
176
+
177
+ ### 1.1.9
178
+
179
+ 1. `npm run build`.
180
+ 2. `npm run test`.
181
+ 3. `npm run format`.
182
+
183
+ ### 1.3.4 — Call & ticket statistics (CP-149)
184
+
185
+ New call statistics getters for dashboards (summary, trend, hourly, routing) and ticket statistics scoped to the same date range (open tickets, draft tickets, subject breakdowns).
186
+
187
+ **Removed**
188
+
189
+ | Removed | Replacement |
190
+ |-------------------------------------|-----------------------------------------------------------------------------------------------------------------|
191
+ | `getTicketsCountByCityAndDateRange` | `aggregateCallsSummary` + `findCallSidTicketCountsByCity` — note: returns `Map<string, number>`, not `string[]` |
192
+ | `getTicketsSubjectStats` | `findSubjectsByCityAndDateRange` |
193
+ | `SubjectStatsItem` | `SubjectItem` |
194
+
195
+ **Do I need to update my app?**
196
+
197
+ Yes — if you used any of the removed functions above.
198
+
199
+ ### 1.3.5 — Muni issues (CP-1115)
200
+
201
+ New `muniIssues` module under `src/municipal/` for issues reported from the call-log screen. The document is written to the municipal DB after its Jira ticket is created.
202
+
203
+ **Added**
204
+
205
+ | Export | Purpose |
206
+ |----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
207
+ | `MuniIssue` / `CreateMuniIssueInput` | Document type and insert-input type (`issueContent` + `jira` domains). |
208
+ | `createMuniIssue(input, id)` | Insert an issue; requires a caller-supplied `_id` from MIS (via `generateMuniIssueId`) so it matches the id embedded in the Jira ticket (two-way link). |
209
+ | `generateMuniIssueId()` | Pre-generate the `_id` to pass to `createMuniIssue`. |
210
+ | `getMuniIssueById` / `getMuniIssueByJiraKey` | Lookups by our id or by the Jira key. |
211
+ | `ensureMuniIssuesCollection()` | Provision the `$jsonSchema` validator and indexes (unique `jira.key`); run once at MIS boot. |
212
+
213
+ **Do I need to update my app?**
214
+
215
+ No — purely additive. New consumers (MIS) import these from `@talkpilot/core-db`.
216
+
217
+ ### 1.3.6 — Context Notes & Products
218
+
219
+ **Context Notes** — new `contextNotes` collection under `src/talkpilot/` for per-client, per-product notes injected into AI calls at runtime. Each document holds a `systemPrompt` and a list of time-bounded entries (`activeFrom`, `expiresAt`). Two setters with split ownership: `setContextNoteEntries` for the notes list and `setContextNoteConfig` for `systemPrompt` and `product`.
220
+
221
+ **Products** — new `products` collection under `src/talkpilot/` cataloguing TalkPilot products. Each document has a stable `name` and an optional `displayName` locale map (`Record<string, string>`) for UI display.
222
+
223
+ **Added**
224
+
225
+ | Export | Purpose |
226
+ |----------------------------------------------|-----------------------------------------------------------------|
227
+ | `getContextNotes(clientId, product)` | Fetch context note documents for a client/product pair. |
228
+ | `createContextNote(input)` | Insert a new context note document. |
229
+ | `setContextNoteEntries(id, clientId, notes)` | Replace the notes list on an existing document. |
230
+ | `setContextNoteConfig(id, clientId, config)` | Update `systemPrompt` and/or `product` on an existing document. |
231
+ | `getAllProducts()` | Fetch the full product catalogue. |
232
+
233
+ **Do I need to update my app?**
234
+
235
+ No — purely additive.
236
+
237
+ ### 1.3.7 — Generic prompt control (CP-704)
238
+
239
+ Added an optional boolean field to the `Flow` type and MongoDB schema.
240
+
241
+ **Added**
242
+
243
+ | Export | Purpose |
244
+ |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------|
245
+ | `Flow.disableGenericPrompt` | Optional `boolean`. When `true`, disables the generic prompt for the flow. Existing flows without this field continue to work unchanged. |
246
+
247
+ **Do I need to update my app?**
248
+
249
+ No — the field is optional and fully backwards-compatible.
250
+
251
+ ### 1.3.8 — Ticket-count Map getters (CP-1200)
252
+
253
+ Adds `Map<string, number>` ticket getters that return per-call ticket counts. The old `string[]` getters and filter fields are kept and marked `@deprecated`.
254
+
255
+ **Deprecated → Replacement**
256
+
257
+ | Deprecated | Replacement |
258
+ |---------------------------------------------|--------------------------------------------------------------|
259
+ | `findCallSidsWithTicketsByCity` | `findCallSidTicketCountsByCity` → `Map<string, number>` |
260
+ | `findCallSidsWithDraftTicketsByCity` | `findCallSidDraftTicketCountsByCity` → `Map<string, number>` |
261
+ | `CallsStatsFilter.callSidsWithTickets` | `CallsStatsFilter.callSidTicketCounts` |
262
+ | `CallsStatsFilter.callSidsWithDraftTickets` | `CallsStatsFilter.callSidDraftTicketCounts` |
263
+
264
+ **Do I need to update my app?**
265
+
266
+ No — the old fields still compile. Migrate when convenient.
267
+
268
+ ### 1.3.9 — Wrap-around hour filter boundary guards (CP-1166)
269
+
270
+ When `hourFrom` > `hourTo` (e.g. 23:00–13:00), two silent miscounting bugs existed:
271
+
272
+ - **First-day morning**: calls before `hourTo` on the first day (e.g. 08:00 on Jun 8) were counted even though the window starts at `hourFrom` that day. Fixed by adding `dateLocal > startStr` to the after-midnight leg.
273
+ - **Last-day evening**: calls at or after `hourFrom` on the last day (e.g. 23:30 on Jun 9) were counted even though the window ends at `hourTo` that day. Fixed by adding `dateLocal < endStr` to the before-midnight leg.
274
+
275
+ **Affects:** `aggregateCallsTrend`, `aggregateCallsSummary`, `aggregateCallsHourlyByRange`, `aggregateCallsRouting`, `findFilteredCallSids`, `findSubjectsByCityAndDateRange`.
276
+
277
+ **Do I need to update my app?**
278
+
279
+ No API changes — both fixes correct silent miscounting. Upgrading is recommended if you use a wrap-around hour window.
280
+
281
+ ### 1.3.10 — Ticket draft flag (CP-1390)
282
+
283
+ Added an optional `isDraft` boolean field to the `Ticket` type.
284
+
285
+ **Added**
286
+
287
+ | Export | Purpose |
288
+ |------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
289
+ | `Ticket.isDraft` | Optional `boolean`. When `true`, the ticket is a draft. When `false`, it is not. When absent (legacy tickets), draft detection falls back to the previous `event_subject_id` heuristic. |
290
+
291
+ **Affects:** `findCallSidDraftTicketCountsByCity`, `findCallSidsWithDraftTicketsByCity` (draft filtering in ticket statistics).
292
+
293
+ **Do I need to update my app?**
294
+
295
+ No — purely additive. Existing tickets without `isDraft` continue to work unchanged. New consumers (MIS) can pass `isDraft: true` when creating a draft ticket.
296
+
297
+ ### 1.3.11 — Fix clientsConfig type declaration import
298
+
299
+ Fixed a pre-existing broken import path in the published `clientsConfig.types.d.ts` (introduced in an earlier release, unrelated to 1.3.10). Consumer TypeScript builds could fail with:
300
+
301
+ `Cannot find module 'src/utils/shared.types' or its corresponding type declarations.`
302
+
303
+ The import now uses a relative path (`../../utils/shared.types`) so `tsc` resolves it correctly from `node_modules/@talkpilot/core-db/dist/`.
304
+
305
+ **Do I need to update my app?**
306
+
307
+ Yes — upgrade to 1.3.11 if your build failed with the error above (affects any version that shipped the broken declaration). No API or behavior changes otherwise.
308
+
309
+ ### 1.3.12 — Calls-with-tickets count (CP-1200)
310
+
311
+ Added `callsWithTickets` to `CallsSummaryAggregation` — the number of distinct calls that opened at least one ticket. Use this field (instead of `openTickets`) to compute call-level rates and "calls without a ticket" counts.
312
+
313
+ **Do I need to update my app?**
314
+
315
+ Yes — replace `openTickets` with `callsWithTickets` wherever you compute `ticketOpenRate` or `not_opened`.
316
+
317
+ ### 1.3.13 — Faulty release
318
+
319
+ This release incorrectly placed `useRedisTranscription` on `Flow` instead of `FlowTool`. It is redundant and should be skipped.
320
+
321
+ ### 1.3.14 — Redis transcription flag
322
+
323
+ Added an optional `FlowTool.useRedisTranscription` boolean that tells consumers whether to read transcriptions from Redis. Defaults to `false` when omitted.
324
+
325
+ **Do I need to update my app?**
326
+
327
+ No — this flag is optional. Only update if you want to opt into the Redis transcription path.
328
+
329
+ ### 1.3.15 — Multi-scan configuration (CP-1372)
330
+
331
+ Adds `websiteUrls` collection (CRUD getters), migrates scans from `baseUrl` to `websiteUrlId`, adds `OVERWRITTEN` scan status, and replaces `defaultBaseUrl`/`logoUrl` on `WebsiteTalkProduct` with `activeScanId` (+ getters).
332
+
333
+ **Breaking**
334
+
335
+ | Removed / changed | Replacement |
336
+ | --- | --- |
337
+ | `Scan.baseUrl` | `Scan.websiteUrlId` |
338
+ | `WebsiteTalkProduct.defaultBaseUrl` | `websiteUrls` collection |
339
+ | `getActiveScanStatus(clientId)` | `getInProgressScanByWebsiteUrl`, `findInProgressScansByClient` |
340
+
341
+ **Do I need to update my app?**
342
+
343
+ Yes — WTIS, CoreBrain, and CoreCrawler must adopt `websiteUrlId` and the new getters before upgrading.
344
+
345
+ ### 1.3.16 — Scan status constants refactor (CP-1372)
346
+
347
+ Centralizes scan status values under a single `SCAN_STATUSES` object map and derives terminal statuses from it.
348
+
349
+ **Changed**
350
+
351
+ | Area | What |
352
+ | --- | --- |
353
+ | `SCAN_STATUSES` | Object map (`SCAN_STATUSES.CHECKING`, `SCAN_STATUSES.COMPLETED`, …) instead of separate exported string constants. |
354
+ | `FINISHED_SCAN_STATUSES` | Derived from `SCAN_STATUSES` (`COMPLETED`, `FAILED`, `OVERWRITTEN`). |
355
+ | `isInProgressScan` | Moved to `scans.utils.ts` (exported from `scans` index). |
356
+ | `ScanStatus` type | Derived from `(typeof SCAN_STATUSES)[keyof typeof SCAN_STATUSES]`. |
357
+
358
+ **Do I need to update my app?**
359
+
360
+ No — behavior is unchanged. If you imported removed aliases like `COMPLETED_SCAN_STATUS`, switch to `SCAN_STATUSES.COMPLETED` (or keep using string literals / `ScanStatus` type).
361
+
362
+ ### 1.3.17 — Twilio call-status semantics (CP-1521)
363
+
364
+ Aligns dashboard KPIs and call-status updates with Twilio semantics so in-call counts update in real time.
365
+
366
+ **Added**
367
+
368
+ | Export | Purpose |
369
+ | --- | --- |
370
+ | `updateCallStatusByCallSid(callSid, status)` | Set the current call status by `callSid`. |
371
+ | `IN_CALL_STATUSES` | `["in-progress", "answered"]` — statuses counted as in-call. |
372
+ | `DashboardSummaryMetrics.inCallCount` | Replaces `busyCount`; counts in-progress + answered calls. |
373
+
374
+ **Changed**
375
+
376
+ | Area | What |
377
+ | --- | --- |
378
+ | Dashboard KPIs | `busyCount` → `inCallCount`; `busy` is line-busy only, not in-call. |
379
+ | `timeSavedMinutes` | Computed from `completed` calls only. |
380
+ | `CallStatus` union | Expanded for Twilio-aligned statuses. |
381
+
382
+ **Do I need to update my app?**
383
+
384
+ Yes — if you read `busyCount` from dashboard KPIs, switch to `inCallCount`.
385
+
386
+ ### 1.3.18 — WebsiteTalk multi-website API (CP-1372)
387
+
388
+ Ships the full persistence API for multi-website / multi-scan. Versions 1.3.15–1.3.16 documented the design; **1.3.17 did not export these symbols** (CP-1372 merged into main after the 1.3.17 release). Upgrade to **1.3.18** if you see missing-export errors such as `getActiveScanId`, `getWebsiteUrlById`, or `WebsiteUrlDoc`.
389
+
390
+ **`websiteUrls` module**
391
+
392
+ | Export | Purpose |
393
+ | --- | --- |
394
+ | `WebsiteUrl` / `WebsiteUrlDoc` / `CreateWebsiteUrlInput` | Document types. |
395
+ | `getWebsiteUrlsCollection()` | Collection access. |
396
+ | `getWebsiteUrlsByClient(clientId)` | All websites for a client. |
397
+ | `getWebsiteUrlById(id)` | Lookup by id. |
398
+ | `findWebsiteUrls(filter?)` | Flexible query. |
399
+ | `createWebsiteUrl({ clientId, name, baseUrl })` | Create. |
400
+ | `updateWebsiteUrl(id, updates)` | Update `name` / `baseUrl`. |
401
+ | `deleteWebsiteUrl(id)` | Delete by id. |
402
+
403
+ **`clientsConfig` — selected scan**
404
+
405
+ | Export | Purpose |
406
+ | --- | --- |
407
+ | `getActiveScanId(clientId)` | Read `products.websiteTalk.activeScanId`. |
408
+ | `updateActiveScanId(clientId, scanId)` | Set the active scan for search. |
409
+ | `clearActiveScanId(clientId)` | Unset `activeScanId`. |
410
+
411
+ **`scans` — by `websiteUrlId`**
412
+
413
+ | Export | Purpose |
414
+ | --- | --- |
415
+ | `getScanById(id)` | Lookup by id. |
416
+ | `getScansByWebsiteUrl(websiteUrlId)` | All scans for a website. |
417
+ | `getLatestScanByWebsiteUrl(websiteUrlId)` | Most recent scan. |
418
+ | `getInProgressScanByWebsiteUrl(websiteUrlId)` | Latest scan if still in progress. |
419
+ | `findInProgressScansByClient(clientId)` | All in-progress scans for a client. |
420
+ | `hasScansForWebsiteUrl(websiteUrlId)` | Whether any scans exist. |
421
+ | `getLatestCompletedScanByWebsiteUrl(websiteUrlId)` | Most recent `COMPLETED` scan. |
422
+ | `updateScanDoc(scanId, updates)` | Partial update (e.g. mark `OVERWRITTEN`). |
423
+ | `deleteScansByWebsiteUrl(websiteUrlId)` | Delete all scans for a website. |
424
+
425
+ **Breaking / type changes**
426
+
427
+ | Removed | Replacement |
428
+ | --- | --- |
429
+ | `WebsiteTalkProduct.defaultBaseUrl` | `websiteUrls` collection (`name`, `baseUrl`) |
430
+ | `Scan.baseUrl` | `Scan.websiteUrlId` (see 1.3.15) |
431
+
432
+ **`OVERWRITTEN` scan status**
433
+
434
+ - `OVERWRITTEN` is part of `ScanStatus` / `SCAN_STATUSES`.
435
+ - Marking previous `COMPLETED` scans as overwritten is **not** done in `createScanDoc` — implement in the service layer (e.g. via `updateScanDoc`).
436
+
437
+ **Not in core-db (service layer)**
438
+
439
+ - `resolveActiveWebsiteContext` — join `activeScanId` → scan → websiteUrl.
440
+ - Migration from legacy `defaultBaseUrl`.
441
+
442
+ **Do I need to update my app?**
443
+
444
+ Yes — WTIS, CoreBrain, and CoreCrawler should upgrade to **1.3.18** and import the symbols above from `@talkpilot/core-db`. Stop reading `defaultBaseUrl` from `WebsiteTalkProduct`; use `websiteUrls` instead.
445
+
446
+ ### 1.3.19 — WebsiteTalk flow provisioning (WTIS activate-scan)
447
+
448
+ Persists the TalkPilot flow id on the client product config and links the client's primary phone number to that flow so inbound calls use the WebsiteTalk flow after `activate-scan`.
449
+
450
+ **`clientsConfig` — `WebsiteTalkProduct`**
451
+
452
+ | Field | Purpose |
453
+ | --- | --- |
454
+ | `WebsiteTalkProduct.flowId?` | Optional TalkPilot flow `_id` (hex string). Set by WTIS after `POST /flows/add_new_flow`; reused on later activations via `PUT /flows/edit_flow/:id`. |
455
+
456
+ **`phone_numbers`**
457
+
458
+ | Export | Purpose |
459
+ | --- | --- |
460
+ | `bindClientPhoneToFlow(clientId, flowId)` | Updates the **primary** `phone_numbers` row for `clientId`, setting `flow_id` to the given TalkPilot flow. Throws if no primary phone exists. |
461
+
462
+ **Typical service-layer flow (WTIS)**
463
+
464
+ 1. Build flow payload from template + `companyInfo` (generated at activate time).
465
+ 2. Create or update the flow via TalkPilot Server API (`add_new_flow` / `edit_flow`).
466
+ 3. On first create: `updateProductConfig(clientId, "websiteTalk", { flowId })`.
467
+ 4. `bindClientPhoneToFlow(clientId, flowId)` — ensure the phone routes to the flow.
468
+ 5. `updateActiveScanId(clientId, scanId)` — point search at the activated scan.
469
+
470
+ **Not in core-db (service layer)**
471
+
472
+ - Flow template substitution, Claude `companyInfo` generation, Firebase Storage template download, TalkPilot flow create/update HTTP calls.
473
+
474
+ **Do I need to update my app?**
475
+
476
+ No — purely additive. **WTIS** should upgrade to **1.3.19** (or later) and import `bindClientPhoneToFlow` plus `WebsiteTalkProduct.flowId` when implementing activate-scan flow provisioning.
477
+
478
+ ### 1.3.20 — `FINAL_STATUSES` call-status constant
479
+
480
+ Centralizes terminal Twilio call statuses so consumers (e.g. TalkPilot Server `callResultService`) don't duplicate the list locally.
481
+
482
+ **Added**
483
+
484
+ | Export | Purpose |
485
+ | --- | --- |
486
+ | `FINAL_STATUSES` | `["no-answer", "completed", "busy", "failed", "canceled"]` — statuses where no further Twilio callbacks are expected. Pair with `IN_CALL_STATUSES` for live vs terminal semantics. |
487
+
488
+ **Do I need to update my app?**
489
+
490
+ No — purely additive. Replace local `FINAL_STATUSES` arrays with `import { FINAL_STATUSES } from "@talkpilot/core-db"` when convenient.
491
+
492
+ ### 1.3.21 — Tool execution steps & push getter (CP-1093)
493
+
494
+ Added `ToolExecutionStep` type, `steps` field on `ToolExecution`, `pushToolExecution` getter, named `ToolExecutionStepLevel` type, and pagination constants.
495
+
496
+ **Added**
497
+
498
+ | Export | Purpose |
499
+ | --- | --- |
500
+ | `ToolExecutionStepLevel` | Named type: `"info" \| "warn" \| "error"`. |
501
+ | `ToolExecution.steps` | Optional `ToolExecutionStep[]`. Ordered log of intermediate steps within a tool call (e.g. `audio_enrichment`, `google_places`, `subject_classification`). Absent on executions recorded before this version. |
502
+ | `ToolExecutionStep.payload` | Optional `Record<string, unknown>`. Structured data for UI drill-down, alongside the human-readable `data` field. |
503
+ | `pushToolExecution(callSid, execution)` | Append a `ToolExecution` to the call's `toolExecutions` array via `$push`. |
504
+ | `getToolExecutionsByCallSid(callSid, opts?)` | Fetch the `toolExecutions` array for a call. `opts.skip` and `opts.limit` (default `TOOL_EXECUTIONS_DEFAULT_LIMIT` = 50) support pagination. Returns `[]` when the call has no executions or does not exist. |
505
+ | `TOOL_EXECUTIONS_DEFAULT_LIMIT` | `50` — default page size for `getToolExecutionsByCallSid`. |
506
+ | `TOOL_EXECUTIONS_DEFAULT_SKIP` | `0` — default skip for `getToolExecutionsByCallSid`. |
507
+
508
+ **Do I need to update my app?**
509
+
510
+ No — purely additive. All new fields are optional and existing documents continue to work unchanged.
511
+
512
+ ### 1.3.22 — `CallsFilterParams.status` type alignment
513
+
514
+ Tightens the `status` filter field on `CallsFilterParams` from `string` to `CallStatus` so call-query consumers get compile-time validation against the Twilio-aligned status union introduced in 1.3.17.
515
+
516
+ **Changed**
517
+
518
+ | Area | What |
519
+ | --- | --- |
520
+ | `CallsFilterParams.status` | `string` → `CallStatus` |
521
+
522
+ **Do I need to update my app?**
523
+
524
+ Only if you pass a non-`CallStatus` string to `CallsFilterParams.status` — fix the value or cast. No runtime behavior change.
525
+
526
+ ### 1.3.23 — Merge of 1.3.21 and 1.3.22, plus `CallStatusValues`
527
+
528
+ Combines the CP-1093 tool-execution-steps work (1.3.21) with the `CallsFilterParams.status` type fix (1.3.22); both were published independently from diverging branches.
529
+
530
+ **Added**
531
+
532
+ | Export | Purpose |
533
+ | --- | --- |
534
+ | `CallStatusValues` | `as const` object mapping named keys (`Completed`, `Failed`, ...) to the 9 raw Twilio-aligned status strings — gives enum-like dot access (`CallStatusValues.Completed`) while `CallStatus` stays a plain string-literal union (no breaking change for existing `status === "completed"` comparisons). |
535
+ | `CallStatus` | Now derived from `CallStatusValues` (`(typeof CallStatusValues)[keyof typeof CallStatusValues]`) instead of a hand-written union — single source of truth. |
536
+ | `ALL_CALL_STATUSES` | `CallStatus[]` — `Object.values(CallStatusValues)`, for runtime validation of raw input (e.g. HTTP query params) against `CallStatus`. |
537
+
538
+ **Do I need to update my app?** No — `CallStatus` is structurally identical to before (same 9 string literals); this is a source-only refactor.
539
+
540
+ `CallStatus` still does not include `"redirected"` — tracked separately.
541
+
542
+ ### 1.3.28 — Soft-delete support and generic bulk-write helpers
543
+
544
+ Adds an `isActive` soft-delete convention, bulk-write getters for Streets/DepartmentSubjects, MongoDB type re-exports, and a generic bulk-write op-builder module.
545
+
546
+ **Added**
547
+
548
+ | Export | Purpose |
549
+ | --- | --- |
550
+ | `Street.isActive` / `DepartmentSubject.isActive` | Optional soft-delete flag; `createStreet` defaults it to `true`. |
551
+ | `bulkWriteStreets` / `bulkWriteDepartmentsSubjects` | Passthrough bulk-write for each collection. |
552
+ | `findDepartmentSubjectsByFilter` | Query subjects by an arbitrary filter. |
553
+ | `updateDepartmentSubjectActive` | Set `isActive` on a subject by `_id`. |
554
+ | `ObjectId`, `Filter`, `BulkWriteOp`, `BulkWriteError`, `OptionalUnlessRequiredId` | Re-exported from `mongodb`. |
555
+ | `buildSetOp`, `buildUpsertOp`, `buildInsertOp`, `buildDeleteOp` | Generic bulk-write op builders — filter/fields in, a shaped op out. |
556
+
557
+ **Do I need to update my app?**
558
+
559
+ No — purely additive.
560
+
561
+ ### 1.3.29 — Client call quota (CP-1500)
562
+
563
+ Per-client call quota with usage counters, optional expiration, and configurable threshold/expiry email alerts. Usage lives on clientsConfig; alert config and send-tracking live on clients. TalkPilot Server consumes these getters to block calls when quota is exceeded or expired and to send notification emails.
564
+
565
+ **Data model**
566
+
567
+ | Location | Field | Purpose |
568
+ | --- | --- | --- |
569
+ | `clientsConfig.quota` | `totalQuota`, `usedQuota`, `expiresAt?` | Call allowance and consumption. `getClientQuotaState` returns `null` when `totalQuota` is unset (quota disabled for that client). |
570
+ | `clients.quota` | `alerts?`, `expiredSent?` | Up to 3 threshold alerts (each with up to 3 recipient emails) and a flag set after the expiry email is sent. |
571
+
572
+ **Added**
573
+
574
+ | Export | Purpose |
575
+ | --- | --- |
576
+ | `ClientQuotaUsage` | Usage shape: `totalQuota`, `usedQuota`, optional `expiresAt`. |
577
+ | `ClientQuotaSettings` | Alert settings on the `clients` doc: `alerts`, `expiredSent`. |
578
+ | `ClientQuotaState` | Merged view returned by `getClientQuotaState` (usage + settings). |
579
+ | `QuotaThresholdAlert` / `QuotaAlertInput` | Threshold alert with `thresholdPct`, `recipientEmails`, and optional `thresholdSent` send-tracking. |
580
+ | `getClientQuotaState(clientId)` | Read combined quota state; `null` when no quota is configured. |
581
+ | `incrementClientQuotaUsage(clientId, amount?)` | Atomically increment `clientsConfig.quota.usedQuota` (default `amount = 1`). No-op when `quota.totalQuota` is absent. |
582
+ | `resetClientQuotaUsage(clientId)` | Reset `usedQuota` to `0` and clear alert/expiry send flags via `resetClientQuotaSettings`. |
583
+ | `updateQuotaAlertsConfig(clientId, alerts)` | Replace threshold alert config; preserves `thresholdSent` for unchanged thresholds. |
584
+ | `markQuotaAlertSent(clientId, alertIndex)` | Idempotently mark a threshold alert as sent; returns whether the update applied. |
585
+ | `markQuotaExpiredSent(clientId)` | Idempotently mark the expiry notification as sent; returns whether the update applied. |
586
+ | `resetClientQuotaSettings(clientId)` | Clear `expiredSent` and strip `thresholdSent` from alerts (keeps alert definitions). |
587
+
588
+ **Do I need to update my app?**
589
+
590
+ No — purely additive. TalkPilot Server should upgrade to 1.3.29 (or later) to enforce quota on inbound/outbound calls and to drive threshold/expiry emails via the new getters.
591
+
592
+ ### 1.3.32 — Quota `clientDisplayName`
593
+
594
+ Optional human-readable account label stored on `clientsConfig.quota` for quota notification emails. TalkPilot Server uses `getClientDisplayName` instead of exposing raw `clientId` in alert/expiry email copy.
595
+
596
+ **Changed**
597
+
598
+ | Area | What |
599
+ | --- | --- |
600
+ | `ClientQuotaUsage.clientDisplayName?` | Optional display name on `clientsConfig.quota` — e.g. `"Acme Corp"`. Included in `ClientQuotaState` via `getClientQuotaState`. |
601
+
602
+ **Added**
603
+
604
+ | Export | Purpose |
605
+ | --- | --- |
606
+ | `getClientDisplayName(clientId)` | Returns trimmed `quota.clientDisplayName`, or `"-"` when unset, missing, or blank. Never falls back to `clientId`. |
607
+
608
+ **Do I need to update my app?**
609
+
610
+ No — purely additive. Set `clientsConfig.quota.clientDisplayName` when provisioning quota for a client. **TalkPilot Server** should upgrade to **1.3.32** (or later) to use the label in quota emails.
611
+
612
+ ### 1.3.33 — Configuration database & Prompts collection (CP-1560)
613
+
614
+ New `configuration` database with a prompts collection, so prompts previously hardcoded in consuming repos (e.g. MIS's `moked_106` street/subject search and transcription prompts) can be stored centrally and edited without a deploy. Ships the **read** path only — documents are seeded/managed manually (e.g. via Compass), not through this package.
615
+
616
+ **Added**
617
+
618
+ | Export | Purpose |
619
+ | --- | --- |
620
+ | `configurationMongodbClient` | MongoDB client for the `configuration` database (default name `configuration`, override with `CONFIGURATION_DB_NAME`). |
621
+ | `getConfigurationDb` / `setConfigurationDb` / `ConfigurationObjectId` | DB handle accessors and `ObjectId`, matching the other domains. |
622
+ | `Prompt` | Document type: `{ _id, name, content, createdAt, updatedAt }`, keyed by unique `name`. |
623
+ | `getPromptByName(name)` | Fetch a single prompt by its unique `name`. Returns `null` if absent. |
624
+ | `findPrompts(filter?)` | Flexible query over the collection. |
625
+ | `getAllPrompts()` | Fetch every prompt. |
626
+ | `getPromptsCollection()` | Raw collection access. |
627
+
628
+ `ensureDbConnected()` / `disconnectDb()` now also connect/disconnect the configuration client alongside talkpilot/municipal/websitalk.
629
+
630
+ **Do I need to update my app?**
631
+
632
+ No — purely additive. Consumers opt in by importing the getters above.
633
+
634
+ ### 1.3.35 — Prompts fixes: collection name, `productName`, centralized config
635
+
636
+ **Breaking**
637
+
638
+ | Changed | What |
639
+ | --- | --- |
640
+ | Collection name | `"Prompts"` → `"prompts"` (lowercase, matching every other collection in core-db). MongoDB collection names are case-sensitive — if you inserted documents into a collection literally named `Prompts` under 1.3.33, move them to `prompts`. |
641
+
642
+ **Added**
643
+
644
+ | Export | Purpose |
645
+ | --- | --- |
646
+ | `Prompt.productName` | Required `KnownProductKey` (`"municipal" \| "clinics" \| "websiteTalk"`). Existing documents need this field backfilled. |
647
+ | `getPromptsByProduct(productName)` | Fetch all prompts for a given product. |
648
+
649
+ **Internal**
650
+
651
+ - Configuration-DB env var reads (`MONGO_URI`, `MONGODB_URI`, `CONFIGURATION_DB_NAME`) centralized into `src/config.ts` (`configurationDbConfig`) — no consumer-facing change.
652
+
653
+ **Do I need to update my app?**
654
+
655
+ Only if you inserted documents into the old `Prompts` (capital P) collection — move them to `prompts`. Also backfill `productName` on any existing prompt documents (e.g. `"municipal"`), since it's now a required field on the type.
656
+
657
+ ### 1.3.36 — Merge with `main`
658
+
659
+ Publishes the 1.3.33/1.3.35 configuration-DB work alongside the latest `main` — client call-quota, `clientDisplayName`, and bulk-write/streets/departmentSubjects updates (see 1.3.28, 1.3.29, 1.3.32). No new code of its own; this version exists to ship both branches' work together.
660
+
661
+ **Do I need to update my app?**
662
+
663
+ No — purely additive, same as the versions it combines.
664
+
665
+ ### 1.3.37 — Model catalog & internal model settings (CP-1624)
666
+
667
+ New `models` and `internalModels` collections under the `configuration` database, so AI model catalogs and cross-service settings previously hardcoded in consuming repos (e.g. TalkPilot Server's realtime/STT model lists and its live transcription model) can be stored centrally and edited without a deploy. Ships the **read** path only, same as `prompts` — documents are seeded/managed manually (e.g. via Compass).
668
+
669
+ **Added — `models`**
670
+
671
+ | Export | Purpose |
672
+ | --- | --- |
673
+ | `ModelDoc` (`RealtimeModelDoc \| SttModelDoc`) | Document type discriminated by `type`: `{ _id, modelId, name, description?, available, features?, configDefaults?, createdAt, updatedAt }`, plus `provider` (`RealtimeModelProvider` for `type: "realtime"`, `SttModelProvider` for `type: "stt"`). |
674
+ | `MODEL_TYPES`, `REALTIME_MODEL_PROVIDERS`, `STT_MODEL_PROVIDERS` | Known `type`/`provider` value lists the types above are derived from. |
675
+ | `getModelByModelId(modelId, type?)` | Fetch a single model by its `modelId`, optionally scoped to a `type`. |
676
+ | `getModelsByProvider(provider, type?)` | Fetch all models for a given `provider`, optionally scoped to a `type`. |
677
+ | `getModelsByType(type)` | Fetch all models of a given `type`. |
678
+ | `getAvailableModelsByType(type)` | Same as above, pre-filtered to `available: true`. |
679
+ | `findModels(filter?)` | Flexible query over the collection. |
680
+ | `getModelsCollection()` | Raw collection access. |
681
+
682
+ **Added — `internalModels`**
683
+
684
+ | Export | Purpose |
685
+ | --- | --- |
686
+ | `InternalModel` | Document type: `{ _id, name, provider, model, config?, createdAt, updatedAt }`, keyed by unique `name` — e.g. a `"transcriptionModel"` document. |
687
+ | `getInternalModelByName(name)` | Fetch a single internal model config by its unique `name`. Returns `null` if absent. |
688
+ | `findInternalModels(filter?)` | Flexible query over the collection. |
689
+ | `getAllInternalModels()` | Fetch every internal model. |
690
+ | `getInternalModelsCollection()` | Raw collection access. |
691
+
692
+ `ensureDbConnected()` / `disconnectDb()` already covered the configuration client from 1.3.33 — no change there.
693
+
694
+ **Do I need to update my app?**
695
+
696
+ No — purely additive. Consumers opt in by importing the getters above.
697
+
698
+ ### 1.3.38 — Transcription comparison field (CP-1594)
699
+
700
+ Added an optional `transcriptionComparison` field to `Call`, for consumers that run side-channel transcription comparisons across multiple providers/models alongside the real `transcription` field.
701
+
702
+ **Added**
703
+
704
+ | Export | Purpose |
705
+ | --- | --- |
706
+ | `Call.transcriptionComparison` | Optional `Record<string, TranscriptionSegment[]>` — one entry per `{provider}-{model}` key, each an array of `TranscriptionSegment` in the same shape as `Call.transcription`. |
707
+
708
+ **Do I need to update my app?**
709
+
710
+ No — purely additive. Existing documents and consumers continue to work unchanged.
711
+
712
+ ## 🛠 CI/CD & deployment
713
+
714
+ - This package is consumed by Cloud Build-based services (TalkPilot Server, MIS, CIS) as a dependency when Docker images are built. Keep `dist/` in sync with your builds because the compiled artifact is what downstream services install.
715
+ - Releases require the shared npm token documented in `DEVELOPMENT.md`; consult that guide for contribution, linking, and token rotation procedures.
716
+
717
+ ## Resources
718
+
719
+ - [DEVELOPMENT.md](./DEVELOPMENT.md) (setup, tooling, publishing, token management)
720
+ - [src/test-utils](src/test-utils) and the `__tests__` folder for examples of `MongoMemoryServer` wiring.
721
+