Product · Identity · Consent
CRM
Knowing that three records are one person
One CRM across the resort, the coffee shop and the store. Scored identity resolution rather than a customer table, segments derived from transactions rather than tags, and consent that has to be proved before anybody can be contacted.
- TypeScript
- React
- Vitest
- 55 tests
Possible duplicates · 5
Ana Cruz ↔ ana dela cruz
- Same phone number (+639171234567)
- Names are similar (85%)
ana dela cruz ↔ Ana Dela Cruz
- Same email address (ana.cruz@example.com)
- Names match
Maria Santos ↔ Maria Santos
- Names match
Roberto Bautista ↔ Elena Bautista
- Same phone number (+639204444444)
- Names do not match — could be a shared phone or address
Ana Cruz ↔ Ana Dela Cruz
- Names are similar (85%)
Only a shared phone or email reaches certain. Two people called Maria Santos score high enough to review and never high enough to merge automatically — welding two real customers together is far harder to undo than leaving a duplicate.
Customers · 9
| Customer | Segment | Seen in | Visits | Lifetime | Last | |
|---|---|---|---|---|---|---|
| Jose Rizal+639215555555 · jose@example.com | lapsed | Resort, Coffee shop | 3 | ₱84,810.00 | 340d | no |
| Ana Cruz+639171234567 | at-risk | Resort | 2 | ₱60,300.00 | 120d | may contact |
| Roberto Bautista+639204444444 | at-risk | Resort | 1 | ₱19,500.00 | 140d | no |
| ana dela cruz+639171234567 · ana.cruz@example.com | promising | Coffee shop | 2 | ₱705.00 | 12d | no |
| Maria Santos+639193333333 · m.santos@example.com | loyal | Coffee shop, Store | 3 | ₱663.00 | 2d | may contact |
| Ana Dela Cruzana.cruz@example.com | new | Store | 1 | ₱612.00 | 5d | no |
| Elena Bautista+639204444444 | at-risk | Coffee shop | 1 | ₱390.00 | 70d | no |
| Maria Santos+639182222222 | lapsed | Store | 1 | ₱240.00 | 190d | no |
| Lito Ramos+639226666666 | new | Store | 1 | ₱96.00 | 6d | no |
Campaign audience
2 of 9 contactable
The default is no. A customer with no consent record cannot be marketed to, and a withdrawal on one channel does not touch the other — unsubscribing from SMS leaves email alone, and the reverse.
- Ana Cruz: email yes (booking form), sms no (STOP reply)
- ana dela cruz: no record
- Ana Dela Cruz: no record
- Maria Santos: no record
- Maria Santos: email yes (counter sign-up)
- Roberto Bautista: no record
- Elena Bautista: no record
- Jose Rizal: email no (unsubscribe link)
- Lito Ramos: sms yes (receipt opt-in)
Seen in more than one business · 2
- Jose RizalResort + Coffee shop
- Maria SantosCoffee shop + Store
This is the reason to run one CRM over three businesses rather than three lists. Without it the resort and the coffee shop each see a stranger, and neither knows the other is serving the same person.
Ana appears three times: she booked a villa by phone, ordered coffee with the same number written differently, and bought groceries under a fuller name with an email. Until those are merged her lifetime value is split across three records and none of them looks like a customer worth keeping. Merge them and watch her become the most valuable person on the list.
Then look at the two Maria Santoses. They score high enough to review and never high enough to merge automatically, because a name is not evidence of identity. Roberto and Elena Bautista share a handset — same phone, different people — and that pair is flagged for exactly the same reason.
What this is, and what it is not
This is the part of the product that is worth building carefully: the rules that decide what can be sold, for how much, and what happens when the answer is no. It is a real engine with tests beside it, running in your browser with no server involved.
It is not a whole product. There is no login, no database and no payment provider — those are known quantities, and building them here would demonstrate nothing that the interesting half does not already demonstrate better. State lives in the page and resets when you reload it.
Read the full case study