Every action the placement team takes, written as a row, as a side effect of them doing their normal work. One append-only stream. No new clicks, no message text, no checklists.
Each row is a fact in the past tense. Nothing is interpreted at write time — status, gaps, dashboards and rubrics are all read out of the log later, never written into it.
Roughly a third of this is already being recorded somewhere — it's just scattered across eight separate tables that don't talk to each other. The rest is new.
Already captured today. Needs moving or copying into the stream, not inventing.
The underlying thing is recorded, but not as an event you can read in sequence — it's buried in a booking record or a provider's history.
Nothing is recorded at all. The action fires and vanishes.
Another system already logs this properly. The job is joining it up, not rebuilding it.
Thirty-five event types across ten areas. This is the thing to argue with — add, cut, or tell me a row is carrying the wrong facts.
| Event | Fires when | What the row carries | Status |
|---|---|---|---|
| The call | |||
| Call started | The agent dials out, or an inbound call rings. | call id direction number dialled |
PartialOnly one row is written today, at hang-up — there's no record of the attempt itself. |
| Call ended | Either side hangs up. | call id connected y/n seconds |
Live |
| Outcome recorded | The agent marks the booking after the call. | outcome booking id |
PartialThe only outcomes that exist are “completed” and “no-show”. Everything else is invisible. |
| Wrap card saved | The agent taps through the post-call card. | the tapped options call id |
Live |
| Transcription started | The client consents and the agent starts captions. | call id consent given — the fact only, never a word of it |
To build |
| Call assessment written | The AI reviewer scores the agent at hang-up. | assessment id call id |
Live |
| Matching | |||
| Matcher run | Every single search, not just the last one. The trail is the evidence. | filters used what the form said what changed result count top therapists + scores |
To buildNothing about searching is recorded today. This is the row that derives “couldn't find anyone”. |
| Therapist profile opened | The agent opens a card to read it properly. | therapist id their score position in results |
To buildOpen question — is this useful evidence of the work, or noise? Your call. |
| The recommendation | |||
| Recommendation sent | The agent sends the client their shortlist. | link token therapists in order score vs the form score vs the call full match breakdown channel |
To buildRecords absolutely nothing today. The scores must be snapshotted — recomputing later gives a different answer. |
| Money | |||
| Payment link sent | The agent sends the checkout link. | therapist id price link slug channel message id |
To buildRecords nothing today. |
| Payment link clicked | The client opens it for the first time. | link slug |
Live |
| Payment received | The order completes. | order id amount therapist paid for |
Live |
| Sessions — with the therapist | |||
| Session booked | The client is booked in with their therapist — usually by the agent right after they pay on the call. | booking id therapist date & time booked by agent or self-serve |
PartialWritten into the booking record, not readable as a sequence — and the agent-booked vs self-serve route isn't distinguished at all. |
| Session cancelled or moved | A booking changes after the fact. | booking id old & new time cancelled by client, agent or therapist |
Partial |
| Refund requested | A cancellation is escalated for a refund. | order id who asked reason |
To buildRefunds are gated, so the request and the decision are two separate facts worth keeping apart. |
| Refund issued | The money goes back. | order id amount who approved reason the booking it relates to |
To buildThe link between the cancellation, the refund and the original session is what makes “why did this happen” answerable. |
| Calls — with the placement team | |||
| Follow-up call booked | A second call with the placement team is scheduled. | booking id which agent date & time booked by agent or self-serve |
Partial |
| Follow-up call cancelled or moved | That call changes. | booking id old & new time who did it |
Partial |
| Automatic emails — sent by the system, not by a person | |||
| Automatic email to client | Session completed, reorder prompt, renewal heads-up, and the rest. | which email session id order id sent or failed |
ElsewhereSession Accounting already logs every one of these — attempt, sent and failed — in its own audit log. |
| Automatic email to therapist | A client is placed with them, a block completes, a payment lands. | which email therapist session id sent or failed |
Elsewhere |
| Automatic email failed | A send doesn't go out. | which email recipient why |
ElsewhereThe most valuable row on this whole page and nobody currently sees it on a client's timeline. |
| Communication — the action and the pointer, never the words | |||
| Text sent | The agent sends an SMS from the cockpit. | Twilio message id which number |
BlockedThe send returns only true/false — the message ID is thrown away. Has to be fixed at the send before there's anything to point at. |
| Text received | A client texts in. | Twilio message id which number — no content |
Partial |
| Email sent | The agent sends from the composer. | Gmail message id thread id which address |
To buildBoth IDs already come back from the send — they're just not kept. |
| Email received | A client replies. | Gmail message id thread id — no content |
Partial |
| Voicemail received | A missed call leaves a message. | recording id seconds caller |
Partial |
| Therapist messaged | The agent writes to the client's therapist. | Gmail thread id therapist id |
To build |
| Meeting link sent | The agent sends the client their session link. | booking id channel message id |
To buildDepends on the Copy button coming out — see below. |
| Login link sent | The agent gets the client into their account. | auto-login or reset channel message id |
To buildCopy-only today — a send button has to exist before the copy can go. |
| Note added | The agent writes a note on the client. | note id |
Live |
| Intent — what we said we'd do next | |||
| Chase date set | The agent picks a date to check back in. | the date |
Live |
| Chase date cleared | The date is removed without closing. | — | Live |
| Chase closed | The agent stops chasing for good. | reason |
Live |
| Identity | |||
| Alias added or removed | A second email or number is tied to a client. | the identity added or removed |
Live |
| Therapist thread assigned | A therapist conversation is tied to a client. | thread id client reassigned from |
Live |
The cockpit and DataHub share a VPS, so the log is written directly into DataHub's Postgres — not into WordPress, and not pulled from anywhere.
ops. That's already where DataHub keeps the tables its own app writes — identity joins, households, pinned items, planner scenarios, team notes. None of those are pulled from WordPress either. The cockpit log is another one of them, written over localhost the moment an agent does something.
Worth stating plainly, because every one of these is a thing someone will eventually suggest adding.
A copied link leaves no trace — the agent pastes it wherever and the log goes blind. Three places have one today.
None of this is being built now. It's here so you can check the log carries enough to make it possible.