Case study · platform engineering. Meta Dados methodology (Genba · Kanso · Omotenashi).
Summary. In multi-tenant SaaS within the services domain, the same human being shows up as customer, employee, and owner — sometimes across several establishments. We model this problem as an anchored identity graph: a global entity (the person, anchored by the CPF) toward which denormalized per-tenant links converge. A controlled experiment, run against the production database within a transaction with ROLLBACK, shows that identity unifies correctly by CPF, but that the denormalized data silently diverges across tables and that a class of entry points that creates an "inline" login with a null CPF splits one human into two identities. We describe two verified interventions and derive reusable principles.
1. Introduction
Scheduling platforms treat three entities as first-class citizens — customer, employee, and establishment — each with its natural key: the customer is recognized by phone number; the employee requires a CPF; the establishment identifies itself by CNPJ + email (or CPF, for the sole proprietor). The problem arises because these three are not disjoint: a customer can be hired and become an employee; a customer can open their own business; an owner can book as a customer at another salon. The system needs information to travel between the tables and stay consistent, with no vital data diverging across different records.
We treat the Marcaê platform as a case study, but the model and the findings are general: they hold for any SaaS where an individual takes on heterogeneous roles over time and across tenants.
2. The model: anchored identity
The core idea is to separate identity from role. The person is a global entity — tenant-less, anchored by a strong key (the normalized CPF). Each link (customer, employee, user) carries a denormalized copy of the vital fields and a person_id foreign key pointing to the person. A database trigger (vincular_pessoa_por_cpf) performs the find-or-create: when a link is written with a valid CPF, it associates (or creates) the person for that CPF and sets the person_id. Without a valid CPF, the identity is local to the tenant.
3. Invariants and divergence metric
The model must guarantee two invariants. The first is identity unification (I1): two links with the same valid CPF point to the same person. The second is role completeness (I2): the person knows all the roles (tenant + role) derived from their links.
To measure the consistency of the vital data (name, email, phone), we define a divergence rate δ: the fraction of people for whom some vital field has more than one non-empty value between the anchor and its links. δ = 0 is the target — the person is the single source of truth.
4. The split-identity defect
A class of entry points creates the login account "inline" (together with the customer) using an anchoring that ignores the CPF — in practice, it always creates a new person. If a human passes through an entry point that anchors and through one that does not, they end up represented by two people — violating I1. The split rate σ grows in proportion to the use of the non-anchoring entry points. It is the highest-severity defect, because once identity is split, it can only be reconciled through a manual/SQL operation.
5. Methodology and results
We adopted Genba — going to the shop floor: instead of reasoning about the intended model, we exercised the real model. Two techniques: (1) an exhaustive reading of the 15 entry points where a customer/employee/user/owner is born or transformed, recording what each one writes and whether it anchors on the CPF; (2) transactional simulation — we instantiated identity journeys directly in the production database, inside BEGIN … ROLLBACK: the anchoring trigger actually fires, but nothing persists.
The results confirmed the model and flagged where it fails:
- I1 holds where anchoring exists — a person traversing 5 roles across 2 tenants recorded the same person_id.
- The vital data diverges — the anchor retains only what it saw first: the email the employee received later never propagated up to the person; names diverged across the tables.
- σ = 0.5 in the controlled scenario — 1 of 2 humans was split into two identities by the entry point that creates the inline login.
6. Interventions
Deduplication as an equivalence relation. The old rule collapsed two records by phone number alone; the new one requires normalized phone AND name. This way, two distinct humans who share a phone number (the mother who books from her own cell phone for her child) are no longer merged by mistake.
Merge as a field-by-field fold. When two records really are the same person, the merge stops being "pick one and discard the other" and becomes a per-field resolution: a diff table presents each divergent field side by side, and the operator chooses the value that stays on the survivor. Order matters — reattach the references and archive the removed records before applying the choice — otherwise the partial unique index collides. A merge that loses data is a regression; a field-by-field merge preserves the best of each record.
7. Discussion and principles
The case illustrates a recurring trade-off: denormalizing vital fields onto the links makes each screen fast and self-contained, at the cost of consistency; keeping the person as the single source of truth eliminates divergence, at the cost of read-time coupling. Reusable principles for any multi-tenant platform with shared identity:
- One anchor, one key. Choose a global entity and a strong key (CPF/CNPJ) and make every entry point anchor by it. A single entry point that anchors with null breaks the guarantee.
- Anchoring is a state invariant, not a role invariant. Model roles as states; the customer→employee→owner transition must preserve the person_id. "Transforming" a role means adding a link, never creating a new identity.
- Decide consistency per field. Email and phone call for a single source; local notes can live on the link. The δ metric measures the cost of each decision.
- Deduplication is an equivalence relation — choose it explicitly. "Same phone" and "same phone and name" produce different partitions.
- Reconciliation is a fold, not a discard.
8. Conclusion
Marcaê's identity unifies correctly when a CPF is present — the anchor works and is robust to role transitions. The class of entry points that split identity was closed off by a database trigger (reconciliation ensures the account follows the person of the CPF, the merge stopped generating orphan logins, and the anchor now learns the vital data it was missing). All that remains is the full single-source-of-truth — a design decision, not a defect. The gain is not only technical: it is the guarantee that a customer who becomes an employee, or an owner who becomes a customer, remains the same person throughout the entire system.
Frequently asked questions
Why not use the phone number alone to identify the person?
Because a phone number is not a strong key for a person: two distinct humans share a number (the mother who books from her own cell phone for her child), and a person changes numbers. Anchoring by CPF (a strong key, unique per individual) and using phone+name only as a deduplication relation avoids merging different humans by mistake.
Does this apply only to scheduling or to any SaaS?
The model is general. It holds for any multi-tenant SaaS where a single individual takes on heterogeneous roles over time and across tenants — marketplaces, healthcare platforms, education, property management. The principle "one anchor, one key; a role is a state, not an identity" carries across domains; what changes is the strong key and the set of vital fields.