Key the communications spine on an owner, not a lead

Featurekamo-shared-library
Shipped
26 Agosti 2026, 01:37 UTC
Author
Kamo
Commit
78d9861

The spine was built lead-shaped — LEAD_CONTACT_POINTS.LEAD_UID, LEAD_COMMUNICATIONS.LEAD_UID — and the association it actually needs is broader. An account owns several leads, typically sharing the same point of contact because they are the same person enquiring twice. A commerce record hangs off the account rather than any one lead. And a patient chart has calls and e-mails about it and no lead at all. Keying to leads meant each of those either borrowed a lead or grew a parallel timeline. Both tables now carry the document manager's (assoc_type, assoc_object_id) pair, with LEAD, ACCOUNT, PATIENT and COMMERCE_RECORD as owners. LEAD_UID is KEPT and still filled for lead-owned rows, so every existing /leads query, index and call site is untouched — the lead-keyed repository methods and the lead timeline overload both remain, and the new owner-keyed ones sit beside them. Three things this had to get right, and one I nearly got wrong. The unique constraint moves to the owner pair. (ORG_ID, LEAD_UID, CHANNEL, SOURCE_ID) is what makes ingestion idempotent — a RingCentral call is seen twice, once by the webhook and once by the reconciliation sweep. With LEAD_UID null for a patient, Postgres treats every one of those NULLs as distinct and the second sighting inserts a duplicate. The contact-point table matters more than the timeline. Pointing a timeline at a new owner changes what is READ; inbound traffic only ever LANDS on an owner that has contact points, because that is what the linker matches against. A patient whose number is not a contact point receives calls that resolve to nobody. The one I nearly shipped: the linker de-duped matches by cp.getLeadUid(). For a non-lead contact point that is null, so seenLeads.add(null) would let exactly ONE non-lead owner through per inbound message — a call to a number two patients share would reach one of them, silently. It now de-dupes on the owner. assoc_type is a STRING, never an ordinal. Hibernate freezes a CHECK (col BETWEEN 0 AND N) over an ordinal enum column at CREATE TABLE and never revisits it, so appending a value later rejects every insert carrying it — silently, because the failing statement sits inside a @Transactional method whose rollback removes the evidence. Seven of those were found full and already breaking things on this platform in August. A stored null reads as LEAD, because every row written before the column existed is a lead's and returning null for those would blank the timeline this change exists to widen. An UNKNOWN value reads as null rather than LEAD — attaching somebody else's traffic to a lead timeline is the one wrong answer worse than none. Also in this commit: the TEFCA exchange layer (partners, the disclosure ledger, cross-organization patient matching). Its purpose codes are now the same HL7 v3 ActReason strings PhiPurposeOfUse already uses — a test caught me inventing "T" for treatment where the platform says "TREAT", and an exchange row and an audit row describe the same disclosure from two angles, so a report joining them joins on those strings. 1932 tests green.

All changes

Je, unaona nini kuhusu usafiri?

Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.

Kuwa Huru MileleMtazamo wa bei