@talkpilot/core-db 1.3.72 → 1.3.74

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 (38) hide show
  1. package/README.md +9 -1
  2. package/dist/municipal/muniIssues/index.d.ts +2 -2
  3. package/dist/municipal/muniIssues/index.d.ts.map +1 -1
  4. package/dist/municipal/muniIssues/index.js +1 -2
  5. package/dist/municipal/muniIssues/index.js.map +1 -1
  6. package/dist/municipal/muniIssues/muniIssues.constants.d.ts +0 -2
  7. package/dist/municipal/muniIssues/muniIssues.constants.d.ts.map +1 -1
  8. package/dist/municipal/muniIssues/muniIssues.constants.js +1 -8
  9. package/dist/municipal/muniIssues/muniIssues.constants.js.map +1 -1
  10. package/dist/municipal/muniIssues/muniIssues.getters.d.ts +1 -6
  11. package/dist/municipal/muniIssues/muniIssues.getters.d.ts.map +1 -1
  12. package/dist/municipal/muniIssues/muniIssues.getters.js +1 -31
  13. package/dist/municipal/muniIssues/muniIssues.getters.js.map +1 -1
  14. package/dist/municipal/muniIssues/muniIssues.schema.d.ts.map +1 -1
  15. package/dist/municipal/muniIssues/muniIssues.schema.js +0 -13
  16. package/dist/municipal/muniIssues/muniIssues.schema.js.map +1 -1
  17. package/dist/municipal/muniIssues/muniIssues.setters.d.ts +1 -5
  18. package/dist/municipal/muniIssues/muniIssues.setters.d.ts.map +1 -1
  19. package/dist/municipal/muniIssues/muniIssues.setters.js +2 -39
  20. package/dist/municipal/muniIssues/muniIssues.setters.js.map +1 -1
  21. package/dist/municipal/muniIssues/muniIssues.types.d.ts +2 -23
  22. package/dist/municipal/muniIssues/muniIssues.types.d.ts.map +1 -1
  23. package/dist/talkpilot/calls/calls.constants.d.ts +2 -1
  24. package/dist/talkpilot/calls/calls.constants.d.ts.map +1 -1
  25. package/dist/talkpilot/calls/calls.constants.js +2 -1
  26. package/dist/talkpilot/calls/calls.constants.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +1 -74
  29. package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +0 -1
  30. package/src/municipal/muniIssues/index.ts +0 -5
  31. package/src/municipal/muniIssues/muniIssues.constants.ts +0 -8
  32. package/src/municipal/muniIssues/muniIssues.getters.ts +2 -46
  33. package/src/municipal/muniIssues/muniIssues.schema.ts +0 -14
  34. package/src/municipal/muniIssues/muniIssues.setters.ts +3 -59
  35. package/src/municipal/muniIssues/muniIssues.types.ts +4 -34
  36. package/src/talkpilot/calls/__tests__/calls.spec.ts +2 -2
  37. package/src/talkpilot/calls/calls.constants.ts +2 -1
  38. package/src/municipal/muniIssues/__tests__/muniIssues.getters.spec.ts +0 -60
package/README.md CHANGED
@@ -183,7 +183,7 @@ Refer to `DEVELOPMENT.md` for the full walkthrough, token instructions, and fact
183
183
  | 1.3.62 | Pause/Resume support for WebsiteTalk scans (CP-1752): `PAUSED` and `CANCELED` added to `SCAN_STATUSES` (`PAUSED` deliberately excluded from `FINISHED_SCAN_STATUSES` — pausing isn't done, `CANCELED` is). Added `Scan.pausedAt`, tracked across pause/resume so elapsed-time display can freeze correctly instead of counting the paused duration. |
184
184
  | 1.3.64 | New `callTokenUsage` collection with `incrementCallTokenUsage` (CP-1810): per-call realtime token usage, one document per `callSid`. |
185
185
  | 1.3.71 | Who ended a call (CP-1873): optional `Call.endedBy` (`system` / `agent` / `user`), `CallEndedByValues`, and `setCallEndedBy` (first write wins). **Breaking** vs 1.3.69–1.3.70: the value `resident` was replaced by `user`. |
186
- | 1.3.72 | Complaint tracking on `muniIssues` (CP-1888): optional `status` / `response` / `updatedAt`, `updateMuniIssueStatus`, `setMuniIssueResponse` (one response, then locked), `findMuniIssuesByClient`, `countMuniIssuesByClient`, `getMuniIssueByIdForClient`, index `clientId_1_createdAt_-1`. |
186
+ | 1.3.74 | Added `human` to `CallEndedByValues` (CP-1873): a human agent ended the call, after a transfer or in a conference. |
187
187
 
188
188
  ### 1.1.9
189
189
 
@@ -824,6 +824,14 @@ Records who ended a connected call. Unset for calls that never connected (busy,
824
824
 
825
825
  **TalkPilot Server** must upgrade to **1.3.71** to write the field. 1.3.69–1.3.70 used `resident` instead of `user` — don't use them.
826
826
 
827
+ ### 1.3.74 — Human agent ended the call (CP-1873)
828
+
829
+ New `CallEndedByValues.Human` (`"human"`): a human agent ended the call, either after a transfer or in a conference.
830
+
831
+ **Do I need to update my app?**
832
+
833
+ No — purely additive. **TalkPilot Server** should upgrade to **1.3.74** to write it.
834
+
827
835
  ## 🛠 CI/CD & deployment
828
836
 
829
837
  - 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.
@@ -1,7 +1,7 @@
1
1
  export * from "./muniIssues.getters";
2
2
  export * from "./muniIssues.setters";
3
3
  export * from "./muniIssues.setup";
4
- export { MUNI_ISSUES_COLLECTION, MUNI_ISSUE_STATUSES, MUNI_ISSUE_SYNC_STATUSES, MUNI_ISSUE_TEXT_MAX_LENGTH, MUNI_ISSUE_NAME_MAX_LENGTH, } from "./muniIssues.constants";
4
+ export { MUNI_ISSUES_COLLECTION, MUNI_ISSUE_SYNC_STATUSES, MUNI_ISSUE_TEXT_MAX_LENGTH, MUNI_ISSUE_NAME_MAX_LENGTH, } from "./muniIssues.constants";
5
5
  export { muniIssuesJsonSchema, muniIssuesIndexes } from "./muniIssues.schema";
6
- export type { MuniIssue, MuniIssueContent, MuniIssueJira, MuniIssueSyncStatus, MuniIssueStatus, MuniIssueResponse, CreateMuniIssueInput, SetMuniIssueResponseInput, FindMuniIssuesOptions, } from "./muniIssues.types";
6
+ export type { MuniIssue, MuniIssueContent, MuniIssueJira, MuniIssueSyncStatus, CreateMuniIssueInput, } from "./muniIssues.types";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
@@ -14,13 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.muniIssuesIndexes = exports.muniIssuesJsonSchema = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUE_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
17
+ exports.muniIssuesIndexes = exports.muniIssuesJsonSchema = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
18
18
  __exportStar(require("./muniIssues.getters"), exports);
19
19
  __exportStar(require("./muniIssues.setters"), exports);
20
20
  __exportStar(require("./muniIssues.setup"), exports);
21
21
  var muniIssues_constants_1 = require("./muniIssues.constants");
22
22
  Object.defineProperty(exports, "MUNI_ISSUES_COLLECTION", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUES_COLLECTION; } });
23
- Object.defineProperty(exports, "MUNI_ISSUE_STATUSES", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_STATUSES; } });
24
23
  Object.defineProperty(exports, "MUNI_ISSUE_SYNC_STATUSES", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_SYNC_STATUSES; } });
25
24
  Object.defineProperty(exports, "MUNI_ISSUE_TEXT_MAX_LENGTH", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_TEXT_MAX_LENGTH; } });
26
25
  Object.defineProperty(exports, "MUNI_ISSUE_NAME_MAX_LENGTH", { enumerable: true, get: function () { return muniIssues_constants_1.MUNI_ISSUE_NAME_MAX_LENGTH; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,uDAAqC;AACrC,qDAAmC;AACnC,+DAMgC;AAL9B,8HAAA,sBAAsB,OAAA;AACtB,2HAAA,mBAAmB,OAAA;AACnB,gIAAA,wBAAwB,OAAA;AACxB,kIAAA,0BAA0B,OAAA;AAC1B,kIAAA,0BAA0B,OAAA;AAE5B,yDAA8E;AAArE,yHAAA,oBAAoB,OAAA;AAAE,sHAAA,iBAAiB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,uDAAqC;AACrC,qDAAmC;AACnC,+DAKgC;AAJ9B,8HAAA,sBAAsB,OAAA;AACtB,gIAAA,wBAAwB,OAAA;AACxB,kIAAA,0BAA0B,OAAA;AAC1B,kIAAA,0BAA0B,OAAA;AAE5B,yDAA8E;AAArE,yHAAA,oBAAoB,OAAA;AAAE,sHAAA,iBAAiB,OAAA"}
@@ -2,8 +2,6 @@
2
2
  export declare const MUNI_ISSUES_COLLECTION = "muniIssues";
3
3
  /** Sync state of the issue's Jira ticket at write time. */
4
4
  export declare const MUNI_ISSUE_SYNC_STATUSES: readonly ["created", "failed"];
5
- /** Customer-facing complaint status, set manually by the TalkPilot team. */
6
- export declare const MUNI_ISSUE_STATUSES: readonly ["in_review", "in_progress", "resolved", "no_issue_found"];
7
5
  /** Max length for the long free-text fields — well above the ~2000-char target. */
8
6
  export declare const MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
9
7
  /** Max length for the short identity fields (a person's name and role). */
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.constants.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gCAAiC,CAAC;AAEvE,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,qEAKtB,CAAC;AAEX,mFAAmF;AACnF,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAG,QAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,EAAG,OAAgB,CAAC"}
1
+ {"version":3,"file":"muniIssues.constants.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gCAAiC,CAAC;AAEvE,mFAAmF;AACnF,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,2EAA2E;AAC3E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAG,QAAiB,CAAC;AAClD,eAAO,MAAM,iBAAiB,EAAG,OAAgB,CAAC"}
@@ -1,17 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VALIDATION_ACTION = exports.VALIDATION_LEVEL = exports.NAMESPACE_EXISTS = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_STATUSES = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
3
+ exports.VALIDATION_ACTION = exports.VALIDATION_LEVEL = exports.NAMESPACE_EXISTS = exports.MUNI_ISSUE_NAME_MAX_LENGTH = exports.MUNI_ISSUE_TEXT_MAX_LENGTH = exports.MUNI_ISSUE_SYNC_STATUSES = exports.MUNI_ISSUES_COLLECTION = void 0;
4
4
  /** Mongo collection name for reported municipal issues. */
5
5
  exports.MUNI_ISSUES_COLLECTION = "muniIssues";
6
6
  /** Sync state of the issue's Jira ticket at write time. */
7
7
  exports.MUNI_ISSUE_SYNC_STATUSES = ["created", "failed"];
8
- /** Customer-facing complaint status, set manually by the TalkPilot team. */
9
- exports.MUNI_ISSUE_STATUSES = [
10
- "in_review",
11
- "in_progress",
12
- "resolved",
13
- "no_issue_found",
14
- ];
15
8
  /** Max length for the long free-text fields — well above the ~2000-char target. */
16
9
  exports.MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
17
10
  /** Max length for the short identity fields (a person's name and role). */
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.constants.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,YAAY,CAAC;AAEnD,2DAA2D;AAC9C,QAAA,wBAAwB,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAEvE,4EAA4E;AAC/D,QAAA,mBAAmB,GAAG;IACjC,WAAW;IACX,aAAa;IACb,UAAU;IACV,gBAAgB;CACR,CAAC;AAEX,mFAAmF;AACtE,QAAA,0BAA0B,GAAG,IAAI,CAAC;AAE/C,2EAA2E;AAC9D,QAAA,0BAA0B,GAAG,GAAG,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAEnC,yEAAyE;AAC5D,QAAA,gBAAgB,GAAG,QAAiB,CAAC;AACrC,QAAA,iBAAiB,GAAG,OAAgB,CAAC"}
1
+ {"version":3,"file":"muniIssues.constants.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.constants.ts"],"names":[],"mappings":";;;AAAA,2DAA2D;AAC9C,QAAA,sBAAsB,GAAG,YAAY,CAAC;AAEnD,2DAA2D;AAC9C,QAAA,wBAAwB,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAEvE,mFAAmF;AACtE,QAAA,0BAA0B,GAAG,IAAI,CAAC;AAE/C,2EAA2E;AAC9D,QAAA,0BAA0B,GAAG,GAAG,CAAC;AAE9C,uGAAuG;AAC1F,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAEnC,yEAAyE;AAC5D,QAAA,gBAAgB,GAAG,QAAiB,CAAC;AACrC,QAAA,iBAAiB,GAAG,OAAgB,CAAC"}
@@ -1,12 +1,7 @@
1
1
  import { Collection, ObjectId } from "mongodb";
2
- import { FindMuniIssuesOptions, MuniIssue } from "./muniIssues.types";
2
+ import { MuniIssue } from "./muniIssues.types";
3
3
  export declare const getMuniIssuesCollection: () => Collection<MuniIssue>;
4
4
  export declare const generateMuniIssueId: () => ObjectId;
5
5
  export declare const getMuniIssueById: (id: string) => Promise<MuniIssue | null>;
6
6
  export declare const getMuniIssueByJiraKey: (jiraKey: string) => Promise<MuniIssue | null>;
7
- /** A client's tracked issues, newest first. */
8
- export declare const findMuniIssuesByClient: (clientId: string, { answered, skip, limit }?: FindMuniIssuesOptions) => Promise<MuniIssue[]>;
9
- export declare const countMuniIssuesByClient: (clientId: string, { answered }?: Pick<FindMuniIssuesOptions, "answered">) => Promise<number>;
10
- /** One tracked issue, only if it belongs to the client. */
11
- export declare const getMuniIssueByIdForClient: (id: string, clientId: string) => Promise<MuniIssue | null>;
12
7
  //# sourceMappingURL=muniIssues.getters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.getters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAU,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGtE,eAAO,MAAM,uBAAuB,QAAO,UAAU,CAAC,SAAS,CAE9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,QAA0B,CAAC;AAElE,eAAO,MAAM,gBAAgB,GAC3B,IAAI,MAAM,KACT,OAAO,CAAC,SAAS,GAAG,IAAI,CAI1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAE1B,CAAC;AAYF,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,4BAAmC,qBAA0B,KAC5D,OAAO,CAAC,SAAS,EAAE,CAOrB,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,EAChB,eAAc,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAM,KACzD,OAAO,CAAC,MAAM,CAIhB,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB,GACpC,IAAI,MAAM,EACV,UAAU,MAAM,KACf,OAAO,CAAC,SAAS,GAAG,IAAI,CAM1B,CAAC"}
1
+ {"version":3,"file":"muniIssues.getters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,eAAO,MAAM,uBAAuB,QAAO,UAAU,CAAC,SAAS,CAE9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,QAA0B,CAAC;AAElE,eAAO,MAAM,gBAAgB,GAC3B,IAAI,MAAM,KACT,OAAO,CAAC,SAAS,GAAG,IAAI,CAI1B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAE1B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getMuniIssueByIdForClient = exports.countMuniIssuesByClient = exports.findMuniIssuesByClient = exports.getMuniIssueByJiraKey = exports.getMuniIssueById = exports.generateMuniIssueId = exports.getMuniIssuesCollection = void 0;
3
+ exports.getMuniIssueByJiraKey = exports.getMuniIssueById = exports.generateMuniIssueId = exports.getMuniIssuesCollection = void 0;
4
4
  const mongodb_1 = require("mongodb");
5
5
  const index_1 = require("../index");
6
6
  const muniIssues_constants_1 = require("./muniIssues.constants");
@@ -21,34 +21,4 @@ const getMuniIssueByJiraKey = async (jiraKey) => {
21
21
  return (0, exports.getMuniIssuesCollection)().findOne({ "jira.key": jiraKey });
22
22
  };
23
23
  exports.getMuniIssueByJiraKey = getMuniIssueByJiraKey;
24
- // Tracked issues of one client. Issues without a status predate complaint tracking and are excluded.
25
- const clientIssuesFilter = (clientId, answered) => ({
26
- clientId,
27
- status: { $exists: true },
28
- ...(answered !== undefined && { response: { $exists: answered } }),
29
- });
30
- /** A client's tracked issues, newest first. */
31
- const findMuniIssuesByClient = async (clientId, { answered, skip = 0, limit = 0 } = {}) => {
32
- return (0, exports.getMuniIssuesCollection)()
33
- .find(clientIssuesFilter(clientId, answered))
34
- .sort({ createdAt: -1 })
35
- .skip(skip)
36
- .limit(limit)
37
- .toArray();
38
- };
39
- exports.findMuniIssuesByClient = findMuniIssuesByClient;
40
- const countMuniIssuesByClient = async (clientId, { answered } = {}) => {
41
- return (0, exports.getMuniIssuesCollection)().countDocuments(clientIssuesFilter(clientId, answered));
42
- };
43
- exports.countMuniIssuesByClient = countMuniIssuesByClient;
44
- /** One tracked issue, only if it belongs to the client. */
45
- const getMuniIssueByIdForClient = async (id, clientId) => {
46
- if (!mongodb_1.ObjectId.isValid(id))
47
- return null;
48
- return (0, exports.getMuniIssuesCollection)().findOne({
49
- ...clientIssuesFilter(clientId),
50
- _id: new mongodb_1.ObjectId(id),
51
- });
52
- };
53
- exports.getMuniIssueByIdForClient = getMuniIssueByIdForClient;
54
24
  //# sourceMappingURL=muniIssues.getters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.getters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":";;;AAAA,qCAAuD;AACvD,oCAAiC;AAEjC,iEAAgE;AAEzD,MAAM,uBAAuB,GAAG,GAA0B,EAAE;IACjE,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAY,6CAAsB,CAAC,CAAC;AAC/D,CAAC,CAAC;AAFW,QAAA,uBAAuB,2BAElC;AAEK,MAAM,mBAAmB,GAAG,GAAa,EAAE,CAAC,IAAI,kBAAQ,EAAE,CAAC;AAArD,QAAA,mBAAmB,uBAAkC;AAE3D,MAAM,gBAAgB,GAAG,KAAK,EACnC,EAAU,EACiB,EAAE;IAC7B,iFAAiF;IACjF,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AANW,QAAA,gBAAgB,oBAM3B;AAEK,MAAM,qBAAqB,GAAG,KAAK,EACxC,OAAe,EACY,EAAE;IAC7B,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;AACpE,CAAC,CAAC;AAJW,QAAA,qBAAqB,yBAIhC;AAEF,qGAAqG;AACrG,MAAM,kBAAkB,GAAG,CACzB,QAAgB,EAChB,QAAkB,EACC,EAAE,CAAC,CAAC;IACvB,QAAQ;IACR,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;IACzB,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC;CACnE,CAAC,CAAC;AAEH,+CAA+C;AACxC,MAAM,sBAAsB,GAAG,KAAK,EACzC,QAAgB,EAChB,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,KAA4B,EAAE,EACvC,EAAE;IACxB,OAAO,IAAA,+BAAuB,GAAE;SAC7B,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SAC5C,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;SACvB,IAAI,CAAC,IAAI,CAAC;SACV,KAAK,CAAC,KAAK,CAAC;SACZ,OAAO,EAAE,CAAC;AACf,CAAC,CAAC;AAVW,QAAA,sBAAsB,0BAUjC;AAEK,MAAM,uBAAuB,GAAG,KAAK,EAC1C,QAAgB,EAChB,EAAE,QAAQ,KAA8C,EAAE,EACzC,EAAE;IACnB,OAAO,IAAA,+BAAuB,GAAE,CAAC,cAAc,CAC7C,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CACvC,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,uBAAuB,2BAOlC;AAEF,2DAA2D;AACpD,MAAM,yBAAyB,GAAG,KAAK,EAC5C,EAAU,EACV,QAAgB,EACW,EAAE;IAC7B,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC;QACvC,GAAG,kBAAkB,CAAC,QAAQ,CAAC;QAC/B,GAAG,EAAE,IAAI,kBAAQ,CAAC,EAAE,CAAC;KACtB,CAAC,CAAC;AACL,CAAC,CAAC;AATW,QAAA,yBAAyB,6BASpC"}
1
+ {"version":3,"file":"muniIssues.getters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.getters.ts"],"names":[],"mappings":";;;AAAA,qCAA+C;AAC/C,oCAAiC;AAEjC,iEAAgE;AAEzD,MAAM,uBAAuB,GAAG,GAA0B,EAAE;IACjE,OAAO,IAAA,aAAK,GAAE,CAAC,UAAU,CAAY,6CAAsB,CAAC,CAAC;AAC/D,CAAC,CAAC;AAFW,QAAA,uBAAuB,2BAElC;AAEK,MAAM,mBAAmB,GAAG,GAAa,EAAE,CAAC,IAAI,kBAAQ,EAAE,CAAC;AAArD,QAAA,mBAAmB,uBAAkC;AAE3D,MAAM,gBAAgB,GAAG,KAAK,EACnC,EAAU,EACiB,EAAE;IAC7B,iFAAiF;IACjF,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AANW,QAAA,gBAAgB,oBAM3B;AAEK,MAAM,qBAAqB,GAAG,KAAK,EACxC,OAAe,EACY,EAAE;IAC7B,OAAO,IAAA,+BAAuB,GAAE,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;AACpE,CAAC,CAAC;AAJW,QAAA,qBAAqB,yBAIhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.schema.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAQ1D,eAAO,MAAM,oBAAoB,EAAE,QA8DlC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAO/C,CAAC"}
1
+ {"version":3,"file":"muniIssues.schema.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAO1D,eAAO,MAAM,oBAAoB,EAAE,QAmDlC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAK/C,CAAC"}
@@ -52,24 +52,11 @@ exports.muniIssuesJsonSchema = {
52
52
  },
53
53
  },
54
54
  createdAt: { bsonType: "date" },
55
- status: { enum: [...muniIssues_constants_1.MUNI_ISSUE_STATUSES] },
56
- response: {
57
- bsonType: "object",
58
- required: ["text", "createdAt"],
59
- properties: {
60
- text: { bsonType: "string", maxLength: muniIssues_constants_1.MUNI_ISSUE_TEXT_MAX_LENGTH },
61
- imageUrl: { bsonType: "string" },
62
- createdAt: { bsonType: "date" },
63
- },
64
- },
65
- updatedAt: { bsonType: "date" },
66
55
  },
67
56
  };
68
57
  exports.muniIssuesIndexes = [
69
58
  { key: { callSid: 1 }, name: "callSid_1" },
70
59
  { key: { createdAt: -1 }, name: "createdAt_-1" },
71
- // Complaint list: one municipality's issues, newest first.
72
- { key: { clientId: 1, createdAt: -1 }, name: "clientId_1_createdAt_-1" },
73
60
  // Unique: one stored document per Jira ticket, guarding against duplicate writes.
74
61
  { key: { "jira.key": 1 }, name: "jira_key_unique", unique: true },
75
62
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.schema.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":";;;AACA,iEAKgC;AAEnB,QAAA,oBAAoB,GAAa;IAC5C,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE;QACR,SAAS;QACT,UAAU;QACV,UAAU;QACV,cAAc;QACd,MAAM;QACN,WAAW;KACZ;IACD,UAAU,EAAE;QACV,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAC/B,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,YAAY,EAAE;YACZ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE;gBACR,YAAY;gBACZ,YAAY;gBACZ,kBAAkB;gBAClB,iBAAiB;aAClB;YACD,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,gBAAgB,EAAE;oBAChB,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,eAAe,EAAE;oBACf,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;aACF;SACF;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;YAC/B,UAAU,EAAE;gBACV,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,+CAAwB,CAAC,EAAE;aACpD;SACF;QACD,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;QAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,0CAAmB,CAAC,EAAE;QAC1C,QAAQ,EAAE;YACR,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;YAC/B,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,iDAA0B,EAAE;gBACnE,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBAChC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;aAChC;SACF;QACD,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;KAChC;CACF,CAAC;AAEW,QAAA,iBAAiB,GAAuB;IACnD,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;IAC1C,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;IAChD,2DAA2D;IAC3D,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE;IACxE,kFAAkF;IAClF,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE;CAClE,CAAC"}
1
+ {"version":3,"file":"muniIssues.schema.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.schema.ts"],"names":[],"mappings":";;;AACA,iEAIgC;AAEnB,QAAA,oBAAoB,GAAa;IAC5C,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE;QACR,SAAS;QACT,UAAU;QACV,UAAU;QACV,cAAc;QACd,MAAM;QACN,WAAW;KACZ;IACD,UAAU,EAAE;QACV,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAC/B,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;QAChC,YAAY,EAAE;YACZ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE;gBACR,YAAY;gBACZ,YAAY;gBACZ,kBAAkB;gBAClB,iBAAiB;aAClB;YACD,UAAU,EAAE;gBACV,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,UAAU,EAAE;oBACV,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,gBAAgB,EAAE;oBAChB,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;gBACD,eAAe,EAAE;oBACf,QAAQ,EAAE,QAAQ;oBAClB,SAAS,EAAE,iDAA0B;iBACtC;aACF;SACF;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;YAC/B,UAAU,EAAE;gBACV,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,+CAAwB,CAAC,EAAE;aACpD;SACF;QACD,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;KAChC;CACF,CAAC;AAEW,QAAA,iBAAiB,GAAuB;IACnD,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;IAC1C,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;IAChD,kFAAkF;IAClF,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE;CAClE,CAAC"}
@@ -1,8 +1,4 @@
1
1
  import { ObjectId } from "mongodb";
2
- import { CreateMuniIssueInput, MuniIssueStatus, SetMuniIssueResponseInput } from "./muniIssues.types";
2
+ import { CreateMuniIssueInput } from "./muniIssues.types";
3
3
  export declare const createMuniIssue: (issueData: CreateMuniIssueInput, id: ObjectId) => Promise<ObjectId>;
4
- /** Changes the status of an unanswered issue. Returns false if none matched. */
5
- export declare const updateMuniIssueStatus: (id: string, clientId: string, status: MuniIssueStatus) => Promise<boolean>;
6
- /** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
7
- export declare const setMuniIssueResponse: (id: string, clientId: string, { status, text, imageUrl }: SetMuniIssueResponseInput) => Promise<boolean>;
8
4
  //# sourceMappingURL=muniIssues.setters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.setters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EACL,oBAAoB,EAEpB,eAAe,EACf,yBAAyB,EAC1B,MAAM,oBAAoB,CAAC;AAK5B,eAAO,MAAM,eAAe,GAC1B,WAAW,oBAAoB,EAC/B,IAAI,QAAQ,KACX,OAAO,CAAC,QAAQ,CAiBlB,CAAC;AAWF,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,GAChC,IAAI,MAAM,EACV,UAAU,MAAM,EAChB,QAAQ,eAAe,KACtB,OAAO,CAAC,OAAO,CASjB,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,GAC/B,IAAI,MAAM,EACV,UAAU,MAAM,EAChB,4BAA4B,yBAAyB,KACpD,OAAO,CAAC,OAAO,CAgBjB,CAAC"}
1
+ {"version":3,"file":"muniIssues.setters.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAa,MAAM,oBAAoB,CAAC;AAKrE,eAAO,MAAM,eAAe,GAC1B,WAAW,oBAAoB,EAC/B,IAAI,QAAQ,KACX,OAAO,CAAC,QAAQ,CAclB,CAAC"}
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setMuniIssueResponse = exports.updateMuniIssueStatus = exports.createMuniIssue = void 0;
4
- const mongodb_1 = require("mongodb");
3
+ exports.createMuniIssue = void 0;
5
4
  const muniIssues_getters_1 = require("./muniIssues.getters");
6
5
  const muniIssues_setup_1 = require("./muniIssues.setup");
7
6
  // Required `id`: MIS pre-generates it (generateMuniIssueId) and embeds it in the Jira ticket — the two-way link.
8
7
  const createMuniIssue = async (issueData, id) => {
9
8
  await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
10
- const now = new Date();
11
9
  const issue = {
12
10
  _id: id,
13
11
  ...issueData,
@@ -15,45 +13,10 @@ const createMuniIssue = async (issueData, id) => {
15
13
  ...issueData.jira,
16
14
  syncStatus: issueData.jira.syncStatus ?? "created",
17
15
  },
18
- status: "in_review",
19
- createdAt: now,
20
- updatedAt: now,
16
+ createdAt: new Date(),
21
17
  };
22
18
  const { insertedId } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().insertOne(issue);
23
19
  return insertedId;
24
20
  };
25
21
  exports.createMuniIssue = createMuniIssue;
26
- // An issue of this client that is tracked (has a status) and not yet answered.
27
- // The `response` condition is the lock: once answered, no further writes match.
28
- const openIssueFilter = (id, clientId) => ({
29
- _id: new mongodb_1.ObjectId(id),
30
- clientId,
31
- status: { $exists: true },
32
- response: { $exists: false },
33
- });
34
- /** Changes the status of an unanswered issue. Returns false if none matched. */
35
- const updateMuniIssueStatus = async (id, clientId, status) => {
36
- if (!mongodb_1.ObjectId.isValid(id))
37
- return false;
38
- await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
39
- const { matchedCount } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().updateOne(openIssueFilter(id, clientId), { $set: { status, updatedAt: new Date() } });
40
- return matchedCount > 0;
41
- };
42
- exports.updateMuniIssueStatus = updateMuniIssueStatus;
43
- /** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
44
- const setMuniIssueResponse = async (id, clientId, { status, text, imageUrl }) => {
45
- if (!mongodb_1.ObjectId.isValid(id))
46
- return false;
47
- await (0, muniIssues_setup_1.ensureMuniIssuesCollectionOnce)();
48
- const now = new Date();
49
- const { matchedCount } = await (0, muniIssues_getters_1.getMuniIssuesCollection)().updateOne(openIssueFilter(id, clientId), {
50
- $set: {
51
- status,
52
- response: { text, ...(imageUrl && { imageUrl }), createdAt: now },
53
- updatedAt: now,
54
- },
55
- });
56
- return matchedCount > 0;
57
- };
58
- exports.setMuniIssueResponse = setMuniIssueResponse;
59
22
  //# sourceMappingURL=muniIssues.setters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.setters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":";;;AAAA,qCAA2C;AAO3C,6DAA+D;AAC/D,yDAAoE;AAEpE,iHAAiH;AAC1G,MAAM,eAAe,GAAG,KAAK,EAClC,SAA+B,EAC/B,EAAY,EACO,EAAE;IACrB,MAAM,IAAA,iDAA8B,GAAE,CAAC;IAEvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAc;QACvB,GAAG,EAAE,EAAE;QACP,GAAG,SAAS;QACZ,IAAI,EAAE;YACJ,GAAG,SAAS,CAAC,IAAI;YACjB,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,SAAS;SACnD;QACD,MAAM,EAAE,WAAW;QACnB,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACf,CAAC;IACF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,4CAAuB,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxE,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AApBW,QAAA,eAAe,mBAoB1B;AAEF,+EAA+E;AAC/E,gFAAgF;AAChF,MAAM,eAAe,GAAG,CAAC,EAAU,EAAE,QAAgB,EAAqB,EAAE,CAAC,CAAC;IAC5E,GAAG,EAAE,IAAI,kBAAQ,CAAC,EAAE,CAAC;IACrB,QAAQ;IACR,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;IACzB,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;CAC7B,CAAC,CAAC;AAEH,gFAAgF;AACzE,MAAM,qBAAqB,GAAG,KAAK,EACxC,EAAU,EACV,QAAgB,EAChB,MAAuB,EACL,EAAE;IACpB,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,IAAA,iDAA8B,GAAE,CAAC;IAEvC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,IAAA,4CAAuB,GAAE,CAAC,SAAS,CAChE,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,EAC7B,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,CAC5C,CAAC;IACF,OAAO,YAAY,GAAG,CAAC,CAAC;AAC1B,CAAC,CAAC;AAbW,QAAA,qBAAqB,yBAahC;AAEF,iGAAiG;AAC1F,MAAM,oBAAoB,GAAG,KAAK,EACvC,EAAU,EACV,QAAgB,EAChB,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAA6B,EACnC,EAAE;IACpB,IAAI,CAAC,kBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,IAAA,iDAA8B,GAAE,CAAC;IAEvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,IAAA,4CAAuB,GAAE,CAAC,SAAS,CAChE,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,EAC7B;QACE,IAAI,EAAE;YACJ,MAAM;YACN,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;YACjE,SAAS,EAAE,GAAG;SACf;KACF,CACF,CAAC;IACF,OAAO,YAAY,GAAG,CAAC,CAAC;AAC1B,CAAC,CAAC;AApBW,QAAA,oBAAoB,wBAoB/B"}
1
+ {"version":3,"file":"muniIssues.setters.js","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.setters.ts"],"names":[],"mappings":";;;AAEA,6DAA+D;AAC/D,yDAAoE;AAEpE,iHAAiH;AAC1G,MAAM,eAAe,GAAG,KAAK,EAClC,SAA+B,EAC/B,EAAY,EACO,EAAE;IACrB,MAAM,IAAA,iDAA8B,GAAE,CAAC;IAEvC,MAAM,KAAK,GAAc;QACvB,GAAG,EAAE,EAAE;QACP,GAAG,SAAS;QACZ,IAAI,EAAE;YACJ,GAAG,SAAS,CAAC,IAAI;YACjB,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,UAAU,IAAI,SAAS;SACnD;QACD,SAAS,EAAE,IAAI,IAAI,EAAE;KACtB,CAAC;IACF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,4CAAuB,GAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxE,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AAjBW,QAAA,eAAe,mBAiB1B"}
@@ -1,14 +1,7 @@
1
1
  import { ObjectId } from "mongodb";
2
2
  import { CityName } from "../utils/types";
3
- import { MUNI_ISSUE_STATUSES, MUNI_ISSUE_SYNC_STATUSES } from "./muniIssues.constants";
3
+ import { MUNI_ISSUE_SYNC_STATUSES } from "./muniIssues.constants";
4
4
  export type MuniIssueSyncStatus = (typeof MUNI_ISSUE_SYNC_STATUSES)[number];
5
- export type MuniIssueStatus = (typeof MUNI_ISSUE_STATUSES)[number];
6
- /** The single TalkPilot response; once set, the complaint is locked. */
7
- export type MuniIssueResponse = {
8
- text: string;
9
- imageUrl?: string;
10
- createdAt: Date;
11
- };
12
5
  export type MuniIssueContent = {
13
6
  issuerName: string;
14
7
  issuerRole: string;
@@ -27,25 +20,11 @@ export type MuniIssue = {
27
20
  issueContent: MuniIssueContent;
28
21
  jira: MuniIssueJira;
29
22
  createdAt: Date;
30
- status?: MuniIssueStatus;
31
- response?: MuniIssueResponse;
32
- updatedAt?: Date;
33
23
  };
34
- export type CreateMuniIssueInput = Omit<MuniIssue, "_id" | "createdAt" | "jira" | "status" | "response" | "updatedAt"> & {
24
+ export type CreateMuniIssueInput = Omit<MuniIssue, "_id" | "createdAt" | "jira"> & {
35
25
  jira: {
36
26
  key: string;
37
27
  syncStatus?: MuniIssueSyncStatus;
38
28
  };
39
29
  };
40
- export type SetMuniIssueResponseInput = {
41
- status: MuniIssueStatus;
42
- text: string;
43
- imageUrl?: string;
44
- };
45
- /** `answered` filters by whether a TalkPilot response exists; omit it for all issues. */
46
- export type FindMuniIssuesOptions = {
47
- answered?: boolean;
48
- skip?: number;
49
- limit?: number;
50
- };
51
30
  //# sourceMappingURL=muniIssues.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"muniIssues.types.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,wEAAwE;AACxE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,QAAQ,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAGhB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB,CAAC;AAIF,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,SAAS,EACT,KAAK,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,CACnE,GAAG;IACF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;KAAE,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
1
+ {"version":3,"file":"muniIssues.types.d.ts","sourceRoot":"","sources":["../../../src/municipal/muniIssues/muniIssues.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,QAAQ,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAIF,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,SAAS,EACT,KAAK,GAAG,WAAW,GAAG,MAAM,CAC7B,GAAG;IACF,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,mBAAmB,CAAA;KAAE,CAAC;CACzD,CAAC"}
@@ -32,10 +32,11 @@ export declare const CallStatusValues: {
32
32
  readonly Canceled: "canceled";
33
33
  };
34
34
  export declare const ALL_CALL_STATUSES: ("in-progress" | "answered" | "no-answer" | "completed" | "busy" | "failed" | "canceled" | "initiated" | "ringing")[];
35
- /** Who ended a connected call: our platform, the bot (end flow), or the caller. */
35
+ /** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
36
36
  export declare const CallEndedByValues: {
37
37
  readonly System: "system";
38
38
  readonly Agent: "agent";
39
39
  readonly User: "user";
40
+ readonly Human: "human";
40
41
  };
41
42
  //# sourceMappingURL=calls.constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"calls.constants.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAG,UAAmB,CAAC;AAE5D,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,EAAG,YAAqB,CAAC;AAEhE,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AAErE,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mEAMjB,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,eAAO,MAAM,iBAAiB,uHAAkC,CAAC;AAEjE,mFAAmF;AACnF,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC"}
1
+ {"version":3,"file":"calls.constants.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,EAAG,UAAmB,CAAC;AAE5D,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,EAAG,YAAqB,CAAC;AAEhE,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AAErE,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mEAMjB,CAAC;AAEX,6BAA6B;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAC9C,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUnB,CAAC;AAEX,eAAO,MAAM,iBAAiB,uHAAkC,CAAC;AAEjE,uGAAuG;AACvG,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC"}
@@ -41,10 +41,11 @@ exports.CallStatusValues = {
41
41
  Canceled: "canceled",
42
42
  };
43
43
  exports.ALL_CALL_STATUSES = Object.values(exports.CallStatusValues);
44
- /** Who ended a connected call: our platform, the bot (end flow), or the caller. */
44
+ /** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
45
45
  exports.CallEndedByValues = {
46
46
  System: "system",
47
47
  Agent: "agent",
48
48
  User: "user",
49
+ Human: "human",
49
50
  };
50
51
  //# sourceMappingURL=calls.constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"calls.constants.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AACjC,QAAA,wBAAwB,GAAG,UAAmB,CAAC;AAE5D,gDAAgD;AACnC,QAAA,0BAA0B,GAAG,YAAqB,CAAC;AAEhE,wEAAwE;AAC3D,QAAA,gBAAgB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAU,CAAC;AAErE,4EAA4E;AAC/D,QAAA,cAAc,GAAG;IAC5B,WAAW;IACX,WAAW;IACX,MAAM;IACN,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,6BAA6B;AAChB,QAAA,aAAa,GAAG,EAAE,CAAC;AAEhC,iEAAiE;AACpD,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAExC;;;;;GAKG;AACU,QAAA,6BAA6B,GAAG,CAAC,CAAC;AAClC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AAEjC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AACjC,QAAA,6BAA6B,GAAG,EAAE,CAAC;AAEnC,QAAA,gBAAgB,GAAG;IAC9B,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,aAAa;IACzB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,CAAC;AAEjE,mFAAmF;AACtE,QAAA,iBAAiB,GAAG;IAC/B,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;CACJ,CAAC"}
1
+ {"version":3,"file":"calls.constants.js","sourceRoot":"","sources":["../../../src/talkpilot/calls/calls.constants.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AACjC,QAAA,wBAAwB,GAAG,UAAmB,CAAC;AAE5D,gDAAgD;AACnC,QAAA,0BAA0B,GAAG,YAAqB,CAAC;AAEhE,wEAAwE;AAC3D,QAAA,gBAAgB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAU,CAAC;AAErE,4EAA4E;AAC/D,QAAA,cAAc,GAAG;IAC5B,WAAW;IACX,WAAW;IACX,MAAM;IACN,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,6BAA6B;AAChB,QAAA,aAAa,GAAG,EAAE,CAAC;AAEhC,iEAAiE;AACpD,QAAA,iBAAiB,GAAG,MAAM,CAAC;AAExC;;;;;GAKG;AACU,QAAA,6BAA6B,GAAG,CAAC,CAAC;AAClC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AAEjC,QAAA,4BAA4B,GAAG,CAAC,CAAC;AACjC,QAAA,6BAA6B,GAAG,EAAE,CAAC;AAEnC,QAAA,gBAAgB,GAAG;IAC9B,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,aAAa;IACzB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEE,QAAA,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,wBAAgB,CAAC,CAAC;AAEjE,uGAAuG;AAC1F,QAAA,iBAAiB,GAAG;IAC/B,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talkpilot/core-db",
3
- "version": "1.3.72",
3
+ "version": "1.3.74",
4
4
  "description": "Core database package for centralized connections and ORM integration.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,8 +1,4 @@
1
- import {
2
- createMuniIssue,
3
- setMuniIssueResponse,
4
- updateMuniIssueStatus,
5
- } from "../muniIssues.setters";
1
+ import { createMuniIssue } from "../muniIssues.setters";
6
2
  import {
7
3
  generateMuniIssueId,
8
4
  getMuniIssueById,
@@ -29,18 +25,6 @@ describe("muniIssues setters", () => {
29
25
  expect(saved?.createdAt).toBeInstanceOf(Date);
30
26
  });
31
27
 
32
- it("should start the issue as in_review with updatedAt and no response", async () => {
33
- const insertedId = await createMuniIssue(
34
- createMuniIssueInput(),
35
- generateMuniIssueId(),
36
- );
37
-
38
- const saved = await getMuniIssueById(insertedId.toString());
39
- expect(saved?.status).toBe("in_review");
40
- expect(saved?.updatedAt).toBeInstanceOf(Date);
41
- expect(saved?.response).toBeUndefined();
42
- });
43
-
44
28
  it("should default jira.syncStatus to created when not provided", async () => {
45
29
  const id = generateMuniIssueId();
46
30
 
@@ -107,61 +91,4 @@ describe("muniIssues setters", () => {
107
91
  expect(await getMuniIssueByJiraKey("CP-nope")).toBeNull();
108
92
  });
109
93
  });
110
-
111
- describe("updateMuniIssueStatus", () => {
112
- it("should change the status of an unanswered issue", async () => {
113
- const input = createMuniIssueInput();
114
- const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
115
-
116
- expect(await updateMuniIssueStatus(id, input.clientId, "in_progress")).toBe(true);
117
- expect((await getMuniIssueById(id))?.status).toBe("in_progress");
118
- });
119
-
120
- it("should not touch another client's issue or a malformed id", async () => {
121
- const id = (
122
- await createMuniIssue(createMuniIssueInput(), generateMuniIssueId())
123
- ).toString();
124
-
125
- expect(await updateMuniIssueStatus(id, "other-client", "resolved")).toBe(false);
126
- expect(await updateMuniIssueStatus("not-a-valid-id", "any", "resolved")).toBe(false);
127
- expect((await getMuniIssueById(id))?.status).toBe("in_review");
128
- });
129
- });
130
-
131
- describe("setMuniIssueResponse", () => {
132
- it("should save the response and status", async () => {
133
- const input = createMuniIssueInput();
134
- const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
135
-
136
- const saved = await setMuniIssueResponse(id, input.clientId, {
137
- status: "resolved",
138
- text: "Fixed",
139
- imageUrl: "https://example.com/a.png",
140
- });
141
-
142
- expect(saved).toBe(true);
143
- const issue = await getMuniIssueById(id);
144
- expect(issue?.status).toBe("resolved");
145
- expect(issue?.response).toMatchObject({
146
- text: "Fixed",
147
- imageUrl: "https://example.com/a.png",
148
- });
149
- expect(issue?.response?.createdAt).toBeInstanceOf(Date);
150
- });
151
-
152
- it("should lock the issue: no second response and no status change", async () => {
153
- const input = createMuniIssueInput();
154
- const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
155
- await setMuniIssueResponse(id, input.clientId, { status: "resolved", text: "First" });
156
-
157
- expect(
158
- await setMuniIssueResponse(id, input.clientId, { status: "in_progress", text: "Second" }),
159
- ).toBe(false);
160
- expect(await updateMuniIssueStatus(id, input.clientId, "in_progress")).toBe(false);
161
-
162
- const issue = await getMuniIssueById(id);
163
- expect(issue?.status).toBe("resolved");
164
- expect(issue?.response?.text).toBe("First");
165
- });
166
- });
167
94
  });
@@ -28,7 +28,6 @@ describe("muniIssues setup", () => {
28
28
  expect.arrayContaining([
29
29
  "callSid_1",
30
30
  "createdAt_-1",
31
- "clientId_1_createdAt_-1",
32
31
  "jira_key_unique",
33
32
  ]),
34
33
  );
@@ -3,7 +3,6 @@ export * from "./muniIssues.setters";
3
3
  export * from "./muniIssues.setup";
4
4
  export {
5
5
  MUNI_ISSUES_COLLECTION,
6
- MUNI_ISSUE_STATUSES,
7
6
  MUNI_ISSUE_SYNC_STATUSES,
8
7
  MUNI_ISSUE_TEXT_MAX_LENGTH,
9
8
  MUNI_ISSUE_NAME_MAX_LENGTH,
@@ -14,9 +13,5 @@ export type {
14
13
  MuniIssueContent,
15
14
  MuniIssueJira,
16
15
  MuniIssueSyncStatus,
17
- MuniIssueStatus,
18
- MuniIssueResponse,
19
16
  CreateMuniIssueInput,
20
- SetMuniIssueResponseInput,
21
- FindMuniIssuesOptions,
22
17
  } from "./muniIssues.types";
@@ -4,14 +4,6 @@ export const MUNI_ISSUES_COLLECTION = "muniIssues";
4
4
  /** Sync state of the issue's Jira ticket at write time. */
5
5
  export const MUNI_ISSUE_SYNC_STATUSES = ["created", "failed"] as const;
6
6
 
7
- /** Customer-facing complaint status, set manually by the TalkPilot team. */
8
- export const MUNI_ISSUE_STATUSES = [
9
- "in_review",
10
- "in_progress",
11
- "resolved",
12
- "no_issue_found",
13
- ] as const;
14
-
15
7
  /** Max length for the long free-text fields — well above the ~2000-char target. */
16
8
  export const MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
17
9
 
@@ -1,6 +1,6 @@
1
- import { Collection, Filter, ObjectId } from "mongodb";
1
+ import { Collection, ObjectId } from "mongodb";
2
2
  import { getDb } from "../index";
3
- import { FindMuniIssuesOptions, MuniIssue } from "./muniIssues.types";
3
+ import { MuniIssue } from "./muniIssues.types";
4
4
  import { MUNI_ISSUES_COLLECTION } from "./muniIssues.constants";
5
5
 
6
6
  export const getMuniIssuesCollection = (): Collection<MuniIssue> => {
@@ -22,47 +22,3 @@ export const getMuniIssueByJiraKey = async (
22
22
  ): Promise<MuniIssue | null> => {
23
23
  return getMuniIssuesCollection().findOne({ "jira.key": jiraKey });
24
24
  };
25
-
26
- // Tracked issues of one client. Issues without a status predate complaint tracking and are excluded.
27
- const clientIssuesFilter = (
28
- clientId: string,
29
- answered?: boolean,
30
- ): Filter<MuniIssue> => ({
31
- clientId,
32
- status: { $exists: true },
33
- ...(answered !== undefined && { response: { $exists: answered } }),
34
- });
35
-
36
- /** A client's tracked issues, newest first. */
37
- export const findMuniIssuesByClient = async (
38
- clientId: string,
39
- { answered, skip = 0, limit = 0 }: FindMuniIssuesOptions = {},
40
- ): Promise<MuniIssue[]> => {
41
- return getMuniIssuesCollection()
42
- .find(clientIssuesFilter(clientId, answered))
43
- .sort({ createdAt: -1 })
44
- .skip(skip)
45
- .limit(limit)
46
- .toArray();
47
- };
48
-
49
- export const countMuniIssuesByClient = async (
50
- clientId: string,
51
- { answered }: Pick<FindMuniIssuesOptions, "answered"> = {},
52
- ): Promise<number> => {
53
- return getMuniIssuesCollection().countDocuments(
54
- clientIssuesFilter(clientId, answered),
55
- );
56
- };
57
-
58
- /** One tracked issue, only if it belongs to the client. */
59
- export const getMuniIssueByIdForClient = async (
60
- id: string,
61
- clientId: string,
62
- ): Promise<MuniIssue | null> => {
63
- if (!ObjectId.isValid(id)) return null;
64
- return getMuniIssuesCollection().findOne({
65
- ...clientIssuesFilter(clientId),
66
- _id: new ObjectId(id),
67
- });
68
- };
@@ -1,6 +1,5 @@
1
1
  import type { Document, IndexDescription } from "mongodb";
2
2
  import {
3
- MUNI_ISSUE_STATUSES,
4
3
  MUNI_ISSUE_SYNC_STATUSES,
5
4
  MUNI_ISSUE_TEXT_MAX_LENGTH,
6
5
  MUNI_ISSUE_NAME_MAX_LENGTH,
@@ -56,25 +55,12 @@ export const muniIssuesJsonSchema: Document = {
56
55
  },
57
56
  },
58
57
  createdAt: { bsonType: "date" },
59
- status: { enum: [...MUNI_ISSUE_STATUSES] },
60
- response: {
61
- bsonType: "object",
62
- required: ["text", "createdAt"],
63
- properties: {
64
- text: { bsonType: "string", maxLength: MUNI_ISSUE_TEXT_MAX_LENGTH },
65
- imageUrl: { bsonType: "string" },
66
- createdAt: { bsonType: "date" },
67
- },
68
- },
69
- updatedAt: { bsonType: "date" },
70
58
  },
71
59
  };
72
60
 
73
61
  export const muniIssuesIndexes: IndexDescription[] = [
74
62
  { key: { callSid: 1 }, name: "callSid_1" },
75
63
  { key: { createdAt: -1 }, name: "createdAt_-1" },
76
- // Complaint list: one municipality's issues, newest first.
77
- { key: { clientId: 1, createdAt: -1 }, name: "clientId_1_createdAt_-1" },
78
64
  // Unique: one stored document per Jira ticket, guarding against duplicate writes.
79
65
  { key: { "jira.key": 1 }, name: "jira_key_unique", unique: true },
80
66
  ];
@@ -1,10 +1,5 @@
1
- import { Filter, ObjectId } from "mongodb";
2
- import {
3
- CreateMuniIssueInput,
4
- MuniIssue,
5
- MuniIssueStatus,
6
- SetMuniIssueResponseInput,
7
- } from "./muniIssues.types";
1
+ import { ObjectId } from "mongodb";
2
+ import { CreateMuniIssueInput, MuniIssue } from "./muniIssues.types";
8
3
  import { getMuniIssuesCollection } from "./muniIssues.getters";
9
4
  import { ensureMuniIssuesCollectionOnce } from "./muniIssues.setup";
10
5
 
@@ -15,7 +10,6 @@ export const createMuniIssue = async (
15
10
  ): Promise<ObjectId> => {
16
11
  await ensureMuniIssuesCollectionOnce();
17
12
 
18
- const now = new Date();
19
13
  const issue: MuniIssue = {
20
14
  _id: id,
21
15
  ...issueData,
@@ -23,58 +17,8 @@ export const createMuniIssue = async (
23
17
  ...issueData.jira,
24
18
  syncStatus: issueData.jira.syncStatus ?? "created",
25
19
  },
26
- status: "in_review",
27
- createdAt: now,
28
- updatedAt: now,
20
+ createdAt: new Date(),
29
21
  };
30
22
  const { insertedId } = await getMuniIssuesCollection().insertOne(issue);
31
23
  return insertedId;
32
24
  };
33
-
34
- // An issue of this client that is tracked (has a status) and not yet answered.
35
- // The `response` condition is the lock: once answered, no further writes match.
36
- const openIssueFilter = (id: string, clientId: string): Filter<MuniIssue> => ({
37
- _id: new ObjectId(id),
38
- clientId,
39
- status: { $exists: true },
40
- response: { $exists: false },
41
- });
42
-
43
- /** Changes the status of an unanswered issue. Returns false if none matched. */
44
- export const updateMuniIssueStatus = async (
45
- id: string,
46
- clientId: string,
47
- status: MuniIssueStatus,
48
- ): Promise<boolean> => {
49
- if (!ObjectId.isValid(id)) return false;
50
- await ensureMuniIssuesCollectionOnce();
51
-
52
- const { matchedCount } = await getMuniIssuesCollection().updateOne(
53
- openIssueFilter(id, clientId),
54
- { $set: { status, updatedAt: new Date() } },
55
- );
56
- return matchedCount > 0;
57
- };
58
-
59
- /** Saves the single TalkPilot response, which locks the issue. Returns false if none matched. */
60
- export const setMuniIssueResponse = async (
61
- id: string,
62
- clientId: string,
63
- { status, text, imageUrl }: SetMuniIssueResponseInput,
64
- ): Promise<boolean> => {
65
- if (!ObjectId.isValid(id)) return false;
66
- await ensureMuniIssuesCollectionOnce();
67
-
68
- const now = new Date();
69
- const { matchedCount } = await getMuniIssuesCollection().updateOne(
70
- openIssueFilter(id, clientId),
71
- {
72
- $set: {
73
- status,
74
- response: { text, ...(imageUrl && { imageUrl }), createdAt: now },
75
- updatedAt: now,
76
- },
77
- },
78
- );
79
- return matchedCount > 0;
80
- };
@@ -1,22 +1,10 @@
1
1
  import { ObjectId } from "mongodb";
2
2
 
3
3
  import { CityName } from "../utils/types";
4
- import {
5
- MUNI_ISSUE_STATUSES,
6
- MUNI_ISSUE_SYNC_STATUSES,
7
- } from "./muniIssues.constants";
4
+ import { MUNI_ISSUE_SYNC_STATUSES } from "./muniIssues.constants";
8
5
 
9
6
  export type MuniIssueSyncStatus = (typeof MUNI_ISSUE_SYNC_STATUSES)[number];
10
7
 
11
- export type MuniIssueStatus = (typeof MUNI_ISSUE_STATUSES)[number];
12
-
13
- /** The single TalkPilot response; once set, the complaint is locked. */
14
- export type MuniIssueResponse = {
15
- text: string;
16
- imageUrl?: string;
17
- createdAt: Date;
18
- };
19
-
20
8
  export type MuniIssueContent = {
21
9
  issuerName: string;
22
10
  issuerRole: string;
@@ -37,31 +25,13 @@ export type MuniIssue = {
37
25
  issueContent: MuniIssueContent;
38
26
  jira: MuniIssueJira;
39
27
  createdAt: Date;
40
- // Complaint tracking (CP-1888). Optional: issues created before it have none
41
- // of these, which is how they are kept out of tracking.
42
- status?: MuniIssueStatus;
43
- response?: MuniIssueResponse;
44
- updatedAt?: Date;
45
28
  };
46
29
 
47
- // _id/createdAt/status/updatedAt are set on insert; jira.syncStatus defaults to
48
- // "created" because the issue is only stored after its Jira ticket exists (CP-1115).
30
+ // _id/createdAt are set on insert; jira.syncStatus defaults to "created"
31
+ // because the issue is only stored after its Jira ticket exists (CP-1115).
49
32
  export type CreateMuniIssueInput = Omit<
50
33
  MuniIssue,
51
- "_id" | "createdAt" | "jira" | "status" | "response" | "updatedAt"
34
+ "_id" | "createdAt" | "jira"
52
35
  > & {
53
36
  jira: { key: string; syncStatus?: MuniIssueSyncStatus };
54
37
  };
55
-
56
- export type SetMuniIssueResponseInput = {
57
- status: MuniIssueStatus;
58
- text: string;
59
- imageUrl?: string;
60
- };
61
-
62
- /** `answered` filters by whether a TalkPilot response exists; omit it for all issues. */
63
- export type FindMuniIssuesOptions = {
64
- answered?: boolean;
65
- skip?: number;
66
- limit?: number;
67
- };
@@ -107,12 +107,12 @@ describe("db.calls", () => {
107
107
 
108
108
  const results = await Promise.all([
109
109
  setCallEndedBy(call.callSid, "user"),
110
- setCallEndedBy(call.callSid, "system"),
110
+ setCallEndedBy(call.callSid, "human"),
111
111
  ]);
112
112
 
113
113
  expect(results.filter(Boolean)).toHaveLength(1);
114
114
  const stored = await getCallByCallSid(call.callSid);
115
- expect(stored?.endedBy).toBe(results[0] ? "user" : "system");
115
+ expect(stored?.endedBy).toBe(results[0] ? "user" : "human");
116
116
  });
117
117
 
118
118
  it("should return false when the call does not exist", async () => {
@@ -48,9 +48,10 @@ export const CallStatusValues = {
48
48
 
49
49
  export const ALL_CALL_STATUSES = Object.values(CallStatusValues);
50
50
 
51
- /** Who ended a connected call: our platform, the bot (end flow), or the caller. */
51
+ /** Who ended a connected call: our platform, the AI agent (end flow), the caller, or a human agent. */
52
52
  export const CallEndedByValues = {
53
53
  System: "system",
54
54
  Agent: "agent",
55
55
  User: "user",
56
+ Human: "human",
56
57
  } as const;
@@ -1,60 +0,0 @@
1
- import { createMuniIssue, setMuniIssueResponse } from "../muniIssues.setters";
2
- import {
3
- countMuniIssuesByClient,
4
- findMuniIssuesByClient,
5
- generateMuniIssueId,
6
- getMuniIssueByIdForClient,
7
- getMuniIssuesCollection,
8
- } from "../muniIssues.getters";
9
- import { createMuniIssueInput } from "../../../test-utils/factories";
10
-
11
- const CLIENT = "client-a";
12
-
13
- const createIssue = async (clientId = CLIENT) =>
14
- (await createMuniIssue(createMuniIssueInput({ clientId }), generateMuniIssueId())).toString();
15
-
16
- describe("muniIssues getters (complaint tracking)", () => {
17
- describe("findMuniIssuesByClient / countMuniIssuesByClient", () => {
18
- it("should return only the client's tracked issues, newest first", async () => {
19
- const older = await createIssue();
20
- const newer = await createIssue();
21
- await createIssue("client-b");
22
- // An issue created before complaint tracking has no status.
23
- await getMuniIssuesCollection().insertOne({
24
- ...createMuniIssueInput({ clientId: CLIENT }),
25
- _id: generateMuniIssueId(),
26
- jira: { key: "CP-legacy", syncStatus: "created" },
27
- createdAt: new Date(),
28
- });
29
-
30
- const issues = await findMuniIssuesByClient(CLIENT);
31
-
32
- expect(issues.map((i) => i._id.toString())).toEqual([newer, older]);
33
- expect(await countMuniIssuesByClient(CLIENT)).toBe(2);
34
- });
35
-
36
- it("should filter by answered and apply skip/limit", async () => {
37
- const answered = await createIssue();
38
- await createIssue();
39
- await createIssue();
40
- await setMuniIssueResponse(answered, CLIENT, { status: "resolved", text: "Done" });
41
-
42
- expect(await countMuniIssuesByClient(CLIENT, { answered: true })).toBe(1);
43
- expect(await countMuniIssuesByClient(CLIENT, { answered: false })).toBe(2);
44
- expect(
45
- (await findMuniIssuesByClient(CLIENT, { answered: true }))[0]._id.toString(),
46
- ).toBe(answered);
47
- expect(await findMuniIssuesByClient(CLIENT, { skip: 1, limit: 1 })).toHaveLength(1);
48
- });
49
- });
50
-
51
- describe("getMuniIssueByIdForClient", () => {
52
- it("should return the issue only for its own client", async () => {
53
- const id = await createIssue();
54
-
55
- expect((await getMuniIssueByIdForClient(id, CLIENT))?._id.toString()).toBe(id);
56
- expect(await getMuniIssueByIdForClient(id, "client-b")).toBeNull();
57
- expect(await getMuniIssueByIdForClient("not-a-valid-id", CLIENT)).toBeNull();
58
- });
59
- });
60
- });