Releases: deepan-mehta-analytics/stayops
Release list
v4.0.0 — Portfolio Polish: Auth, Theme Overhaul & Screenshots
🏠 StayOps — v4.0.0
Phase 4 portfolio polish — multi-user authentication, warm alabaster ops console theme, and full-page screenshot suite captured from the live Vercel deployment.
What's included
Authentication & Security
| Feature | Detail |
|---|---|
| Supabase Auth (email/password) | Login page with full-width AI property banner, inline forgot-password toggle |
| PKCE reset-password flow | Secure token exchange via /reset-password route |
| Route guard middleware | proxy.ts protects all /dashboard, /bookings, /reconciliation, /reports routes |
| Row-Level Security | RLS enabled on all 7 Postgres tables — anon blocked from PostgREST direct access |
| Sign-out button | Mint default matching nav; bright red on hover |
Ops Console Theme Overhaul (Theme F — Warm Alabaster)
| Token | Value | Purpose |
|---|---|---|
| Page background | #F4F3EF |
Warm alabaster — reduces eye strain vs cool blues |
| Table container | #FFFFFF |
Clear card separation from page |
| Table header | #E9ECEF |
Distinct but not harsh |
| Row divider | 1px solid #E2E8F0 |
Replaces alternating row bands |
| Drop shadow | 0 4px 6px -1px rgb(0 0 0 / 0.05) |
Subtle card lift via .table-card CSS class |
| Text | #212529 |
Deep charcoal (oklch) |
Applied consistently across /dashboard, /bookings, /reconciliation, /reports.
Portfolio Screenshots (1280×800, live Vercel)
| File | Used in |
|---|---|
public/screenshots/landing-hero.png |
README ## 📊 Results + hero section |
public/screenshots/dashboard.png |
README ## 📊 Results |
public/screenshots/reconciliation.png |
README ## 📊 Results + hero card (replaces placeholder) |
public/screenshots/bookings.png |
public/screenshots/ only |
public/screenshots/reports.png |
public/screenshots/ only |
Captured via Playwright MCP at 1280×800 from stayops-five.vercel.app. Hero card [ reconciliation dashboard screenshot ] placeholder replaced with real <img> tag.
Unit Tests
| Suite | Tests | Status |
|---|---|---|
classifyBookings() — Phase 1 |
8 | ✅ |
| AI agent tools — Phase 2 | 8 | ✅ |
| Weekly report format — Phase 2 | 7 | ✅ |
| POST /api/leads — Phase 3 | 4 | ✅ |
| Total | 27 | CI green |
Roadmap
v4.1.0— Playwright E2E test suite against live Vercel deployment (6-step flow: landing → lead form → dashboard → reconciliation → AI resolve → bookings/reports)v5.0.0— Multi-tenant operator accounts with per-user RLS data isolation
v3.0.0 — Growth Surface: Landing Page + PostHog Funnel
🏠 StayOps — v3.0.0
Phase 3 complete. The public-facing growth surface is live at the root URL — a premium marketing landing page with PostHog funnel tracking, UTM attribution, and lead capture into Supabase.
What's included
Route group architecture
app/(marketing)/— public landing page at/, light-only, Poppins font, OG metaapp/(app)/— ops console at/dashboard,/bookings,/reconciliation,/reports(URLs unchanged)- Root
app/layout.tsxslimmed to bare font shell; each group has its own layout
Landing page sections
| Section | Component | Notes |
|---|---|---|
| Sticky nav | MarketingNav |
Scroll-to-anchor links, transparent overlay on dark hero |
| Hero | Hero |
Dark slate/blue-950 gradient mesh, floating glassmorphic card, animated pulse dot |
| Metrics strip | MetricsStrip |
IntersectionObserver count-up animation (86+ bookings, 5 conflict types, 3 channels) |
| Features grid | FeaturesGrid |
6 cards with Lucide icons, stagger entrance animation |
| How it works | HowItWorks |
3-step numbered flow with dashed connector |
| Social proof | SocialProof |
Testimonial card with 5-star rating |
| Lead form | LeadForm |
PostHog funnel events, honeypot spam guard, optional fields |
PostHog funnel events
| Event | When |
|---|---|
landing_page_viewed |
Auto-captured on init |
form_start |
First focus on email field |
form_submit_attempt |
Submit clicked |
lead_created |
201 response — conversion |
form_error |
API error |
Leads API
POST /api/leads— Zod validation, honeypot guard (silent 200), Drizzle insert- 4 TDD tests: valid email, honeypot, invalid email, optional field passthrough
- Schema:
property_count+channels_usedadded toleadstable (Migration 0003)
Test suite
| File | Tests |
|---|---|
lib/reconciliation.test.ts |
8 |
lib/ai-agent.test.ts |
8 |
lib/weekly-report.test.ts |
7 |
lib/leads-api.test.ts |
4 (new) |
| Total | 27 |
CI: run 26707895559 — both jobs green.
Roadmap
v4.0.0— Phase 4 portfolio polish: integration tests, Playwright E2E, README screenshots
v2.0.0 — Phase 2: Claude AI Agent + Weekly Reports + Cron Automation
🏠 StayOps — v2.0.0
Phase 2 ships the AI agent layer: Claude tool-calling reconciliation analysis, weekly Slack reports, turnover auto-generation, and the full server-to-client UI wiring.
What's included
Schema (Task 1)
| Column | Type | Purpose |
|---|---|---|
accepted_by |
text | Operator who clicked Accept — audit trail |
accepted_at |
timestamp | When Accept was clicked |
ai_confidence |
integer 0–100 | Claude's probability score stored at resolve time |
user_feedback |
varchar(20) | "correct" / "wrong" / null — Phase 3 ML training label |
AI Agent (lib/ai-agent.ts) (Task 2)
RECONCILIATION_TOOLS— 3 tools:get_booking_details,get_property_info,propose_resolution(required: action, confidence, reasoning_summary)CHANNEL_PRIORITY—["airbnb", "direct", "booking_com", "vrbo"]- Full multi-turn agentic loop via
streamAnalysis()— emits NDJSON events: text, tool_call_start, proposal, done resolveFlag()— writes status, resolution, resolvedAt, acceptedBy, acceptedAt
Weekly Report (lib/weekly-report.ts) (Task 3)
getCurrentIsoWeek()— ISO 8601 Thursday-anchoring, returnsYYYY-WwwformatWeeklyReport()— pure Markdown formatterbuildWeeklyReport()— assembles live DB stats + formats report
API Routes (Task 4)
| Route | Method | Purpose |
|---|---|---|
/api/ai/analyze |
POST | Stream analysis from Claude agent |
/api/ai/resolve |
POST | Accept a proposed resolution |
/api/ai/feedback |
POST | Record 👍/👎 feedback without resolving |
/api/cron/weekly-report |
POST | Generate + deliver weekly Markdown report |
/api/cron/generate-turnovers |
POST | Idempotent nightly turnover task creation |
ConflictSlideOver component (Task 5)
- 3 states: idle (conflict detail), analysing (streaming tokens), resolved (confirmation)
- Glassmorphism panel:
rgba(255,255,255,0.92)+backdrop-filter: blur(16px) - Feature-flagged:
NEXT_PUBLIC_ENABLE_AI_AGENT=truegates the Analyze button - Confidence badge colours: ≥90 violet · ≥70 amber · <70 red
ReconciliationClient + page refactor (Task 6)
"use client"boundary withselectedFlagstate and violet row highlightkey={selectedFlag.id}forces slide-over remount on row switch- Server component serialises
Date → ISO stringbefore passing to client
Vercel Cron (Task 7)
| Cron | Schedule |
|---|---|
/api/cron/weekly-report |
Mondays 08:00 UTC |
/api/cron/generate-turnovers |
Daily midnight UTC |
Tests (Task 8)
| Suite | Tests |
|---|---|
lib/reconciliation.test.ts |
8 |
lib/ai-agent.test.ts |
8 |
lib/weekly-report.test.ts |
7 |
| Total | 23 |
Roadmap
v3.0.0— Phase 3 growth surface (direct-booking landing page + PostHog funnel + lead capture + AI listing copy)
v1.2.0 — Conflicts/Opportunities Split + First Unit-Test Suite
🏠 StayOps — v1.2.0
Reclassifies reconciliation flags by business meaning — urgent conflicts isolated from revenue opportunities — and ships the project's first unit-test suite.
What's included
Reconciliation engine reclassification
| Category | Flag types | UI treatment |
|---|---|---|
| Conflicts | duplicate, double_book, price_mismatch |
Top section, severity-ordered (double-book first) |
| Opportunities | gap (2–3 nights) |
Second section, per-row ~$ estimate |
| Orphan nights | orphan_night (1 night, unsellable) |
Transparency footnote count only |
| Intentional vacancy | 4+ night gap | Not flagged |
Dollar-value opportunity estimates
estimated_valuecolumn added toreconciliation_flags(Drizzle migration applied)- Engine computes
gap × base_ratefor each opportunity; page header sums to "~$X recoverable" - Drizzle numeric-string footgun guarded:
Number(estimatedValue)before summing
Dashboard fix
- "Open Flags" card → "Conflicts" card using new
getOpenConflictCountquery - Card is green when zero real conflicts exist (gaps/orphan nights never redden the dashboard)
First unit-test suite
| Fixture | Tests |
|---|---|
double_book overlap |
1 |
duplicate from two channels |
1 |
1-night orphan (no estimatedValue) |
1 |
2-night gap with correct estimatedValue |
1 |
| 4-night gap → no flag (boundary pin) | 1 |
| Multi-property opportunity sum (numeric-string guard) | 1 |
price_mismatch >25% deviation |
1 |
| Back-to-back clean bookings → no flags | 1 |
CI
- New parallel
Unit Testsjob in.github/workflows/ci.yml - Both
Lint & TypecheckandUnit Testsrequired green on every push
Pure classifyBookings refactor
- Detection logic extracted from
runReconciliationinto a pure function (bookings in → flags out, no I/O) runReconciliationis now a thin orchestrator: fetch → classify → filter (idempotency) → insert
Roadmap
v2.0.0— AI agent layer: Claude tool-calling reconciliation agent, weekly ops summary → Slack, turnover auto-generation via Cronv3.0.0— Growth surface: direct-booking landing page, PostHog funnel analytics, lead capture
v1.1.0 — Vega Theme, Dark Mode & Repo Topics
🏠 StayOps — v1.1.0
Polish release applying the Vega/Green/Blue shadcn preset, adding a system-aware light/dark toggle to the nav, and wiring 14 GitHub repo topics for discoverability.
What's included
Theme — shadcn Vega/Green/Blue preset (b3ZMmbVHcm)
globals.css: replaced default neutral palette with green primary (oklch(0.527 0.154 150.069)) and blue chart spectrum (--chart-1→--chart-5)components.json: style updated frombase-nova→vega
Light / Dark Mode
- Installed
next-themes;components/theme-provider.tsxwraps the layout app/layout.tsx:ThemeProviderwithdefaultTheme="system"— OS preference respected on first loadcomponents/nav.tsx: Sun/Moon toggle button (top-right); nav colours migrated to CSS variables
Repository & docs
- 14 GitHub repo topics added:
nextjstypescripttailwindcssshadcn-uidrizzle-ormsupabasepostgresqlproperty-managementvacation-rentalhospitalityoperations-dashboardbooking-managementdata-engineeringnext-themes - README: Quick Summary rewritten as bullet lists + roadmap table; all staleness swept (Phase 1 metrics, component statuses, Known Limitations, version checklist)
| Check | Result |
|---|---|
| Build | ✅ Clean (next build Turbopack, 9s) |
| CI | ✅ Green (lint + typecheck, Node 24) |
| Theme toggle | ✅ Persists across page navigation (localStorage) |
| Dark mode | ✅ Verified live on Vercel across all 4 routes |
Roadmap
v2.0.0— Claude tool-calling reconciliation agent · weekly AI ops report → Slack · turnover auto-generation via Vercel Cronv3.0.0— Direct-booking landing page · PostHog funnel · lead capture with UTM attribution
v1.0.0 — MVP: Reconciliation Engine + KPI Dashboard
🏠 StayOps — v1.0.0
Full MVP — property operations dashboard with automated booking reconciliation, CSV/Sheets import, and a live KPI dashboard backed by Supabase Postgres.
What's included
Reconciliation Engine
- Rule-based engine (
lib/reconciliation.ts) detects 4 conflict types: duplicate, double_book, gap, price_mismatch - Idempotent flag creation — SHA-256
flagKey(type, sortedIds)prevents duplicate flags on re-run - Auto-triggers on first visit to
/reconciliationif table is empty
KPI Dashboard (/)
- Occupancy %, Average Daily Rate, Gross Revenue (rolling 30-day window)
- Revenue by property table with nights + ADR breakdown
- Upcoming turnovers (next 7 days) for cleaning schedule
- Open flags card — red/green link to reconciliation page
Booking Import
| Source | Endpoint | Method |
|---|---|---|
| CSV upload | /api/import/csv |
multipart/form-data via papaparse |
| Google Sheets | /api/import/sheets |
service account JSON, A1:Z1000 range |
- Dedup via
source_row_hash(SHA-256 of guest|property|dates|channel) - Reconciliation auto-runs after every import batch
Reports Page (/reports)
- All-time revenue by channel and by property
- ADR per night and revenue share % per segment
Infrastructure
| Item | Detail |
|---|---|
| Database | Supabase Postgres, 7-table Drizzle schema |
| Deploy | Vercel (auto-deploy on push) |
| CI | GitHub Actions — ESLint + TypeScript typecheck (Node 24) |
| Rendering | All data pages force-dynamic — no stale static pre-renders |
Roadmap
v2.0.0— AI agent layer: Claude tool-calling reconciliation, weekly ops report → Slack, turnover auto-generationv3.0.0— Growth surface: direct-booking landing page, PostHog funnel analytics, lead capture
v0.1.0 — Phase 0 Scaffold Deployed
🏠 StayOps — v0.1.0
Phase 0 complete: full Next.js scaffold live on Vercel with GitHub CI wired up.
What's included
App scaffold
| Item | Detail |
|---|---|
| Framework | Next.js 16 (App Router, TypeScript, Tailwind) |
| UI | shadcn/ui — base layout + persistent top nav |
| Live URL | https://stayops-five.vercel.app |
| GitHub | https://github.com/deepan-mehta-analytics/stayops |
Data layer
| Item | Detail |
|---|---|
| ORM | Drizzle ORM + drizzle-kit |
| Schema | 7 tables: properties, channels, bookings, reconciliation_flags, turnover_tasks, leads, reports |
| DB | Supabase (Postgres) — connection pending next session |
Seed script (npm run seed)
| Conflict type | Instances | Properties |
|---|---|---|
| duplicate | 2 | Lakeview Cottage, Downtown Studio |
| double_book | 2 | Beach House, Mountain Cabin |
| gap | 2 | Downtown Studio (1-night), Lakeview Cottage (2-night) |
| price_mismatch | 2 | Lakeview Cottage (+50%), Beach House (-45%) |
CI
- GitHub Actions: lint + typecheck on every push to main
- Node 24, 4/4 runs green
Roadmap
v0.2.0— Phase 0 complete (Supabase connected + seed running against live DB)v1.0.0— MVP: Phase 1 reconciliation engine + KPI dashboardv2.0.0— Phase 2 AI agent layer (Claude tool-calling reconciliation)v3.0.0— Phase 3 growth surface (landing page + PostHog)