Calendar & Onboarding — Handoff

What the calendar integration is today, how a connection actually works, what the onboarding wizard does now, and where the next phase is headed. Written for the agent picking this up, by the one who built the last stretch.

2026-09-16 · Google + Microsoft calendars, all three rungs · onboarding wizard in one straight line · last two PRs merging

Where it stands

Calendars work on both vendors at every level, and onboarding runs in one straight line. A company's shared calendar, a building's calendar, and a leasing agent's own calendar can each be Microsoft or Google. Clara books tours on any of them. The one thing we do not have is Gmail: Clara cannot read or send a company's Google mail.

RungWhat it isWhere you see itMicrosoftGoogle
CompanyOne shared calendar (and, on Microsoft, the shared leasing mailbox) for the whole company. The default shape for a new customer.Onboarding · Channels step (company shape) · Organization Settings cardmailbox + calendarcalendar only
BuildingA calendar (and mailbox) per property, for companies run per-building team.Onboarding · Channels step (per-building shape) · Property Settingslivelive
PersonA leasing agent's own calendar. Tours go in a person's day, not a building's.Onboarding · Your calendar step · first sign-in screen · Profile → My calendarlivelive

How a connection works

Every rung on every vendor is the same four-step shape. Learn it once.

Authorize routemints a signed state, writes a "started" ledger row Vendor consentMicrosoft or Google, account chooser forced on the person lane One callback per vendortells the three rungs apart by the state's shape Channel vaultone row per node + kind, provider on the row

Infrastructure

PieceWhereNotes
Google sign-inGoogle Cloud project propflow-login, PropFlow org, hello@ accountBetter Auth. Env: GOOGLE_LOGIN_CLIENT_ID / _SECRET. Moved off a personal account on 2026-09-16.
Google integrationsGoogle Cloud project propflow-integrations-508806, same orgCalendar API and Gmail API enabled. Env: GOOGLE_INTEGRATIONS_CLIENT_ID / _SECRET. One registered redirect URI: the Google calendar callback above. Verified; no ID verification was required.
Legacy Google clientGOOGLE_CLIENT_ID / _SECRETThe vendor-quote poller's old project. Not part of calendars. Leave it.
MicrosoftOne app registration (Fede's earlier in-house move)Env: MICROSOFT_CLIENT_ID / _SECRET. Company connects can hit the admin-approval wall; the vault carries a pending_admin_approval status and a silent re-ask. Google has no such wall.
DeployVercel, project propflowaiMerge to main is the production deploy. A green main run promotes; check the Production deployment's SHA before telling anyone something is live.
Gmail scopesGooglegmail.send is cheap. gmail.readonly is a restricted scope and needs Google's CASA review, unless a customer's own Workspace admin allowlists our app, which exempts us. Nothing in code uses either today.

The onboarding wizard now

1 · AppFoliorequired, no skip 2 · Syncpick buildings 3 · Reviewwhat we imported 4 · Channelscompany shape OR per-building picker, in place 5 · Your calendarMicrosoft or Google, skippable 6 · Teammatesemail only, role from the standard select, one ending Dashboard

What we don't have

Where it's going (from the 2026-09-16 founders' standup)

Testing and resetting

Accounts and companies

Resetting an onboarded admin to walk it again

There is no button for this yet. The least-resistance path is a script run from a session, dry-run by default:

npm run reset:onboarding-walk -- --email admin@testco.example            # shows what would change
npm run reset:onboarding-walk -- --email admin@testco.example --apply --confirm-table=propflow-prod
npm run reset:onboarding-walk -- --email ... --disconnect --apply --confirm-table=propflow-prod   # also ends channel hooks + disables the AppFolio credential

Ships in #8919. Without --disconnect it clears only the completion stamps (the user row's two dates and the onboarding record), so the wizard opens on whichever steps are still outstanding. With it, the company's mailbox and calendar hooks and the admin's own calendar hook are ended and the AppFolio credential is disabled, so the walk starts from the AppFolio step. Imported properties are left alone; the import is an upsert and re-running it is safe. To wipe properties too, use reset-org-sync-for-reimport.ts, which is heavier and requires sync to be paused first.

What shipped on 2026-09-16

PRWhat it did
#8841Google sign-in moved to a company-owned Google Cloud project.
#8845One multi-provider integration row, used everywhere a vendor is chosen.
#8878The channel vault refreshes Google tokens through Google; company and person rungs admit a Google row.
#8883A centralized company connects its shared Google calendar; "Calendar connected" tone in settings and onboarding.
#8884Teammates step: email-only invites, standard role select, one ending.
#8895The Microsoft-named onboarding step renamed vendor-neutral; old address redirects.
#8897A leasing agent connects their own Google calendar (first sign-in screen and My calendar).
#8902One Channels step: the company shape renders in place; both shapes continue into the wizard.
#8906Google's account chooser on the person lane, so "connect a different account" can.
#8911Your calendar as wizard step 5 of 6, with the offer stamped on render.
#8914Person-calendar links signed and session-bound on both vendors.

Gotchas the next agent will hit

Companion pages: Google Calendar, Three Rungs (the plan this executed) · Google connect flow · New customer onboarding experience.

PropFlow Docs