Files
Wellspringmanagement01/apps/Backend/src/services/networkSyncConfigService.ts
T
ffandClaude Sonnet 4.6 f5f3768108 feat: add Network Backup section to Database Management
PC2 can now automatically pull and restore a fresh copy of PC1's database
on a daily schedule. Config and API key are stored in local JSON files so
they survive database restores.

- New networkSyncConfigService: file-based config (network-backup-key.json,
  network-sync-config.json) that persists through DB restores
- New networkSyncService: streams live pg_dump from source PC over HTTP and
  pipes into psql, then reconnects Prisma and applies missing migrations
- 6 new endpoints: get/regenerate API key, serve backup stream (key-auth
  only), get/save sync config, trigger immediate sync
- Hourly cron job that fires only when current hour matches configured syncHour
- NetworkBackupManager component: shows this machine's key (show/copy/regen)
  and receiver config (enable toggle, hour picker 0-23, source URL + key,
  Save + Sync Now, last sync status)
- README setup guide for both PCs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 00:15:42 -04:00

59 lines
1.5 KiB
TypeScript

import fs from "fs";
import path from "path";
import crypto from "crypto";
const KEY_FILE = path.resolve(process.cwd(), "network-backup-key.json");
const CONFIG_FILE = path.resolve(process.cwd(), "network-sync-config.json");
export interface NetworkSyncConfig {
enabled: boolean;
syncHour: number;
sourceUrl: string;
apiKey: string;
lastSyncAt: string | null;
lastSyncStatus: string | null;
lastSyncError: string | null;
}
export function getOrCreateApiKey(): string {
if (fs.existsSync(KEY_FILE)) {
try {
const data = JSON.parse(fs.readFileSync(KEY_FILE, "utf8"));
if (data.apiKey) return data.apiKey;
} catch {}
}
const key = crypto.randomUUID();
fs.writeFileSync(KEY_FILE, JSON.stringify({ apiKey: key }), "utf8");
return key;
}
export function regenerateApiKey(): string {
const key = crypto.randomUUID();
fs.writeFileSync(KEY_FILE, JSON.stringify({ apiKey: key }), "utf8");
return key;
}
export function readSyncConfig(): NetworkSyncConfig {
if (fs.existsSync(CONFIG_FILE)) {
try {
return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
} catch {}
}
return {
enabled: false,
syncHour: 0,
sourceUrl: "",
apiKey: "",
lastSyncAt: null,
lastSyncStatus: null,
lastSyncError: null,
};
}
export function writeSyncConfig(patch: Partial<NetworkSyncConfig>): NetworkSyncConfig {
const current = readSyncConfig();
const updated = { ...current, ...patch };
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), "utf8");
return updated;
}