mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
Carry the reminder schedule and its ledger through backup and restore
The reminder cadences were the oldest entry on the coverage-pending register: carried in name, restored never — an account came back silent until every reminder was rebuilt by hand. Both models are two-ended now, in the house shape (both ends in one file, reminders-backup.ts): every column travels, nextDueAt verbatim rather than recomputed, the completion ledger beside it, tombstones in disaster recovery only, and a portable export omits a tombstoned reminder together with its ledger rows. Encounter.reminderId and VaccinationRecord.reminderId stop being dropped on restore: both remap against the restored reminders and fall to NULL with a skip report only when the file genuinely lacks the row. The wipe plan names the ledger child-before-parent; the classification guard, completeness guards and the integration round trip all demand the new coverage (proven failing with the section removed). Refs #223
This commit is contained in:
1 parent
a1ca0dc911
commit
b1be67bfa7
15 files changed
+864
-86
No files matched your search
@@ -292,6 +292,10 @@ function sourceClient() {
|
||||
encounterConditionLink: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
vaccinationRecord: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
vaccinationDocumentLink: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
// The reminder engine tables (v1.37.20, #223 / iOS #68). Empty for the
|
||||
// same reason as the visit tables above.
|
||||
measurementReminder: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
measurementReminderEvent: { findMany: vi.fn().mockResolvedValue([]) },
|
||||
customMetric: {
|
||||
findMany: vi.fn().mockResolvedValue([
|
||||
{
|
||||
|
||||
@@ -50,6 +50,7 @@ import { restoreIntradayProfileData } from "@/lib/export/intraday-profile-backup
|
||||
import { restoreHealthScoreData } from "@/lib/export/health-score-backup";
|
||||
import { restoreVisitsData } from "@/lib/export/visits-backup";
|
||||
import { restoreVaccinationsData } from "@/lib/export/vaccinations-backup";
|
||||
import { restoreRemindersData } from "@/lib/export/reminders-backup";
|
||||
import { invalidateUserData } from "@/lib/cache/invalidate";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -95,6 +96,8 @@ interface RestoreResponse {
|
||||
encounterLinks: number;
|
||||
vaccinations: number;
|
||||
vaccinationLinks: number;
|
||||
measurementReminders: number;
|
||||
measurementReminderEvents: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1329,12 +1332,28 @@ const handler = apiHandler(
|
||||
});
|
||||
}
|
||||
|
||||
// Visits, the address book and the three link tables. Last on
|
||||
// purpose: a link is written only when both of its ends exist, and
|
||||
// the documents above are the final far side to land. Both ends of
|
||||
// this section live in `src/lib/export/visits-backup.ts`, so a grep
|
||||
// of THIS file alone will not find them — the same delegation as the
|
||||
// cycle, profile, intraday and score restores above.
|
||||
// The Vorsorge reminders and their completion ledger (v1.37.20,
|
||||
// #223 / iOS #68), BEFORE the visits and the vaccinations: both of
|
||||
// those remap a `reminderId` against the reminders in the database,
|
||||
// so the reminders have to be in the database first or every
|
||||
// appointment and booster reference would read as unresolvable and
|
||||
// drop. Both ends of this section live in
|
||||
// `src/lib/export/reminders-backup.ts`.
|
||||
const remindersCleared = await restoreRemindersData(
|
||||
tx,
|
||||
ownerId,
|
||||
payload,
|
||||
skips,
|
||||
);
|
||||
|
||||
// Visits, the address book and the three link tables. After the
|
||||
// documents and the reminders on purpose: a link is written only
|
||||
// when both of its ends exist, and the encounter's reminder
|
||||
// reference remaps against the rows the branch above has just
|
||||
// written. Both ends of this section live in
|
||||
// `src/lib/export/visits-backup.ts`, so a grep of THIS file alone
|
||||
// will not find them — the same delegation as the cycle, profile,
|
||||
// intraday and score restores above.
|
||||
const visitsCleared = await restoreVisitsData(
|
||||
tx,
|
||||
ownerId,
|
||||
@@ -1343,10 +1362,10 @@ const handler = apiHandler(
|
||||
);
|
||||
|
||||
// The immunization log, after the visits: a dose remaps its
|
||||
// practitioner and its encounter against rows the branch above has
|
||||
// just written, and its document link needs the documents that
|
||||
// landed before that. Both ends of this section live in
|
||||
// `src/lib/export/vaccinations-backup.ts`.
|
||||
// practitioner, its encounter and its booster reminder against rows
|
||||
// the branches above have just written, and its document link needs
|
||||
// the documents that landed before that. Both ends of this section
|
||||
// live in `src/lib/export/vaccinations-backup.ts`.
|
||||
const vaccinationsCleared = await restoreVaccinationsData(
|
||||
tx,
|
||||
ownerId,
|
||||
@@ -1385,6 +1404,9 @@ const handler = apiHandler(
|
||||
encounterLinks: visitsCleared.encounterLinks,
|
||||
vaccinations: vaccinationsCleared.vaccinations,
|
||||
vaccinationLinks: vaccinationsCleared.vaccinationLinks,
|
||||
measurementReminders: remindersCleared.measurementReminders,
|
||||
measurementReminderEvents:
|
||||
remindersCleared.measurementReminderEvents,
|
||||
};
|
||||
return { cleared, skipped: summarizeRestoreSkips(skips) };
|
||||
},
|
||||
@@ -1537,6 +1559,8 @@ const handler = apiHandler(
|
||||
encounterLinks: summary.encounterLinks,
|
||||
vaccinations: summary.vaccinations,
|
||||
vaccinationLinks: summary.vaccinationLinks,
|
||||
measurementReminders: summary.measurementReminders,
|
||||
measurementReminderEvents: summary.measurementReminderEvents,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user