Brownstone product flow

← Dashboard

Gray nodes are Firestore collections (same as Data Tables). Green nodes are ops actions — click one to jump to What code writes.

Table Action
After interview accept, admin only sends the reserve link. 1st month’s rent / PayPal (outside this repo) creates the resident + stay and marks the applicant converted.

Lifecycle

Happy path down the center. Side columns: deny/waitlist exits, inventory, email log, support tickets.

What code writes

Each green action above links to a row here.

ActionCodeTables
Apply Typeform / import applicants
Approve POST /api/applications/:id/approve applicants · email_events
Move to waitlist POST /api/applications/:id/move-to-waitlist waitlist_entries · applicants
Deny / Spam POST …/deny|spam applicants — terminal
Calendly sync calendlyWebhook / syncCalendlyInterviews interviews
Interview accept POST /api/interviews/:id/decision interviews · applicants · email_events — no stay
Interview deny same decision endpoint interviews · applicants — terminal
1st month’s rent Outside repo (brownstone.live/reserve · PayPal) residents · stays · charges · payments · payment_allocations · applicants
Daily rent job generateRentChargesDaily (06:00 PT) charges only
2nd / future months’ rent Payments UI / API payments · payment_allocations · charge balances
Move-out POST /api/beds/:podId/process-move-out stays · charges · beds · residents (if now)
Support import Spreadsheet import (offline path) support_tickets

Data tables

Same set as the Data Tables tab, plus interviews. Links = foreign keys / common joins.

CollectionRoleLinks to
properties Houses
beds Inventory units properties via property_id
bed_property_assignments Bed ↔ house over time beds · properties
applicants Funnel people properties (desired_property_id) · residents (converted_resident_id)
waitlist_entries Per-property queue properties · optional applicants / residents
interviews Calendly / manual calls optional applicants · optional residents
residents Billing / occupancy party optional applicants · optional interviews (interview_id / interview_ids)
stays Open-ended bed terms residents · beds · properties
charges Invoices / periods stays · residents · optional properties
payments Cash in residents · optional properties
payment_allocations Payment → charge payments · charges
email_events Outbound send log optional applicants · residents · properties · stays · charges
support_tickets Maintenance / ops tickets properties · optional residents · beds · stays

Known missing from the code

Things the lifecycle implies, but this admin repo does not implement (or only partially).

GapWhat’s missing
1 In-admin conversion After interview accept, admin only sends the reserve link. Creating resident + stay + first charge/payment lives outside this repo (PayPal / 1st month’s rent).
2 Waitlist → bed Marking a waitlist row “converted” does not create a resident, stay, charges, or bed assignment. Offer → 1st month’s rent is still a manual handoff.
3 Stay creation job No scheduler creates stays. The daily job only writes new monthly charges for existing active stays.
4 Email delivery truth email_events records SendGrid accept, not inbox delivery. Bounces / opens need a SendGrid Event Webhook that is not wired here.
5 Interviews in Data Tables interviews is live product data but not on the Data Tables whitelist — only the Interviews UI / API.
6 Unified status model Interview accept writes accepted; funnel/types mostly track approved / converted; waitlisted lands in “other.” No single status vocabulary across surfaces.
Quick map: applicant → funnel person · waitlist → property queue · interview → decision · resident → who pays · stay → bed term · charge / payment / allocation → ledger · email_events → send log