Customer Approvals Plan

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.

Reviewers per module, on our customers page

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?

What the customer sees
1 · Email

"Clara has a reply waiting for your approval at Camellia." One link, or reply "approve" / "reject".

→
2 · Held message page

Who it's to, the message, and why it was held. Two buttons: Approve, Reject (with a reason).

→
3 · Done

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.

What already exists, and what's missing

✅ Already built

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.

🛠 Missing

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.

Asking for changes

Today

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.

Planned

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

One door in, one door out

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.

What we found today

  • A reply to the weekly owner report or to a team notice (lease signed, key pickup, leases ending, quiet leads) is thrown away with no alert. Nobody sees it.
  • Replies to Clara's team emails about handoffs and missed calls are meant to be matched, but never are: we save the wrong message number, and the tag the reader looks for is never put on the email.
  • "Why?" in Slack rejects a held text, but on a prospect email it rewrites the draft. By email it gets a follow-up question.
  • Owners are only recognised on escalation emails. Anywhere else, Clara doesn't know who they are.
  • There is no newsletter to customers' teams in the system today.

The fix: one staff-reply door

Every reply from a customer's team or owner, by email, Slack or text, goes through the same four steps before anything else:

  1. Who is this? One check, which also knows about owners.
  2. What are they answering? Everything we send them carries a tag, and the reply carries it back.
  3. What do they want? Approve, reject, change it, why, a question, stop. If it's unclear, we ask; we never guess "reject".
  4. Do it. One handler per want, the same for every channel.

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)

Build order: customer approvals is the first thing through the door

PartWhat it doesWorks on its own?
0Write 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
1Reviewers 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
2Move 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
3Slack and text replies join the door. Owners become a known kind of person everywhere. The nine separate "who is this?" checks become one.Yes
LaterAsk for changes and Ask Clara why ride the same door, so they work the same on every channel.Yes
How we keep it the one door (so it can't drift)
  1. An automatic check that fails if any message to a customer's team or owner goes out without a tag. Exceptions must be written into a short, reviewed list.
  2. An automatic check that only the door may approve, reject or rewrite a held message. Anything else that tries fails the build.
  3. Texts have no threading. The best we can do is match a reply to the last thing we sent that number, and we say so rather than pretend.
Detail: every lane out and every door in (for engineers)
Sent to staff/ownersChannelCan a reply be matched?
Weekly owner reportemailNo; reply dropped
Team notices: holdover, lease signed, leases ending, key pickup, quiet leadsemailNo; reply dropped
Team notifications: handoffs, missed call, after-hours, tour updatesemail + textMeant to, but broken: SendGrid's id saved instead of ours; reply tag only sent to SendGrid, never on the email
Escalation decision requestemail + textYes, by message number
Held-message cardsSlackYes, by thread (channel not checked)
Renewal review, maintenance page, staff tour alerts, text-on-ringemail / textNo
Where a reply landsHow it's read"Why?" becomes
Slack, held text or held workflow emailexact-word listreject
Slack, held prospect emailexact-word list, else AIrewrite
Email, escalationAI readera follow-up question
Text, tenant confirmationseparate AI readernothing happens
Email, team notificationnot readwould 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.

Decided (Gera, 8 October 2026)

QuestionAnswer
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.
Things to watch
  1. Customers may approve at odd hours. Night approvals now wait for 8am and still send, so that's covered.
  2. A held message expires after 24 hours if nobody acts. With customers in the loop, both sides get the expiry notice so nothing silently disappears.
  3. A customer-facing page may overlap the customer inbox/hub another team owns. We check with them before part 1 starts.
PropFlow Docs