Let chosen people on a customer's side approve Clara's held messages, picked separately for each module.
Decided 8 October 2026 · Building
The idea: today only PropFlow approves messages Clara holds in Supervised. Now each module (Maintenance, Leasing, …) gets its own list of reviewers on our customers page. When a module is on Supervised, its held messages go to our Slack and to that module's reviewers. Whoever approves first wins.
Modules ┌──────────────────────────────────────────────────────────────┐ │ Maintenance Supervised ▾ │ │ ↳ reviewers: Dana (PM), Joe (handyman, vendor) [+ Add]│ │ Leasing Supervised ▾ │ │ ↳ reviewers: Priya (leasing lead) [+ Add]│ │ Renewals Live ▾ (reviewers only matter on Supervised) │ └──────────────────────────────────────────────────────────────┘ [+ Add] → pick from their team or vendors (suggested list), or type an email (checked)
No new switch. Nobody picked = only PropFlow reviews, same as today. Reviewers can be anyone on the company's team or one of its vendors (so a handyman already on file works), and they approve by replying to the email. Open question: someone typed in who is neither: do we invite them to a login first, or is their email enough?
"Clara has a reply waiting for your approval at Camellia." One link, or reply "approve" / "reject".
Who it's to, the message, and why it was held. Two buttons: Approve, Reject (with a reason).
It goes out (or, at night, at 8am). The conversation shows it as sent. Our Slack card shows who approved.
They only ever see Approve and Reject (asking for changes comes later). Off / Supervised / Live stays ours to set.
The approve/reject step already accepts a customer admin for their own buildings (it will need to accept a chosen reviewer). The held-messages list is already limited to a customer's own buildings. The "Held, awaiting approval" badge already shows in their conversations. Night approvals now send at 8am.
Reviewers per module. A held-message page customers can open (today's lives in our staff area and turns them away). The email to the reviewers, and reading their reply. Naming the customer who approved. Fede is hard-coded as the one reviewer.
Only prospect emails, only in Slack: reply "make it shorter" and Clara rewrites it, as many rounds as you like. Texts and every other held message can't be rewritten. A reply like "why?" on those rejects the message. Nobody can ask Clara a question about a draft.
An Ask for changes box on the held-message page and in Slack, for every kind of held message. Clara rewrites it and shows the new version, then you Approve. An Ask Clara why option answers without changing the draft.
Held message · Reply to Ana · Camellia "Hi Ana, a plumber will come Thursday 9–11am." [ Approve ] [ Reject ] [ Ask for changes ▾ ] [ Ask Clara why ] ↳ "Say the window is 9am–noon" → Clara rewrites → shows new draft → Approve
Your worry is right. Everything Clara sends already leaves through one door, the Off / Supervised / Live gate. Replies from a customer's team come back through five different doors, and each one decides on its own who wrote, what they're answering and what they want. So the same reply means different things depending on where it lands, and a fix in one place doesn't reach the others.
Every reply from a customer's team or owner, by email, Slack or text, goes through the same four steps before anything else:
If a known team member or owner writes and nothing matches, a person is alerted. Nothing disappears silently again.
DOOR OUT (exists) DOOR IN (to build)
Clara ─► Off / Supervised / Live ─► send reply ─► who? ─► answering what? ─► wants what? ─► one handler
│ ▲
└──── stamps a tag ────────┘ (email: tag in the address · Slack: the thread · text: last message to that number)
| Part | What it does | Works on its own? |
|---|---|---|
| 0 | Write it down: a decision record saying "one door in for staff replies", next to the door-out record. Update the "customers never review" wording. | Yes, wording only |
| 1 | Reviewers per module on our customers page, the held-message page, and the email to the reviewers, with a tag on the email. A reply of "approve" or "reject" by email is matched and acted on. Unmatched replies from known team members or owners alert a person. Email only, approve/reject only. | Yes: the whole door, one channel, end to end |
| 2 | Move today's escalation and team-notice reply handling (two copies of each) behind the same door, and fix the wrong saved message number. Tag the owner report and team notices. This is where "fix once" starts paying. | Yes |
| 3 | Slack and text replies join the door. Owners become a known kind of person everywhere. The nine separate "who is this?" checks become one. | Yes |
| Later | Ask for changes and Ask Clara why ride the same door, so they work the same on every channel. | Yes |
| Sent to staff/owners | Channel | Can a reply be matched? |
|---|---|---|
| Weekly owner report | No; reply dropped | |
| Team notices: holdover, lease signed, leases ending, key pickup, quiet leads | No; reply dropped | |
| Team notifications: handoffs, missed call, after-hours, tour updates | email + text | Meant to, but broken: SendGrid's id saved instead of ours; reply tag only sent to SendGrid, never on the email |
| Escalation decision request | email + text | Yes, by message number |
| Held-message cards | Slack | Yes, by thread (channel not checked) |
| Renewal review, maintenance page, staff tour alerts, text-on-ring | email / text | No |
| Where a reply lands | How it's read | "Why?" becomes |
|---|---|---|
| Slack, held text or held workflow email | exact-word list | reject |
| Slack, held prospect email | exact-word list, else AI | rewrite |
| Email, escalation | AI reader | a follow-up question |
| Text, tenant confirmation | separate AI reader | nothing happens |
| Email, team notification | not read | would be passed on as the answer (if it ever matched) |
Read from the code on main, 8 October 2026. The two "broken" findings were checked by hand: team-notify/live-deps.ts saves SendGrid's x-message-id, not our internetMessageId, and the reply key is passed only as customArgs, never as the +rk_ address or X-PropFlow-Reply-Key header that inbound-email-reply.ts reads.
| Question | Answer |
|---|---|
| Which held messages can the customer's people approve? | Everything at their buildings. |
| Who approves? | A chosen list of people, separate for each module. On our customers page: pick from their team (multi-select, a suggested list to start from) or type any email, checked for validity. Maintenance can include a handyman. |
| A new switch? | No. The existing Off / Supervised / Live switch per module stays. Picking reviewers for a module is what sends its held messages to them as well as to our Slack. Nobody picked = only us, as today. |
| A casual Slack reply on a held text? | An unclear reply gets a question back. Never a reject on a guess. |
| Owner replies to the weekly report? | Answered by the Ask Clara brain already in the app, after we know who they are from their email and check what they may see. Unknown senders: a person is alerted. |
| Newsletter? | None for now. |