Explanation: Live Sync & Data Freshness
Deep dive into the Toast POS / 7shifts sync pipeline, FastAPI bridging, and cacheLife performance optimizations
This document explains the technical architecture of the Danvas external synchronization pipeline, including Dagster orchestration, Next.js 16 caching layers, and the circuit-breaker status engine.
The Synchronization Pipeline
Danvas synchronizes data from Toast POS (sales, clock-ins, orders, discounts) and 7shifts (scheduling, employees, roles). Integration runs are orchestrated by Dagster assets and background data-sync packages (@repo/data-sync, @repo/toast):
┌────────────────┐ Partition-native extraction ┌───────────────────┐
│ Toast / 7shifts├───────────────────────────────────────►│ Dagster Pipelines │
└────────────────┘ └─────────┬─────────┘
│ Writes to DB
▼
┌────────────────┐ Reads (cacheLife) ┌───────────────────┐
│ apps/app (RSC) ◄────────────────────────────────────────┤ Neon Database │
└────────────────┘ └───────────────────┘Ingestion & Active Writers
Orchestration is owned by Dagster assets (dagster/canvas_forge/) and database-backed sync packages:
- Adapter Layer:
@repo/toast/clientand@repo/sevenshiftshandle connection pools, retries, and token management. - Staging & Marts: Assets extract raw data into PostgreSQL staging tables (
stg_toast_*) and transform them intoanalytics.f_*marts. - State Tracking: Every execution updates high-watermark timestamps and circuit-breaker states in the
sync_statetable.
Next.js 16 cacheLife Optimization
The authenticated app uses Next.js 16 Cache Components for bounded live reads:
- Dashboard and monitoring caches:
getCachedDashboardSummary()andgetCachedMonitoringSummary()use the customliveprofile. The profile allows a 30-second client stale window, revalidates server results every 30 seconds, and expires entries after 60 seconds. - Tag-based invalidation: Dashboard mutations invalidate
dashboardSummaryTag(...)withupdateTag()for read-your-own-writes. Shift-task and location mutations invalidate their team-scoped tags withrevalidateTag(..., "max"). - Dynamic holes: These live reads remain request-time streamed content; their short expiration intentionally keeps them out of the static App Shell.
The client still performs non-blocking refreshes for status indicators. Cache
invalidation and freshness are separate concerns: invalidation removes known
stale entries, while the live profile bounds freshness when no mutation
signal is available.
Circuit-Breaker Status Engine
To prevent cascading failures and continuous hammering when third-party APIs experience outages:
- The sync manager tracks sequential execution failures in
sync_state. - If a sync source fails 3 times consecutively, the circuit opens, marking the source as
disabledand triggering an alert. - While the circuit is open, subsequent reads serve cached local marts directly, preventing UI requests from blocking.
- The circuit breaker transitions to
half_openafter a 5-minute cooldown period to attempt a recovery sync.