initial commit

This commit is contained in:
voltsrage
2026-06-26 04:20:20 +08:00
commit 869006e5e7
64 changed files with 4632 additions and 0 deletions
@@ -0,0 +1,31 @@
public class DigitizationBatch
{
public Guid Id { get; set; }
public BatchStatus Status { get; set; }
public BatchType BatchType { get; set; }
public BatchTrack Track { get; set; }
public Guid? PatientId { get; set; }
public Guid? EncounterDraftId { get; set; }
public string DocumentRef { get; set; } = null!;
public string DocumentSha256 { get; set; } = null!;
public bool EnableRetroactiveAlerts { get; set; }
public Guid? EnteredByUserId { get; set; }
public Guid? VerifiedByUserId { get; set; }
public Guid? ApprovedByUserId { get; set; }
public string? RejectionReason { get; set; }
public DateTimeOffset? PromotedAt { get; set; }
public Guid? PromotionEncounterId { get; set; }
public Guid? SupersedesBatchId { get; set; }
public bool ClinicianAttestation { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public User? EnteredByUser { get; set; }
public User? VerifiedByUser { get; set; }
public User? ApprovedByUser { get; set; }
public ScannedDocument? Document { get; set; }
public DraftPatient? DraftPatient { get; set; }
public DraftEncounter? DraftEncounter { get; set; }
public ICollection<DraftObservation> DraftObservations { get; set; } = new List<DraftObservation>();
public ICollection<DigitizationEvent> Events { get; set; } = new List<DigitizationEvent>();
}
@@ -0,0 +1,12 @@
public class DigitizationEvent
{
public Guid Id { get; set; }
public Guid BatchId { get; set; }
public DigitizationEventType EventType { get; set; }
public Guid ActorUserId { get; set; }
public DateTimeOffset OccurredAt { get; set; }
public string? MetadataJson { get; set; }
public DigitizationBatch Batch { get; set; } = null!;
public User Actor { get; set; } = null!;
}
@@ -0,0 +1,15 @@
public class DraftEncounter
{
public Guid Id { get; set; }
public Guid BatchId { get; set; }
public DateTimeOffset? AdmissionDate { get; set; }
public Department? Department { get; set; }
public string? RoomBed { get; set; }
public string? AdmissionReason { get; set; }
public string? DischargeDiagnosis { get; set; }
public string? Status { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public DigitizationBatch Batch { get; set; } = null!;
}
@@ -0,0 +1,13 @@
public class DraftObservation
{
public Guid Id { get; set; }
public Guid BatchId { get; set; }
public string ObservationCode { get; set; } = null!;
public decimal Value { get; set; }
public string Unit { get; set; } = null!;
public DateTimeOffset RecordedAt { get; set; }
public string? Note { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DigitizationBatch Batch { get; set; } = null!;
}
@@ -0,0 +1,18 @@
public class DraftPatient
{
public Guid Id { get; set; }
public Guid BatchId { get; set; }
public string? FullName { get; set; }
public DateOnly? DateOfBirth { get; set; }
public string? Sex { get; set; }
public BloodType? BloodType { get; set; }
public string? EmergencyContact { get; set; }
public string? AllergiesJson { get; set; }
public bool NoKnownAllergies { get; set; }
public string? MedicationsJson { get; set; }
public bool NoActiveMedications { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public DateTimeOffset UpdatedAt { get; set; }
public DigitizationBatch Batch { get; set; } = null!;
}
@@ -0,0 +1,12 @@
public class ScannedDocument
{
public Guid Id { get; set; }
public Guid BatchId { get; set; }
public string ObjectKey { get; set; } = null!;
public string Sha256 { get; set; } = null!;
public string ContentType { get; set; } = null!;
public long FileSizeBytes { get; set; }
public DateTimeOffset UploadedAt { get; set; }
public DigitizationBatch Batch { get; set; } = null!;
}
@@ -0,0 +1,10 @@
public class User
{
public Guid Id { get; set; }
public string Username { get; set; } = null!;
public string PasswordHash { get; set; } = null!;
public string FullName { get; set; } = null!;
public UserRole Role { get; set; }
public bool IsActive { get; set; } = true;
public DateTimeOffset CreatedAt { get; set; }
}
@@ -0,0 +1,30 @@
public enum BatchStatus { Uploaded, InEntry, PendingVerification, Rejected, Verified, AwaitingClinicalApproval, Approved, Promoted }
public static class BatchStatusExtensions
{
public static string ToDbString(this BatchStatus s) => s switch
{
BatchStatus.Uploaded => "UPLOADED",
BatchStatus.InEntry => "IN_ENTRY",
BatchStatus.PendingVerification => "PENDING_VERIFICATION",
BatchStatus.Rejected => "REJECTED",
BatchStatus.Verified => "VERIFIED",
BatchStatus.AwaitingClinicalApproval => "AWAITING_CLINICAL_APPROVAL",
BatchStatus.Approved => "APPROVED",
BatchStatus.Promoted => "PROMOTED",
_ => throw new ArgumentOutOfRangeException(nameof(s))
};
public static BatchStatus FromDbString(string v) => v switch
{
"UPLOADED" => BatchStatus.Uploaded,
"IN_ENTRY" => BatchStatus.InEntry,
"PENDING_VERIFICATION" => BatchStatus.PendingVerification,
"REJECTED" => BatchStatus.Rejected,
"VERIFIED" => BatchStatus.Verified,
"AWAITING_CLINICAL_APPROVAL" => BatchStatus.AwaitingClinicalApproval,
"APPROVED" => BatchStatus.Approved,
"PROMOTED" => BatchStatus.Promoted,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown batch status: '{v}'")
};
}
@@ -0,0 +1,18 @@
public enum BatchTrack { Backfill, LiveCapture }
public static class BatchTrackExtensions
{
public static string ToDbString(this BatchTrack t) => t switch
{
BatchTrack.Backfill => "BACKFILL",
BatchTrack.LiveCapture => "LIVE_CAPTURE",
_ => throw new ArgumentOutOfRangeException(nameof(t))
};
public static BatchTrack FromDbString(string v) => v switch
{
"BACKFILL" => BatchTrack.Backfill,
"LIVE_CAPTURE" => BatchTrack.LiveCapture,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown batch track: '{v}'")
};
}
@@ -0,0 +1,28 @@
public enum BatchType { PatientRegistration, EncounterSummary, VitalsSheet, LabResults, MedicationList, AllergyUpdate, Mixed }
public static class BatchTypeExtensions
{
public static string ToDbString(this BatchType t) => t switch
{
BatchType.PatientRegistration => "PATIENT_REGISTRATION",
BatchType.EncounterSummary => "ENCOUNTER_SUMMARY",
BatchType.VitalsSheet => "VITALS_SHEET",
BatchType.LabResults => "LAB_RESULTS",
BatchType.MedicationList => "MEDICATION_LIST",
BatchType.AllergyUpdate => "ALLERGY_UPDATE",
BatchType.Mixed => "MIXED",
_ => throw new ArgumentOutOfRangeException(nameof(t))
};
public static BatchType FromDbString(string v) => v switch
{
"PATIENT_REGISTRATION" => BatchType.PatientRegistration,
"ENCOUNTER_SUMMARY" => BatchType.EncounterSummary,
"VITALS_SHEET" => BatchType.VitalsSheet,
"LAB_RESULTS" => BatchType.LabResults,
"MEDICATION_LIST" => BatchType.MedicationList,
"ALLERGY_UPDATE" => BatchType.AllergyUpdate,
"MIXED" => BatchType.Mixed,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown batch type: '{v}'")
};
}
@@ -0,0 +1,37 @@
public enum BloodType { APos, ANeg, BPos, BNeg, AbPos, AbNeg, OPos, ONeg }
public static class BloodTypeExtensions
{
public static string ToDbString(this BloodType t) => t switch
{
BloodType.APos => "A+",
BloodType.ANeg => "A-",
BloodType.BPos => "B+",
BloodType.BNeg => "B-",
BloodType.AbPos => "AB+",
BloodType.AbNeg => "AB-",
BloodType.OPos => "O+",
BloodType.ONeg => "O-",
_ => throw new ArgumentOutOfRangeException(nameof(t))
};
public static BloodType FromDbString(string v) => v switch
{
"A+" => BloodType.APos,
"A-" => BloodType.ANeg,
"B+" => BloodType.BPos,
"B-" => BloodType.BNeg,
"AB+" => BloodType.AbPos,
"AB-" => BloodType.AbNeg,
"O+" => BloodType.OPos,
"O-" => BloodType.ONeg,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown blood type: '{v}'")
};
public static bool TryFromDbString(string? v, out BloodType result)
{
if (v is null) { result = default; return false; }
try { result = FromDbString(v); return true; }
catch (ArgumentOutOfRangeException) { result = default; return false; }
}
}
@@ -0,0 +1,83 @@
public enum Department
{
EmergencyDepartment,
InternalMedicine,
GeneralMedicine,
Surgery,
Icu,
Nicu,
MedSurg,
OutpatientClinic,
Pediatrics,
ObstetricsGynecology,
LaborAndDelivery,
Cardiology,
Orthopedics,
Neurology,
Oncology,
Radiology,
Laboratory,
Psychiatry,
PhysicalTherapy,
Anesthesiology
}
public static class DepartmentExtensions
{
public static string ToDbString(this Department d) => d switch
{
Department.EmergencyDepartment => "Emergency Department",
Department.InternalMedicine => "Internal Medicine",
Department.GeneralMedicine => "General Medicine",
Department.Surgery => "Surgery",
Department.Icu => "ICU",
Department.Nicu => "NICU",
Department.MedSurg => "Medical-Surgical",
Department.OutpatientClinic => "Outpatient Clinic",
Department.Pediatrics => "Pediatrics",
Department.ObstetricsGynecology => "Obstetrics & Gynecology",
Department.LaborAndDelivery => "Labor & Delivery",
Department.Cardiology => "Cardiology",
Department.Orthopedics => "Orthopedics",
Department.Neurology => "Neurology",
Department.Oncology => "Oncology",
Department.Radiology => "Radiology",
Department.Laboratory => "Laboratory",
Department.Psychiatry => "Psychiatry",
Department.PhysicalTherapy => "Physical Therapy",
Department.Anesthesiology => "Anesthesiology",
_ => throw new ArgumentOutOfRangeException(nameof(d))
};
public static Department FromDbString(string v) => v switch
{
"Emergency Department" => Department.EmergencyDepartment,
"Internal Medicine" => Department.InternalMedicine,
"General Medicine" => Department.GeneralMedicine,
"Surgery" => Department.Surgery,
"ICU" => Department.Icu,
"NICU" => Department.Nicu,
"Medical-Surgical" => Department.MedSurg,
"Outpatient Clinic" => Department.OutpatientClinic,
"Pediatrics" => Department.Pediatrics,
"Obstetrics & Gynecology" => Department.ObstetricsGynecology,
"Labor & Delivery" => Department.LaborAndDelivery,
"Cardiology" => Department.Cardiology,
"Orthopedics" => Department.Orthopedics,
"Neurology" => Department.Neurology,
"Oncology" => Department.Oncology,
"Radiology" => Department.Radiology,
"Laboratory" => Department.Laboratory,
"Psychiatry" => Department.Psychiatry,
"Physical Therapy" => Department.PhysicalTherapy,
"Anesthesiology" => Department.Anesthesiology,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown department: '{v}'")
};
public static bool TryFromDbString(string? v, out Department result)
{
if (v is null) { result = default; return false; }
try { result = FromDbString(v); return true; }
catch (ArgumentOutOfRangeException) { result = default; return false; }
}
}
@@ -0,0 +1,73 @@
public enum DigitizationEventType
{
Uploaded,
EntryStarted,
SubmittedForVerification,
Rejected,
Verified,
VerifiedPendingClinical,
AwaitingClinicalApproval,
Approved,
Promoted,
LiveCaptureAttested,
CorrectionRequested,
VerificationFailed,
Superseded,
CorrectionPromoted,
CorrectionUploaded,
PromotionRetrySucceeded,
PromotionRetryFailed,
PromotionRetryExhausted,
PromotionFailed
}
public static class DigitizationEventTypeExtensions
{
public static string ToDbString(this DigitizationEventType t) => t switch
{
DigitizationEventType.Uploaded => "uploaded",
DigitizationEventType.EntryStarted => "entry_started",
DigitizationEventType.SubmittedForVerification => "submitted_for_verification",
DigitizationEventType.Rejected => "rejected",
DigitizationEventType.Verified => "verified",
DigitizationEventType.VerifiedPendingClinical => "verified_pending_clinical",
DigitizationEventType.AwaitingClinicalApproval => "awaiting_clinical_approval",
DigitizationEventType.Approved => "approved",
DigitizationEventType.Promoted => "promoted",
DigitizationEventType.LiveCaptureAttested => "live_capture_attested",
DigitizationEventType.CorrectionRequested => "correction_requested",
DigitizationEventType.VerificationFailed => "verification_failed",
DigitizationEventType.Superseded => "superseded",
DigitizationEventType.CorrectionPromoted => "correction_promoted",
DigitizationEventType.CorrectionUploaded => "correction_uploaded",
DigitizationEventType.PromotionRetrySucceeded => "promotion_retry_succeeded",
DigitizationEventType.PromotionRetryFailed => "promotion_retry_failed",
DigitizationEventType.PromotionRetryExhausted => "promotion_retry_exhausted",
DigitizationEventType.PromotionFailed => "promotion_failed",
_ => throw new ArgumentOutOfRangeException(nameof(t))
};
public static DigitizationEventType FromDbString(string v) => v switch
{
"uploaded" => DigitizationEventType.Uploaded,
"entry_started" => DigitizationEventType.EntryStarted,
"submitted_for_verification" => DigitizationEventType.SubmittedForVerification,
"rejected" => DigitizationEventType.Rejected,
"verified" => DigitizationEventType.Verified,
"verified_pending_clinical" => DigitizationEventType.VerifiedPendingClinical,
"awaiting_clinical_approval" => DigitizationEventType.AwaitingClinicalApproval,
"approved" => DigitizationEventType.Approved,
"promoted" => DigitizationEventType.Promoted,
"live_capture_attested" => DigitizationEventType.LiveCaptureAttested,
"correction_requested" => DigitizationEventType.CorrectionRequested,
"verification_failed" => DigitizationEventType.VerificationFailed,
"superseded" => DigitizationEventType.Superseded,
"correction_promoted" => DigitizationEventType.CorrectionPromoted,
"correction_uploaded" => DigitizationEventType.CorrectionUploaded,
"promotion_retry_succeeded" => DigitizationEventType.PromotionRetrySucceeded,
"promotion_retry_failed" => DigitizationEventType.PromotionRetryFailed,
"promotion_retry_exhausted" => DigitizationEventType.PromotionRetryExhausted,
"promotion_failed" => DigitizationEventType.PromotionFailed,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown digitization event type: '{v}'")
};
}
@@ -0,0 +1,26 @@
public enum UserRole { IntakeClerk, DataEntryClerk, Verifier, ClinicalApprover, Clinician, Administrator }
public static class UserRoleExtensions
{
public static string ToDbString(this UserRole r) => r switch
{
UserRole.IntakeClerk => "INTAKE_CLERK",
UserRole.DataEntryClerk => "DATA_ENTRY_CLERK",
UserRole.Verifier => "VERIFIER",
UserRole.ClinicalApprover => "CLINICAL_APPROVER",
UserRole.Clinician => "CLINICIAN",
UserRole.Administrator => "ADMINISTRATOR",
_ => throw new ArgumentOutOfRangeException(nameof(r))
};
public static UserRole FromDbString(string v) => v switch
{
"INTAKE_CLERK" => UserRole.IntakeClerk,
"DATA_ENTRY_CLERK" => UserRole.DataEntryClerk,
"VERIFIER" => UserRole.Verifier,
"CLINICAL_APPROVER" => UserRole.ClinicalApprover,
"CLINICIAN" => UserRole.Clinician,
"ADMINISTRATOR" => UserRole.Administrator,
_ => throw new ArgumentOutOfRangeException(nameof(v), $"Unknown user role: '{v}'")
};
}