Skip to main content
Product changelog

What's shipped.

Product features shipped into VR Goals, dated and in reverse chronological order. Subscribe to the RSS feed.

MarketingHighlight

Marketing module completes, Learning gets gamified, and the Foundations course goes live

The Marketing module crossed from "Phase 2 backend + 3 pages" to a fully realized loop in one week. Learning shipped its Tier 3 gamification stack — achievements, streaks, points, and a profile section. And the Foundations course landed end-to-end through a new upload pipeline.

Marketing — module complete. All three sidebar surfaces finished. Underperformers page with filters (#374). Creative Library + wizard prefill (#376). Insights & ROAS page as the final sidebar entry (#377). Campaign Detail page gained pause / resume / delete actions (#373). Auto-Promote Phase A shipped its settings UI + tables — cron deferred for Phase B (#403). AI rewrite for the Step-3 headline + body powered by Claude Opus 4.7 (#400). Human-friendly Meta scope labels on the connect card (#398). "Integrations" vocabulary unified across the app, with a Meta tile added to the surface (#394). A small campaign_status enum fix added completed to repair a PR #373 delete bug (#375).

Learning — Tier 3 gamification. Three PRs in a stack. PR1 (#399) added the achievements schema and a Learning section on the user profile. PR2 (#401) layered on activity events plus streak / level / points stats. PR3 (#402) surfaces a UserLearningChip next to user names across the app so a learner's status travels with them.

Knowledge Base — Foundations course pipeline. Phase 2 added kb_course upload metadata columns (#388). Phase 3 added a private kb-upload-staging bucket with RLS (#389). Phase 4 added the kb-upload-course extractor Edge Function (#390). Phase 5 shipped the /admin/knowledge-base upload UI (#391), with the sidebar link surfaced under Super Admin (#392). Course assets now serve via a Vercel proxy instead of a public/ copy (#385). The Foundations course landed as an iframe-embedded lesson (#381), then got spotlighted on /knowledge-base (#395). A kind column on kb_course separates full courses from micro-learning (#397).

AlignHighlight

Stripe billing complete, Meeting Series tabs, Marketing module Phase 1+2, and Photo Timestamp

Three big lifts crossed the finish line in the same week. Stripe billing went from "Phase 4" to "production-grade with reconciliation." The Meetings module gained a full Series workspace. The Marketing module launched in two phases and shipped its first batch of customer-facing pages. And a brand-new Photo Timestamp workflow joined Ops.

Stripe billing — Phases 1-3 complete. Full webhook coverage, signup provisioning, and reconciliation landed together (#322). Nightly reconcile cron with proper snapshot semantics (#324). Email alert when reconcile detects new drift (#341). The provisioning flow now surfaces failures and offers a retry instead of leaving accounts stranded (PR5 #336). RLS gained a can_write_module helper as the foundation for read-only archive mode (PR6 #337). A nightly auth cleanup sweeps abandoned signups (PR3 #333).

Module gating — tenant vs. user. The locked-module page now distinguishes between "your tenant doesn't have this" and "your user role doesn't have this" (PR2 #335) so the message a user sees is actually actionable. Invited-user workflow corrected — the /invited-onboarding detour was dropped (PR4 #334).

Meetings — Series workspace. A new series page shipped with full tab navigation: Overview (composes from the others), Action Items, Decisions, Notes (sharing a hook), Instances (with useSeriesInstances), Ratings (useSeriesRatings), and Stats (useSeriesStats + an AttendanceGrid). Migration retrofitted meeting_rating and canonicalized RLS. joined_at / left_at writes on live-meeting mount/unmount close the attendance loop. A wall-clock + section + total-elapsed top bar uses DB-canonical pause math; a Decision Maker warning fires at 3+ attendees; presenter-as-scribe team ratings at Sacred Close (Round 2 #3); migration consolidating roles, adding pause columns, dropping agenda-presenter, and installing the rating trigger.

Marketing — Phase 1 + 2 launch. Net-new module. Phase 1 shipped the Meta Ads foundation (OAuth + schema + UI #342), enabled for all active tenants (#343), with an admin bootstrap edge function for Stripe Products (#344). Phase 2 backend followed the same day with campaigns, insights sync, ROAS, and KPI plumbing (#347). UI followed immediately: a 3-step campaign creation wizard (Task 2.12 #348), a dashboard + campaigns list (Tasks 2.9, 2.10 #350), and a campaign detail page with revenue Promote cross-link (Tasks 2.11, 2.13 #351). Two days later: an impeccable design pass on all 5 pages (#363), replaced Expedia with Booking.com across listings + wizard (#362), and Step-3 photos pulled from the listing with drag-to-reorder (#365).

Photo Timestamp — new Ops workflow. A new sidebar route lets techs and supervisors generate a documented record for every property visit. Native HEIC decode with EXIF + GPS metadata extraction, lazy HEIC conversion on the canvas overlay, computed overlay positioning, and a stamp pipeline that writes the timestamp + GPS into the downloaded photo. Wired into per-item module gating; database-side module registration grants photo_timestamp to existing customers.

Entitlements — B&B Ventures full access. B&B Ventures granted active access to all add-on modules (#352) and then upgraded to full-tier access on every module (#354) so the team can validate the new entitlement surface end-to-end.

QBO — Phase 2 deployed. Tenant-aware sync pipeline (#380). The QBO P&L now respects client_id end-to-end through the sync layer, not just at read time.

TrustHighlight

Multi-tenancy core complete and the entitlement-driven billing stack lands

The infrastructure week. Multi-tenancy moved from "partial" to "core complete." Module-level entitlements now gate every read and write, and Stripe checkout drives upgrades, downgrades, and cancellations end-to-end.

Multi-tenancy — core complete. client_id columns added across revenue.*, accounting.*, ops.*, and gw_edw.guesty.* schemas. Auto-derive triggers on gw_edw.guesty.* (Phase 4 Batch 2a) so ingested rows tenant themselves. RLS enabled on revenue / accounting / ops tables (Phase 3). Native tenant-filtering pushed into the overview, pacing, channel, and revenue read/write RPCs (Phase 2 Groups 1-8). Phase 0 guard removed — the core is in. Per-tenant locations dropdown on revenue surfaces. End-to-end tenant scoping for the Guesty ETL.

Security — emergency block + nightly audit. A circuit-breaker emergency tenant block on revenue/finance RPCs lets us isolate a tenant in seconds. Nightly cross-tenant isolation audit (Phase 6) runs from cron and flags any leak across the new RLS surface.

Billing — entitlement-driven, Phase 1 through 4. Module entitlement schema + catalog seed (Phase 1). Entitlement wired into hasModuleAccess (Phase 2). RLS now enforces module entitlement at the database layer (Phase 3). Stripe Products + Prices provisioned for every entitlement (Phase 4a). Per-module Stripe checkout + entitlement grid (Phase 4b/c). Bridge for the remaining Stripe gaps + an updated provisioning plan. Real upgrade / downgrade / cancel workflows replaced the simulated paths. Warehouse-side sync gating shipped in two halves (in-repo + out-of-repo) for Phase 5.

Module gates. A dedicated module-locked page replaces silent redirects when a user hits something their tenant hasn't purchased. Sidebar surfaces Billing & Modules under Admin.

QBO — per-tenant P&L. Multi-tenancy end-to-end on the QBO P&L: every tile, every drill-through respects client_id. HK-recon Phase B added bill_to, the Breezeway description, and line items as read-only from Breezeway for the QBO Journal export.

Integrations — surfaced and self-serve. Multiple Guesty accounts now visible in the frontend. Breezeway card on the admin integrations tab. Breezeway tenant onboarding wizard + admin API. Breezeway page shows live Guesty connection status. Admin-level integration access plus a daily token-refresh cron.

Uptime — multi-tenant + Listing Rankings. Uptime moved to multi-tenancy (client_id columns + RLS + cron writes). Listing Rankings tab on /uptime for single-listing checks and history, backed by new listing_rank_targets + listing_ranks tables.

RevenueHighlight

Live Coach goes live, Revenue ships Projections + Channels v2, and Listing Visibility v1 lands

The biggest single product week of the month. Three flagships shipped in parallel: Live Coach moved out of spike into production, Revenue gained projections plus a deeper Channels view, and a brand-new Listing Visibility module went live behind a Firecrawl-backed rank crawler.

Live Coach — production-grade transcription. Browser-direct-to-Deepgram via a temp token replaced the proxied path. An AudioWorklet buffer plus Deepgram keyterms tightened the small-transcript wins. A Web Speech instant-ghost overlay (Chrome / Edge) shows the rep what they just said before the model returns. Per-type suppression and rep-tunable thresholds eliminate noisy nudges, a pagehide teardown prevents zombie sessions, an hourly janitor closes anything stuck with ended_at=NULL, and the coach UI now hides itself to keep focus on the transcript surface. A silent-or-unavailable-mic warning surfaces fast when the rep's audio path breaks, and comm_log is unified via Twilio CallSid linkage.

Comms — every call captured, transcribed, and playable. Inbound Twilio webhook plus a shared comm-log upsert helper. Every Twilio call records by default, with verify_jwt pinned. Recordings mirror into a durable Supabase Storage bucket, async transcription runs against plain Twilio calls (transcribe-recording), and reps can play recordings inline from the lead Communications tab.

Revenue PR 11 — Projections. A new Projections tab with three sub-tabs (Form, History, CSV Upload). Annual + monthly projection tables, both lifecycle-aware. Drawer-edit pencil and a ProjectionEditPanel wired into the NewUnitDrawer. Bulk-upsert RPC with an EXISTS guard, an upsert RPC for individual rows, and a revenue.projection_import audit table. CSV parser with TDD test suite, drag/paste/file CSV import via ProjectionsCsvUpload (mirroring GoalsCsvUpload), and a downloadable CSV template.

Revenue PR 11 — New Unit Performance. A complete new-unit tab with portfolio KPI strip (5 cards with skeleton loading), filter toolbar (multi-select chips for territory, bedrooms, phase + a guardrail toggle), sortable table with phase chips and guardrail badges, drawer with header + 4 KPIs + actions + projection breakdown + notes, and a Carson-tone recommended-actions list. Two RPCs (get_new_unit_kpis, get_new_unit_listings) move phase + band + pace% to the database.

Revenue PR 8 — Channels v2. Channel Mix chart got a 3-stack treatment with LY Final. Booking Window column on ChannelSummaryTable. BedroomRevenueShareTab gained a ?months= URL filter and a Booking Fee Share tooltip. ChannelsTab gained a ?br= URL bedroom filter. PinnedKPIRow shows a Commission % badge with a bookingFeeMargin refactor. ChannelDrawer reorder plus a delete affordance on BookingCurveByChannel. PR 8 RPC migration added taxonomy + bedroom filter + booking-window mean/median.

Revenue — Calendar Occupancy. A new tab in Revenue Reports renders 12 mini-calendars (responsive 1/2/3/4-col), each showing 365-day occupancy with STLY pace + LY-Final. Year stepper, bedroom chips, and a Tailwind-only modal (Esc + backdrop close) for the expanded month view. New get_calendar_occupancy RPC. Color-mode toggle (absolute heatmap vs smart-anchor delta) plus a hover tooltip.

Listing Visibility v1 — rank crawler. Net-new module. A Firecrawl REST client with stealth + retry, listing-id extraction, listing metadata parser, URL builders, block detection, rank math, multi-adults search per market, and an orchestrator (live-fire passing). Card-based index + detail page with grade / visibility / history, bulk import from Guesty inventory, auto-sync Guesty inventory into Optimized Listings, aggregated weekly portfolio scan via pg_cron, and a weekly digest delivered as email + in-app inbox. Three iterative polish passes: v1.1 (search context + filters), v1.2 (tiles, trends, quick wins), v1.3 (admin polish).

CRM lifecycle — Phase 1 + 2. Phase 1 removed Pricing/Live and added sub-statuses, checklists, and tags. Phase 2 made the lifecycle interactive: sub-statuses, tags, delays, and a property section on the lead drawer.

Guesty self-serve. A self-serve Guesty connect wizard with two-path entry, plus a live read-through proxy + listings preview to validate the connection before write-back.

OwnersHighlight

CRM deepens: 11-stage funnel, HubSpot import, communications, and HK Recon Phase 2

CRM moved from foundation to flywheel. Underperforming listings got a richer drawer in Revenue. Housekeeping reconciliation completed its first dashboard-grade phase.

CRM — the 11-stage deal funnel. The Properties page now exposes a single 11-stage deal funnel with sub-status pill tiles, a stage filter dropdown with Apple-tone colors, a funnel strip, and a board view that uses the 11 stages as columns. Sub-statuses renamed to pitch_completed and contract_signed; the funnel moved from Properties to the CRM dashboard so reps see pipeline first. Stale indicators and revenue metrics now decorate the property board, table, dashboard, and leads list.

CRM — Phases 4-9. A cascade of phases landed: Phase 4 (add-contact + contract mutations), Phase 5 (lifecycle workspace on property Overview), Phase 6 (activity-tab log-note mutation), Phase 7 (lead inbox MVP), and Phase 9 (CRM dashboard landing at /crm). Property Documents section accepts PDF and CSV uploads to a private bucket with signed-URL access. Inline sub-status dropdown on the Overview pill, edit-lifecycle from Overview, and a lifecycle detail drawer on board card click.

CRM — lead intake and qualification. Manual + Add-lead form with editable contact preview, a confirm dialog, and a qualify_lead_with_contact RPC. Status tabs as primary nav with a filters drawer. Per-lead Communications tab filtered to sales lines, an Activity tab, an Overview tab with inline-editable contact details, a stats strip on the leads page, and a lead_inbox_stats RPC. The inbound-zoom edge function accepts the new event format with did_phone_number routing.

CRM — HubSpot import. Migrate driver pulled contacts, deals, emails, notes, meetings, and file attachments from HubSpot into property_activity_event, communication_log, and the property-documents bucket. External-id columns added so future syncs can dedupe cleanly.

CRM — Communications Integration (#184). Zoom Phone + WhatConverts unified into the lead Communications tab. Backfill participant→contact matches, retro-match trigger, and a webhook-server change to extract the DID and create the activity record.

HK Recon Phase 2 — four PRs in a stack. PR-1 shipped backend RPCs and drift detection. PR-2 added the period dashboard with Requires Review + Auto-Validated tabs. PR-3 added the Finance Payout Register tab. PR-4 added an Audit tab as a period-transitions timeline. Owner/owner-guest reservation review with a quick stayed/no-stay toggle, period driven from a week dropdown, a public-summary Edge Function for the daily babysitter agent, and a QBO Journal CSV download from the Finance Payout Register.

Revenue PR 7 — Underperforming drawer. Drawer KPIs + peer-group context, a DrawerBlockedNightsBreakdown sub-section, and the first UI consumer of the Notes RPCs (DrawerNotesPanel). PR 7 RPC migration canonicalized adj_revpar, added net_rent, and split blocked-nights into named buckets. Δ headers now read "vs STLY" or "vs Goal" instead of a bare delta.

Contracts and dialer. Contracts pipeline kanban with auto-flip and activate/terminate (#189). Property record page redesigned in an Attio-style scrollable layout (#188). Twilio softphone spike landed (no screenshare path); Live Coach learned to use softphone streams instead.

OwnersHighlight

CRM foundations, Channel Revenue analytics, and Accounting Phase 1

A foundation week. The CRM module landed end-to-end, Revenue gained a Channels dimension, and Accounting closed Phase 1 of the reconciliation rewrite.

CRM module — first complete pass. A full property-and-lead workspace shipped behind /crm: a CRM dashboard landing page, Properties list with state-chip filters and territory search, a board view with drag-and-drop and a transition drawer, a 6-tab property detail page, lifecycle workspace on property Overview, lead inbox MVP, and a 2-step Add-Property modal with live RentCast enrichment. Hooks layer (property, contact, contract, lead, activity, issue, delay), the foundation migration applied to production, and an enrich-property edge function backing it all.

Revenue PR 5 — Channels & Bedrooms. A new Channels tab on /revenue with a 4-card KPI strip, channel mix chart (grouped LY/TY stacked bars), per-channel YoY tooltip, channel × market heatmap with click-to-drill, and a 6-panel ChannelDrawer triggered from TY-table row clicks. Bedroom Revenue Share tab joined the lineup with destination stacked bars, an economics table with portfolio total row, and STLY-aware deltas. Layer 5 channel-drawer RPCs and a channel × market heatmap RPC backed the new surface.

Accounting Phase 1 — clean ledger plumbing. Removed the Airbnb ghost, made listings.cleaning_fee flow through a clean waterfall, un-netted taxes, attributed Airbnb markup per-fee at the config base, and pulled the BOOKING_FEE invoice line into reservation_fees. New CFF ↔ QBO reconciliation tab gives finance a side-by-side view of cash flow forecast vs. the books.

Quality-of-life. Tooltips on every Overview KPI card, sized chart and KPI skeletons that match final card dimensions, and STLY legend labels with faded color swatches across the Revenue dashboard.

OpsHighlight

AI inspection assistance: real-time photo validation + async quality review

Inspections used to be the step where documentation quality and field speed fought each other. We split the fight.

Tier 1 — real-time, in the field. Every photo a tech takes runs through a fast vision model the moment it's captured. If the photo is of the wrong area — "this is supposed to be the refrigerator, that's a living room chair" — the field app blocks the submission and asks for a retake before the tech moves on. Latency is low enough the tech doesn't notice.

Tier 2 — async, for supervisors. After the inspection submits, a more thorough vision model reviews the whole packet and flags anything that warrants a supervisor eyeball — missed requirements, condition mismatches, unclear photos. Flagged inspections land in a review queue at /ops/review. Supervisors review exceptions, not every submission.

Net effect. Techs don't get pulled back to a property to re-shoot the dishwasher. Supervisors don't scroll through 200 photos to find the one questionable item. Documentation quality goes up, rework goes to near-zero, owner statements never include "we need to reschedule that inspection."

Model choices and strictness are configurable per account. If your ops team wants Tier 1 off and only async review, that works. If you want stricter field-time blocking, dial up the Tier 1 threshold.

This is the first of several vision-AI workflows on the roadmap. Next up: condition drift detection across consecutive inspections (is the carpet actually aging faster than you'd expect?) and owner-reserve triggers from documented wear.

OpsHighlight

Operations dashboard: task-management parity in one view

Ops teams asked for a single pane of glass. Here it is.

The new Operations Dashboard is the landing page for anyone running turns, inspections, or maintenance across the portfolio:

  • Four donut charts at the top — Total / Clean / Inspect / Maintenance — showing task counts by status at a glance.
  • Nine-column property table with sticky headers: listing, current reservation, turn status, task progress, open issues, latest comment, gap-night snapshot. Sorts, filters, virtualized for 500+ units (Mammoth market, we're looking at you).
  • Task-management color parity — if your team is already color-coded to ready, in-progress, blocked, the same palette carries over. No retraining.

Built to handle Bear Moon Ranch, Highland Lakes, and the Mammoth fleet simultaneously without a single virtualization hiccup.

This is the surface the Ops agent now writes to and reads from. When Turn.autocreator spawns a task from a reservation webhook, it shows up here first. When Schedule.guard flags a late clean, the property row glows.

More ops polish already in flight: inspection template builder (7 typed requirement kinds — Checklist, Photo, Condition, Count, Text, Yes/No, Rating — plus a ~50-row element catalog so you don't build from scratch) and task auto-generation (reservations spawn cleaning + inspection tasks on a 30-day rolling window via webhook + nightly sweep, with per-listing modifiers for time, piece rate, and total cost).

TrustHighlight

Cash flow forecast: 12 months of actuals + budget in one view

Finance teams finally get a forward-looking cash view inside VR Goals — not a separate spreadsheet, not a QBO tab.

The new Cash Flow Forecast tab renders a 12-month P&L matrix: rows are line items, columns are months. Past months fill in with actuals from your PMS reservation data. Future months fill in with your FY26 QBO budget. A running cash balance computes live underneath the P&L so you can eyeball the runway.

  • One pane, past and future. No more switching between "historical P&L" in one tool and "budget" in another.
  • Market filter. Slice to Nashville, Austin, Smokies, Hilton Head, Breckenridge, Mammoth, or Sea Ranch — or view the portfolio roll-up.
  • FY26 budget selector. Load scenario versions if your finance team runs more than one.
  • Net Revenue, Total Expenses, Running Balance computed on the client, so changes to the budget propagate instantly.

Backing this: 10 new QBO data views (qbo_accounts, qbo_deposits, qbo_bills, qbo_transfers, qbo_budgets, cash_position, budget_vs_actual, and more) synced from QuickBooks Online into Supabase through our existing pipeline. No frontend API calls, no per-render QBO auth cost, clean typed hooks the whole way down.

One small admin perk shipped alongside: P&L account mapping is now a self-service popover inside the same tab. When a new QBO account shows up unmapped, any admin can classify it into the right P&L section (Revenue, OPEX, Owner Payouts, etc.) without engineering. Specificity resolver handles overlapping rules — exact match beats prefix beats longest prefix.

Align

Team chat with AI agent as co-pilot

Chat inside VR Goals used to be you and the agent. Now it's your team plus the agent, when you want it.

  • Group threads — invite teammates into a chat the same way you'd invite them to a shared doc. Sender avatar and name on every message. Realtime delivery via Supabase subscriptions — no refresh.
  • Owner + member roles — group creator can add and remove members; members can post and @mention.
  • AI agent, optional — toggle the agent into a group thread, or summon it mid-conversation with @agent. It has read access to the goals, KRs, and ledger context attached to the group.
  • Mention notifications — every @yourname lands in your inbox as a mention, so you don't have to watch twelve threads.

Why this matters: most ops conversations used to live in Slack, losing their link to the goal or KR they're actually about. Now the thread sits next to the goal, the agent sees it, and the context survives the week.

Align

Inbox activation: persistent notifications + real-time goal alerts

The bell icon used to show an ephemeral alert and lose it on refresh. Not anymore.

Inbox is now a server-backed, cross-session, realtime notification stream that wakes up when it matters:

  • Goal drift alerts — any goal that slips behind pace lands in your inbox automatically, not when someone remembers to check the dashboard.
  • KR milestone crossings — 25%, 50%, 75%, and 100% each fire their own notification. Celebrations at 100%.
  • Cycle deadline warnings — windows close loudly, not quietly.
  • Check-in reminders — daily 7am UTC nudge for pending check-ins, deduped so you don't get four for the same goal.
  • AI agent insights — when the agent spots a pattern (underperforming market, pricing drift, unresolved owner ticket), you hear about it here.

Under the hood: two daily cron jobs (agent-inbox-nudges at 7am UTC, agent-daily-learning at 2am UTC), realtime triggers on goal status changes, dedup via unique indexes on unread reminders, and seven distinct notification categories wired end-to-end.

Old bell icon is retired. The inbox is the primary notification surface now.