Skip to content

Fix revenue dashboard: tenant data leak, rounding, timezones, DB pool - #222

Open
vidz231 wants to merge 1 commit into
Base360-AI:mainfrom
vidz231:fix/revenue-dashboard-bugs
Open

vidz231 wants to merge 1 commit into
Base360-AI:mainfrom
vidz231:fix/revenue-dashboard-bugs

Conversation

@vidz231

@vidz231 vidz231 commented Oct 12, 2026

Copy link
Copy Markdown
  • Cache: scope Redis key by tenant (revenue:{tenant}:{property}); prop ids are only unique per tenant, so one client was served the other's data.
  • Precision: sum as Decimal and round to cents once; stop per-item rounding and float math.
  • Timezones: compute month boundaries in each property's local timezone (calculate_monthly_revenue, previously a stub returning 0).
  • DB pool: build URL from DATABASE_URL (supabase_db_* settings don't exist), drop QueuePool (invalid for async engines), make get_session sync, add greenlet. The pool never initialised, so the API silently served hardcoded mock revenue.
  • Remove mock-data fallback; DB failures now return a logged 503.
  • Reject requests with no tenant (403) instead of "default_tenant".
  • Return 404 for unknown/foreign properties instead of 0.00 (not cached).

- Cache: scope Redis key by tenant (revenue:{tenant}:{property}); prop ids
  are only unique per tenant, so one client was served the other's data.
- Precision: sum as Decimal and round to cents once; stop per-item rounding
  and float math.
- Timezones: compute month boundaries in each property's local timezone
  (calculate_monthly_revenue, previously a stub returning 0).
- DB pool: build URL from DATABASE_URL (supabase_db_* settings don't exist),
  drop QueuePool (invalid for async engines), make get_session sync, add
  greenlet. The pool never initialised, so the API silently served
  hardcoded mock revenue.
- Remove mock-data fallback; DB failures now return a logged 503.
- Reject requests with no tenant (403) instead of "default_tenant".
- Return 404 for unknown/foreign properties instead of 0.00 (not cached).
- Dashboard: add GET /dashboard/properties and load the property dropdown
  from it, so each client only sees its own properties (the hardcoded list
  offered every tenant's properties and mislabeled Ocean's prop-001).
{!loadingProperties && !propertiesError && properties.length === 0 && (
<div className="text-sm text-gray-500">No properties found for your account.</div>
)}
{selectedProperty && <RevenueSummary propertyId={selectedProperty} />}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: RevenueSummary retains a stale error state across propertyId changes because the error state is not reset and the component remains mounted.
Severity: MEDIUM

Suggested Fix

Reset error to null before re-fetching data when propertyId changes inside the effect in RevenueSummary, or pass key={propertyId} to RevenueSummary in Dashboard.tsx to force remounting.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: frontend/src/components/Dashboard.tsx#L82

Potential issue: In `RevenueSummary`, the `error` state is set when data fetching fails
but is never reset when `propertyId` changes. Because `Dashboard` renders
`RevenueSummary` without a `key` prop tied to `propertyId`, the component remains
mounted across dropdown property changes. Consequently, once an error occurs, switching
to another property continues displaying the stale error message instead of loading the
newly selected property's data.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant