mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
Output of `node scripts/strip-planning-tags.mjs --write`: 3,157 comment lines in 1,308 files lose the work-item identifier at their head. Release versions and issue references stay; nothing outside comment text changes, which the script checks per file against a comment-free printout. healthlog/no-planning-tags is enabled at error level with this commit, so the tree it lands on is clean.
231 lines
9.7 KiB
TypeScript
231 lines
9.7 KiB
TypeScript
/**
|
|
* What a backup is, without the schema that checks one.
|
|
*
|
|
* `backupPayloadSchema` (`backup.ts`) is the largest Zod tree in the server:
|
|
* built at import, it holds about 12 MB of heap. Everything here is what the
|
|
* backup paths need besides that check: the schema version, whether a file's
|
|
* version is one this server reads, and the per-section counts of a payload
|
|
* that has already been parsed. Importing this module never builds the
|
|
* schema, so a module on the boot path (the restore job, the stored-backup
|
|
* readers, the export writer) can import it freely and load `backup.ts` with
|
|
* a dynamic `import()` at the moment a file is actually validated.
|
|
*/
|
|
import type { BackupPayload } from "@/lib/validations/backup";
|
|
|
|
export const BACKUP_SCHEMA_VERSION = "2" as const;
|
|
export const LEGACY_BACKUP_SCHEMA_VERSION = "1" as const;
|
|
|
|
/**
|
|
* Numeric counts of each backed-up record kind. Returned in the
|
|
* upload + restore API responses so the admin sees what they
|
|
* uploaded/restored without having to download the file again.
|
|
*/
|
|
export interface BackupSummary {
|
|
schemaVersion: string;
|
|
userId: string;
|
|
exportedAt: string;
|
|
measurements: number;
|
|
medications: number;
|
|
intakeEvents: number;
|
|
/** Side effects recorded against a drug, across every medication. */
|
|
medicationSideEffects: number;
|
|
/** Pinned efficacy targets, across every medication. */
|
|
medicationEfficacyTargets: number;
|
|
/** Archived schedule eras, across every medication. */
|
|
medicationScheduleRevisions: number;
|
|
moodEntries: number;
|
|
/** v1.15.0 — observed cycle spans in the backup. */
|
|
cycles: number;
|
|
/** v1.15.0 — cycle day-logs in the backup. */
|
|
cycleDayLogs: number;
|
|
/** Lab results in the backup. */
|
|
labResults: number;
|
|
nutrientDays: number;
|
|
/** User-scoped biomarker catalog entries in the backup. */
|
|
biomarkers: number;
|
|
/** Illness episodes, including flares/exacerbations. */
|
|
illnessEpisodes: number;
|
|
/** Illness day-logs across every episode. */
|
|
illnessDayLogs: number;
|
|
/** Allergy/intolerance records in the backup. */
|
|
allergies: number;
|
|
/** Family-history entries in the backup. */
|
|
familyHistory: number;
|
|
/** Workout summary records in the backup. */
|
|
workouts: number;
|
|
/** Document records (ciphertext included in canonical DR payloads). */
|
|
documents: number;
|
|
/** Which documents were filed against which condition. */
|
|
documentConditionLinks: number;
|
|
/** Facts staged out of a document, with their review decision. */
|
|
extractedFacts: number;
|
|
/** 1 when the account's durable self-context rides the file, 0 otherwise. */
|
|
healthProfile: number;
|
|
/** Effective-dated structured health-profile revisions. */
|
|
healthProfileFactRevisions: number;
|
|
/** Metrics the account defined itself. */
|
|
customMetrics: number;
|
|
/** Readings across every user-defined metric. */
|
|
customMetricEntries: number;
|
|
/** Persisted accepted correlation identities and dismissal decisions. */
|
|
correlationPatterns: number;
|
|
/** Stored day curves for the cumulative metrics, across every metric. */
|
|
intradayProfiles: number;
|
|
/** Local days whose health score was written down as it was shown. */
|
|
healthScoreRecords: number;
|
|
/** 1 when the record's setup answers ride the file, 0 otherwise. */
|
|
onboardingRecords: number;
|
|
/** v1.37.19 — the visit address book. */
|
|
practitioners: number;
|
|
/** v1.37.19 — doctor visits, planned and past. */
|
|
encounters: number;
|
|
/** v1.37.19 — the three encounter link tables, summed. */
|
|
encounterLinks: number;
|
|
/** v1.37.19 — immunization log entries. */
|
|
vaccinations: number;
|
|
/** v1.37.19 — vaccination↔document links. */
|
|
vaccinationLinks: number;
|
|
/** v1.43 — the five relation link tables, summed. */
|
|
relationLinks: number;
|
|
/** v1.42 (#1005) — the person's own vaccine definitions. */
|
|
customVaccines: number;
|
|
/** v1.37.20 (#223 / iOS #68) — Vorsorge reminder cadences. */
|
|
measurementReminders: number;
|
|
/** v1.37.20 (#223 / iOS #68) — completion-ledger rows across every reminder. */
|
|
measurementReminderEvents: number;
|
|
/** Coach conversation threads. */
|
|
coachConversations: number;
|
|
/** Coach turns across every thread. */
|
|
coachMessages: number;
|
|
/** Durable facts, agreed plans and things to bring back up. */
|
|
coachFacts: number;
|
|
coachPlans: number;
|
|
coachReminders: number;
|
|
/** Completed screener administrations. Disaster-recovery payloads only. */
|
|
mentalHealthAssessments: number;
|
|
/** Consent records. Disaster-recovery payloads only. */
|
|
consentReceipts: number;
|
|
/** Personal bests across every metric and sport slot. */
|
|
personalRecords: number;
|
|
/** Badges the account has unlocked, each with the day it was earned. */
|
|
userAchievements: number;
|
|
/** Local days with an environmental reading. */
|
|
environmentContexts: number;
|
|
/** Declared stretches spent away from home. */
|
|
environmentTravelLocations: number;
|
|
/** Local days of Dawarich movement values. */
|
|
dawarichDays: number;
|
|
/** ECG strips, with their rhythm verdict and their trace. */
|
|
ecgRecordings: number;
|
|
}
|
|
|
|
export function summarizeBackup(payload: BackupPayload): BackupSummary {
|
|
return {
|
|
schemaVersion: payload.schemaVersion,
|
|
userId: payload.userId,
|
|
exportedAt: payload.exportedAt,
|
|
measurements: payload.measurements.length,
|
|
medications: payload.medications.length,
|
|
intakeEvents: payload.intakeEvents.length,
|
|
medicationSideEffects: payload.medications.reduce(
|
|
(sum, medication) => sum + medication.sideEffects.length,
|
|
0,
|
|
),
|
|
medicationEfficacyTargets: payload.medications.reduce(
|
|
(sum, medication) => sum + medication.efficacyTargets.length,
|
|
0,
|
|
),
|
|
medicationScheduleRevisions: payload.medications.reduce(
|
|
(sum, medication) => sum + medication.scheduleRevisions.length,
|
|
0,
|
|
),
|
|
moodEntries: payload.moodEntries.length,
|
|
cycles: payload.cycles.length,
|
|
cycleDayLogs: payload.cycleDayLogs.length,
|
|
nutrientDays: payload.nutrientDays.length,
|
|
labResults: payload.labResults.length,
|
|
biomarkers: payload.biomarkers.length,
|
|
illnessEpisodes: payload.illnessEpisodes.length,
|
|
illnessDayLogs: payload.illnessEpisodes.reduce(
|
|
(sum, e) => sum + e.dayLogs.length,
|
|
0,
|
|
),
|
|
allergies: payload.allergies.length,
|
|
familyHistory: payload.familyHistory.length,
|
|
workouts: payload.workouts.length,
|
|
documents: payload.documents.length,
|
|
// Counted from the release that carries them, so the admin's "what did I
|
|
// just restore" answer never under-counts a filed vault the way it once
|
|
// did for visits.
|
|
documentConditionLinks: payload.documentConditionLinks.length,
|
|
extractedFacts: payload.extractedFacts.length,
|
|
healthProfile: payload.healthProfile ? 1 : 0,
|
|
healthProfileFactRevisions: payload.healthProfileFacts.length,
|
|
customMetrics: payload.customMetrics.length,
|
|
customMetricEntries: payload.customMetrics.reduce(
|
|
(sum, metric) => sum + metric.entries.length,
|
|
0,
|
|
),
|
|
correlationPatterns: payload.correlationPatterns.length,
|
|
intradayProfiles: payload.intradayProfiles.length,
|
|
healthScoreRecords: payload.healthScoreRecords.length,
|
|
onboardingRecords: payload.onboardingRecord ? 1 : 0,
|
|
// v1.37.19 — the sections restored since 08-01 were written and
|
|
// restored but absent from this report, so the admin's "what did I just
|
|
// restore" answer silently under-counted a file that carried visits or
|
|
// an Impfpass.
|
|
practitioners: payload.practitioners.length,
|
|
encounters: payload.encounters.length,
|
|
encounterLinks:
|
|
payload.encounterDocumentLinks.length +
|
|
payload.encounterLabLinks.length +
|
|
payload.encounterConditionLinks.length,
|
|
vaccinations: payload.vaccinations.length,
|
|
vaccinationLinks: payload.vaccinationDocumentLinks.length,
|
|
relationLinks:
|
|
payload.labResultDocumentLinks.length +
|
|
payload.encounterMedicationLinks.length +
|
|
payload.encounterVaccinationLinks.length +
|
|
payload.medicationDocumentLinks.length +
|
|
payload.medicationConditionLinks.length,
|
|
customVaccines: payload.customVaccines.length,
|
|
// v1.37.20 (#223 / iOS #68) — counted from the release that carries them,
|
|
// so the admin's "what did I just restore" answer never under-counts a
|
|
// file with reminders the way it once did for visits.
|
|
measurementReminders: payload.measurementReminders.length,
|
|
measurementReminderEvents: payload.measurementReminderEvents.length,
|
|
coachConversations: payload.coachConversations.length,
|
|
coachMessages: payload.coachConversations.reduce(
|
|
(total, conversation) => total + conversation.messages.length,
|
|
0,
|
|
),
|
|
coachFacts: payload.coachFacts.length,
|
|
coachPlans: payload.coachPlans.length,
|
|
coachReminders: payload.coachReminders.length,
|
|
mentalHealthAssessments: payload.mentalHealthAssessments.length,
|
|
consentReceipts: payload.consentReceipts.length,
|
|
// Counted from the release that carries them, so the admin's "what did I
|
|
// just restore" answer never under-counts a file with bests, badges or an
|
|
// environmental history the way it once did for visits.
|
|
personalRecords: payload.personalRecords.length,
|
|
userAchievements: payload.userAchievements.length,
|
|
environmentContexts: payload.environmentContexts.length,
|
|
environmentTravelLocations: payload.environmentTravelLocations.length,
|
|
dawarichDays: payload.dawarichDays.length,
|
|
ecgRecordings: payload.ecgRecordings.length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* The schemaVersion the system understands today. Used by the upload
|
|
* route to reject inbound files written by a *future* HealthLog instance
|
|
* — restoring them under the current code might silently drop data the
|
|
* new shape carried.
|
|
*/
|
|
export function isCompatibleSchemaVersion(version: string): boolean {
|
|
return (
|
|
version === LEGACY_BACKUP_SCHEMA_VERSION ||
|
|
version === BACKUP_SCHEMA_VERSION
|
|
);
|
|
}
|