feat:improve performance improvements#544
Merged
Merged
Conversation
…#504) - Add tenant_id column to audit_logs with backfill from users table - Create tenant_partitions registry table for partition lifecycle tracking - Add create_tenant_partition() and refresh_partition_stats() PG functions - Create partitioned shadow tables for payments, invoices, audit_logs, webhook_logs - Seed shadow tables from originals with ON CONFLICT DO NOTHING for safety - Add PartitionManager class with createPartition, dropTenantPartitions, getPartitionStats, migrateExistingTenantData, and getQueryMetrics APIs - Zero-downtime strategy: shadow tables run alongside originals; cutover handled by partition-manager outside of migration to allow rollback
…martdevs17#503) - Add useCreatePayment, useUpdatePayment, useCancelPayment, useRetryPayment mutation hooks with TanStack Query optimistic update pattern - onMutate snapshots cache and applies optimistic state immediately - onError rolls back to snapshot; onSettled invalidates for server sync - Payments above OPTIMISTIC_THRESHOLD (10k) skip optimistic path - OptimisticStatus badge component shows pending/success/error with spinner - StaleBadge and ConflictBanner components for stale/conflict UX - useMutationState helper derives MutationState from isPending/isSuccess/isError - Extend query-keys with invoices, webhooks, and payments.infinite namespaces
- Add cache-headers.ts middleware with configurable Cache-Control and Surrogate-Control header management per CDN TTL tier (none/user/static) - Vary header includes Accept, Accept-Language plus hashed X-Auth-Hash so CDN can cache per-user responses without exposing raw tokens in cache keys - Surrogate-Key / Cache-Tag headers enable tag-based purge on data mutation - purgeCdnCache() supports CloudFront, Cloudflare, and Fastly providers - Pre-built cdnCache presets: none, realtime, userData, staticData - getCacheMetrics() and getCacheHitRatioSummary() for monitoring - cdn.tf: CloudFront distribution with per-path behaviours: no-cache for mutations, 30 s TTL for user data, 5 min for static, with origin shield - CloudFront Function hashes Authorization into X-Auth-Hash before caching - CDN access logs stored in S3 with 90-day lifecycle expiry
…ync (Smartdevs17#501) - Add offline-queue.ts: IndexedDB-backed queue with enqueue, flush, getSnapshot, removeItem, clearAll, and subscribeToQueue APIs - Exponential backoff on retry: 5 s, 15 s, 1 min, 5 min, 10 min; max 5 retries - 409 Conflict treated as success (idempotent replay protection) - SyncManager registration on enqueue for automatic background sync - subscribeToQueue dispatches CustomEvent for cross-component reactivity - Add useOnlineStatus hook: tracks online/offline state, auto-flushes on reconnect, listens to SW PAYMENT_QUEUE_CHANGED/SYNCED messages, exposes flushNow() for manual sync trigger and queue snapshot for UI display - Update sw.js: bump to APP_VERSION 2026-06-27.1, add /dashboard/payments and /dashboard/transactions to precache shell, upgrade IndexedDB to v2 with retryAt index, apply exponential backoff in flushPaymentQueue, honour retryAt filter to skip items not yet due for retry
|
@Samuel1505 is attempting to deploy a commit to the smartdevs17's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Samuel1505 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Performance improvements: DB partitioning, optimistic UI, CDN edge caching, PWA offline queue
Summary
This PR implements four performance issues (#501–#504) to improve query performance, perceived latency, API response time for distributed users, and offline resilience.
closes #504
closes #503
closes #502
closes #501
#504 — Database Partitioning by Tenant
Files changed
backend/prisma/migrations/20260627000000_tenant_partitioning/migration.sqlbackend/src/db/partition-manager.tsWhat was done
Added PostgreSQL LIST partitioning by
tenant_idfor the four high-volume tables (payments,invoices,audit_logs,webhook_logs).audit_logsgains atenant_idcolumn with backfill fromusers.tenant_id(falls back to'system'for non-user actors).tenant_partitionsregistry table tracks every partition with row counts, byte sizes, and last-analyzed timestamps.create_tenant_partition(table, tenant)(idempotent) andrefresh_partition_stats().payments_partitioned,invoices_partitioned,audit_logs_partitioned,webhook_logs_partitioned) are seeded from the originals withON CONFLICT DO NOTHING.PartitionManagerTypeScript class exposes:ensurePartitionsForTenant(tenantId)— call when a new tenant registersdropTenantPartitions(tenantId)— archive/delete a tenant's data by dropping their partitiongetPartitionStats([tenantId])— monitoring: size and row counts per partitiongetPartitionDistribution()— aggregate by table for dashboardsmigrateExistingTenantData(tenantId, table)— backfill per-tenant with error resultmigrateAllTenants(table)— full table backfillgetQueryMetrics(tenantId, table)— pruning efficiency metricZero-downtime strategy: shadow tables run in parallel with originals. The cutover (rename) is deferred to a maintenance window and driven by
PartitionManager, not the migration itself, so rollback is a single rename.#503 — Optimistic UI Updates with Background Revalidation
Files changed
frontend/src/hooks/mutations/usePaymentMutations.tsfrontend/src/components/common/optimistic-status.tsxfrontend/lib/query-keys.tsWhat was done
TanStack Query v5 optimistic update pattern applied to all payment mutations.
useCreatePayment— immediately prepends an optimistic payment to the cache list; skips optimistic path for amounts >=OPTIMISTIC_THRESHOLD(10 000) to avoid false positives on critical transactions.useUpdatePayment— patches both list and detail caches;onErrorrestores both from snapshot.useCancelPayment— sets status to'cancelled'optimistically; rolls back on error.useRetryPayment— no optimistic update (server drives the retry outcome).onMutateto snapshot and apply,onErrorto rollback,onSettledto invalidate for server revalidation.OptimisticStatusbadge component: shows spinner/label duringpending, checkmark onsuccess, error label onerror; auto-hides after configurable duration; marks optimistic items with(optimistic)suffix.StaleBadgeandConflictBannercomponents for stale-data and server-vs-optimistic conflict UX.useMutationStatehelper derivesMutationStatefrom TanStack Query's boolean flags.query-keys.tsextended withinvoices,webhooks, andpayments.infinitenamespaces.#502 — CDN-Powered Geo-Distributed API Edge Caching
Files changed
backend/src/middleware/cache-headers.tsinfra/cdn.tfWhat was done
Adds
Cache-Control/Surrogate-Controlheader management and a CloudFront distribution.Middleware (
cache-headers.ts)cacheHeaders(options)middleware setsCache-ControlandSurrogate-Controlwith configurable TTL,stale-while-revalidate, andstale-if-error.X-Auth-Hash;Varyincludes this hash so CDN caches per-user without storing raw tokens in cache keys.Surrogate-Key/Cache-Tagheaders enable tag-based purge after mutations.purgeCdnCache({ provider, paths?, surrogateKeys? })supports CloudFront, Cloudflare, and Fastly.cdnCache.none(),cdnCache.realtime(),cdnCache.userData(),cdnCache.staticData().getCacheMetrics()andgetCacheHitRatioSummary()for monitoring dashboards.Terraform (
cdn.tf)/api/v1/payments*,/api/v1/invoices*,/api/v1/config*,/api/v1/currencies*.cdn_distribution_id,cdn_domain_name,cdn_hosted_zone_idoutputs for Route53 alias wiring.#501 — Progressive Web App with Offline Transaction Queuing
Files changed
frontend/src/lib/offline-queue.tsfrontend/src/hooks/useOnlineStatus.tsfrontend/public/sw.jsWhat was done
IndexedDB-backed offline transaction queue with automatic background sync.
offline-queue.tsenqueue(input)— writes to IndexedDB, registers a SyncManager tag, and dispatches aCustomEventfor cross-component reactivity.flush(apiBaseUrl)— submits all due items (respectsretryAt), markssyncedor applies exponential backoff (5 s -> 15 s -> 1 min -> 5 min -> 10 min); after 5 retries status is'failed'.getSnapshot()— counts by status for UI indicators.subscribeToQueue(listener)— event-based subscription; unsubscribe function returned.useOnlineStatus.tsnavigator.onLineviaonline/offlinewindow events.onlineevent): callsflush()automatically.PAYMENT_QUEUE_CHANGEDandPAYMENT_QUEUE_SYNCEDmessages from the service worker.flushNow()for manual sync (e.g. a "Sync now" button in the UI).{ isOnline, wasOffline, queue, isFlushing, lastFlushResult, flushNow }.sw.jsupdatesAPP_VERSIONto2026-06-27.1to invalidate old caches on deploy./dashboard/paymentsand/dashboard/transactionsto the precache App Shell.retryAtindex for efficient due-item queries.flushPaymentQueuefilters byretryAt <= now()before submitting; applies same exponential backoff; stops retrying on offline detection.Test plan
PartitionManager.ensurePartitionsForTenant('test-tenant')creates four partitions;EXPLAIN (ANALYZE) SELECT * FROM payments_partitioned WHERE tenant_id = 'test-tenant'showsBitmap Index Scanon the single partition only.dropTenantPartitions('test-tenant')drops all four partitions and removes registry rows.OptimisticStatusshows spinner during mutation, checkmark on success, auto-hides after 2 s.GET /api/v1/paymentsresponse hasCache-Control: private, max-age=30, stale-while-revalidate=60.POST /api/v1/paymentsresponse hasCache-Control: no-store.purgeCdnCachefor the relevant surrogate key (check Cloudflare/CloudFront purge logs).getSnapshot()showspending: 1.getSnapshot()showstotal: 0.'failed'after 5 attempts.