fix: stabilize auth context effect deps and batch uptime cleanup

Extract stable primitives (isAuthenticated, userOrgId) from user object
for the checkOrg effect dependency array to prevent unnecessary re-runs
on every render. Batch uptime cleanup deletion (1000 rows/batch) to
avoid lock contention and WAL bloat.
This commit is contained in:
Usman Baig
2026-03-01 19:56:14 +01:00
parent 4de4e05ccb
commit dfa887147a
2 changed files with 15 additions and 3 deletions

View File

@@ -8,6 +8,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
### Improved ### Improved
- **Smoother navigation across the app.** Switching pages, changing organizations, or signing in no longer triggers unnecessary background checks. Previously, an internal effect re-ran on every navigation because it watched the entire user object for changes — now it only reacts when your authentication state or organization actually changes. This makes page transitions faster and reduces redundant network requests.
- **Faster uptime data cleanup under heavy usage.** Old uptime check records are now removed in small batches instead of all at once. Previously, a single large deletion could briefly slow down database performance when months of monitoring data had accumulated. Cleanup now runs incrementally so your dashboard stays responsive throughout.
- **More reliable automated testing.** Backend tests that verify authentication and billing no longer rely on a fragile internal shortcut that could mask real bugs. If a code change accidentally reaches the database during a test, it now fails gracefully with a clear error instead of crashing silently.
- **Database queries are now verified automatically before every release.** A new step in our release process runs all database operations against a real PostgreSQL database — including applying all schema migrations — so we catch query errors, missing columns, and data-access bugs before they reach production.
- **Safer database schema changes.** The large migration that restructured how your analytics data is stored now has a documented rollback procedure. If anything goes wrong during a database upgrade, we can revert cleanly instead of requiring manual intervention.
- **Easier setup for new developers.** Building and testing Pulse no longer requires a specific directory layout on your machine. All builds use a pre-packaged snapshot of dependencies, so you can clone the project and start working immediately without extra setup steps.
- **Faster, smarter dashboard data loading.** Your dashboard now loads each section independently using an intelligent caching strategy. Data refreshes happen automatically in the background, and when you switch tabs the app pauses updates to save resources — resuming instantly when you return. This replaces the previous approach where everything loaded in one large batch, meaning your charts, visitor maps, and stats now appear faster and update more reliably. - **Faster, smarter dashboard data loading.** Your dashboard now loads each section independently using an intelligent caching strategy. Data refreshes happen automatically in the background, and when you switch tabs the app pauses updates to save resources — resuming instantly when you return. This replaces the previous approach where everything loaded in one large batch, meaning your charts, visitor maps, and stats now appear faster and update more reliably.
- **Better data accuracy across the dashboard.** All data displayed on the dashboard — pages, locations, devices, referrers, performance metrics, and goals — is now fully typed end-to-end. This eliminates an entire class of potential display bugs where data could be misinterpreted between the server and your screen. - **Better data accuracy across the dashboard.** All data displayed on the dashboard — pages, locations, devices, referrers, performance metrics, and goals — is now fully typed end-to-end. This eliminates an entire class of potential display bugs where data could be misinterpreted between the server and your screen.
- **Dashboard stays fast under heavy traffic.** When many users view their dashboards at the same time, the backend now limits how many data queries run in parallel so it doesn't overwhelm the database. If you navigate away while the dashboard is loading, queries are cancelled immediately instead of continuing to run in the background. - **Dashboard stays fast under heavy traffic.** When many users view their dashboards at the same time, the backend now limits how many data queries run in parallel so it doesn't overwhelm the database. If you navigate away while the dashboard is loading, queries are cancelled immediately instead of continuing to run in the background.

View File

@@ -187,10 +187,15 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}, },
}) })
// * Stable primitives for the effect dependency array — avoids re-running
// * on every render when the `user` object reference changes.
const isAuthenticated = !!user
const userOrgId = user?.org_id
// * Organization Wall & Auto-Switch // * Organization Wall & Auto-Switch
useEffect(() => { useEffect(() => {
const checkOrg = async () => { const checkOrg = async () => {
if (!loading && user) { if (!loading && isAuthenticated) {
if (pathname?.startsWith('/onboarding')) return if (pathname?.startsWith('/onboarding')) return
if (pathname?.startsWith('/auth/callback')) return if (pathname?.startsWith('/auth/callback')) return
@@ -204,7 +209,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
} }
// * If user has organizations but no context (org_id), switch to the first one // * If user has organizations but no context (org_id), switch to the first one
if (!user.org_id && organizations.length > 0) { if (!userOrgId && organizations.length > 0) {
const firstOrg = organizations[0] const firstOrg = organizations[0]
try { try {
@@ -235,7 +240,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
} }
checkOrg() checkOrg()
}, [loading, user, pathname, router]) }, [loading, isAuthenticated, userOrgId, pathname, router])
return ( return (
<AuthContext.Provider value={{ user, loading, login, logout, refresh, refreshSession }}> <AuthContext.Provider value={{ user, loading, login, logout, refresh, refreshSession }}>