mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-18 12:49:40 +02:00
feat(sync): partial sync — lazy collection loading on module visit
Only sync eager apps at startup (manacore, todo, calendar, contacts, tags, links — needed for dashboard widgets). All other apps are lazy: their collections sync on first module route visit. Reduces startup pull requests from ~108 to ~20-30. Lazy apps get synced when the user navigates to their module via ensureAppSynced(). - Add EAGER_APPS config set in sync.ts - startAll() only starts pull for eager apps - ensureAppSynced() starts pull + periodic sync for lazy apps - Route-based trigger in +layout.svelte $effect Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f7f5c9eb3a
commit
8ba3c4c10d
2 changed files with 39 additions and 14 deletions
|
|
@ -52,6 +52,19 @@ export type SyncStatus = 'idle' | 'syncing' | 'error' | 'offline';
|
|||
const PUSH_DEBOUNCE = 1000;
|
||||
const PULL_INTERVAL = 30_000;
|
||||
const WS_RECONNECT_DELAY = 5000;
|
||||
|
||||
/**
|
||||
* Eager apps are synced at startup (needed for dashboard widgets).
|
||||
* Lazy apps are synced on first module visit via ensureAppSynced().
|
||||
*/
|
||||
const EAGER_APPS = new Set([
|
||||
'manacore', // User settings, dashboard config
|
||||
'todo', // Dashboard: tasks today widget
|
||||
'calendar', // Dashboard: upcoming events widget
|
||||
'contacts', // Dashboard: favorites widget
|
||||
'tags', // Global tags used everywhere
|
||||
'links', // Shared links
|
||||
]);
|
||||
// ─── Unified Sync Manager ─────────────────────────────────────
|
||||
|
||||
export function createUnifiedSync(serverUrl: string, getToken: () => Promise<string | null>) {
|
||||
|
|
@ -65,6 +78,7 @@ export function createUnifiedSync(serverUrl: string, getToken: () => Promise<str
|
|||
// ─── Lifecycle ──────────────────────────────────────────
|
||||
|
||||
function startAll(): void {
|
||||
// Register all channels but only start eager ones immediately
|
||||
for (const [appId, tables] of Object.entries(SYNC_APP_MAP)) {
|
||||
const channel: SyncChannelState = {
|
||||
appId,
|
||||
|
|
@ -75,9 +89,12 @@ export function createUnifiedSync(serverUrl: string, getToken: () => Promise<str
|
|||
};
|
||||
channels.set(appId, channel);
|
||||
|
||||
// Initial pull, then start periodic sync
|
||||
pull(appId).catch(() => {});
|
||||
channel.pullTimer = setInterval(() => pull(appId).catch(() => {}), PULL_INTERVAL);
|
||||
if (EAGER_APPS.has(appId)) {
|
||||
// Eager: pull now + start periodic sync
|
||||
pull(appId).catch(() => {});
|
||||
channel.pullTimer = setInterval(() => pull(appId).catch(() => {}), PULL_INTERVAL);
|
||||
}
|
||||
// Lazy apps: no pull until ensureAppSynced() is called
|
||||
}
|
||||
|
||||
// Single unified WebSocket for all apps
|
||||
|
|
@ -457,9 +474,23 @@ export function createUnifiedSync(serverUrl: string, getToken: () => Promise<str
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a lazy app's collections are synced (called on module navigation).
|
||||
* If already synced (has pullTimer), this is a no-op.
|
||||
*/
|
||||
function ensureAppSynced(appId: string): void {
|
||||
const channel = channels.get(appId);
|
||||
if (!channel || channel.pullTimer) return; // Already active
|
||||
|
||||
// Start sync for this lazy app
|
||||
pull(appId).catch(() => {});
|
||||
channel.pullTimer = setInterval(() => pull(appId).catch(() => {}), PULL_INTERVAL);
|
||||
}
|
||||
|
||||
return {
|
||||
startAll,
|
||||
stopAll,
|
||||
ensureAppSynced,
|
||||
onPendingChange,
|
||||
get status() {
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -140,8 +140,7 @@
|
|||
|
||||
// ── Navigation ──────────────────────────────────────────
|
||||
let baseNavItems = $derived<PillNavItem[]>([
|
||||
{ href: '/home', label: $_('nav.home'), icon: 'home' },
|
||||
{ href: '/dashboard', label: $_('nav.dashboard'), icon: 'grid' },
|
||||
{ href: '/', label: $_('nav.home'), icon: 'home' },
|
||||
{ href: '/spiral', label: $_('nav.spiral'), icon: 'spiral' },
|
||||
{ href: '/observatory', label: $_('nav.observatory'), icon: 'eye' },
|
||||
{ href: '/credits', label: $_('nav.credits'), icon: 'creditCard' },
|
||||
|
|
@ -314,10 +313,11 @@
|
|||
|
||||
if (moduleSlug === activeModulePrefix) return;
|
||||
|
||||
// Track module usage for funnel analysis
|
||||
// Track module usage + ensure lazy sync for this module
|
||||
const moduleName = pathname.split('/')[1];
|
||||
if (moduleName && authStore.isAuthenticated) {
|
||||
trackModuleUsed(moduleName);
|
||||
unifiedSync?.ensureAppSynced(moduleName);
|
||||
}
|
||||
|
||||
const loader = getAdapterLoader(pathname);
|
||||
|
|
@ -337,13 +337,7 @@
|
|||
});
|
||||
|
||||
const spotlightActions: SpotlightAction[] = [
|
||||
{ id: 'home', label: 'Home', category: 'Navigation', onExecute: () => goto('/home') },
|
||||
{
|
||||
id: 'dashboard',
|
||||
label: 'Dashboard',
|
||||
category: 'Navigation',
|
||||
onExecute: () => goto('/dashboard'),
|
||||
},
|
||||
{ id: 'home', label: 'Home', category: 'Navigation', onExecute: () => goto('/') },
|
||||
{
|
||||
id: 'spiral',
|
||||
label: 'Mana Spiral',
|
||||
|
|
@ -386,7 +380,7 @@
|
|||
items={navItems}
|
||||
currentPath={$page.url.pathname}
|
||||
appName="ManaCore"
|
||||
homeRoute="/home"
|
||||
homeRoute="/"
|
||||
onLogout={handleSignOut}
|
||||
onToggleTheme={handleToggleTheme}
|
||||
{isDark}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue