A principal is one of your users
You register them by your id. The platform stores no vertical vocabulary:kind is a slug you choose. The platform never branches on its value, so
student, vice_principal and account_manager are all equally ordinary. A
school with six staff levels and a CRM with two do not need different releases.
attributes is for prompting and reporting only. It is never consulted
to decide what someone may see — that is what a grant is for. A JSON blob
that quietly becomes a permission system is a permission system nobody can
audit.Principals are not leads
The platform already models a customer (a person) and a lead (a sales record) — see Identity. A principal is neither. A lead requires a phone number, dedupes on it, and carriesdo_not_call.
Registering eight hundred students as leads would poison every one of those
behaviours. They stay separate, and a principal may optionally point at a
customer when the same human is both — a parent who also enquired about fees.
One person, many channels
An identity maps a channel handle to a principal, so the same person reached on WhatsApp and on the web is one principal rather than two.The session token
Your backend mints a short-lived token for the user whose browser is about to talk to the assistant. The browser presents it; it cannot mint its own.Authorization header, so a session token can never
be mistaken for a workspace key (tgcc_…) or a partner key (tgpk_…), and a
mix-up cannot silently escalate.
It carries no entitlements
The token names a person. What that person may reach is read from the database on every request instead.This is the decision the rest of the design hangs on, and the reason is
revocation: a grant withdrawn at 10:00 stops applying at 10:00, not whenever
a token happens to expire. A learner enrolled in forty units would also carry
forty ids in a header on every request, and a credential sitting in a browser
should have the smallest blast radius available. “Names a person” is smaller
than “enumerates their access”.
Refreshing cannot widen access
A live token can be exchanged for a fresh one until the refresh ceiling. The replacement is built from the stored record, never from the presented claims — so a withdrawn grant does not survive a refresh, and a tampered token that somehow verified would still only get back what the database says.Asking about somebody else
A parent’s session is about their child. The asker and the subject are different people, and both matter:- Knowledge is filtered by the asker. A parent reads the parent handbook, not the marking scheme.
- Records are reachable for the subject, and only where an explicit grant says so.
How access is actually decided
Grants, roles, deny rules, and what retrieval does with them.

