diff --git a/backend/src/Health.Domain/Entities/support_entities.cs b/backend/src/Health.Domain/Entities/support_entities.cs
index 293e98b..45abfac 100644
--- a/backend/src/Health.Domain/Entities/support_entities.cs
+++ b/backend/src/Health.Domain/Entities/support_entities.cs
@@ -89,6 +89,10 @@ public sealed class NotificationPreference
public bool FollowUpReminder { get; set; } = true;
public bool DoctorReply { get; set; } = true;
public bool AbnormalAlert { get; set; } = true;
+ public bool PushEnabled { get; set; } = true;
+ public bool DndEnabled { get; set; }
+ public int DndStartMinutes { get; set; } = 22 * 60;
+ public int DndEndMinutes { get; set; } = 8 * 60;
// 健康录入提醒——总开关 + 5 子项
public bool HealthRecordReminder { get; set; } = true;
public bool HealthRecordReminderBloodPressure { get; set; } = true;
diff --git a/backend/src/Health.Infrastructure/Data/Migrations/20260713022401_AddPushAndDndPreferences.Designer.cs b/backend/src/Health.Infrastructure/Data/Migrations/20260713022401_AddPushAndDndPreferences.Designer.cs
new file mode 100644
index 0000000..e8c9162
--- /dev/null
+++ b/backend/src/Health.Infrastructure/Data/Migrations/20260713022401_AddPushAndDndPreferences.Designer.cs
@@ -0,0 +1,1473 @@
+//
+using System;
+using System.Collections.Generic;
+using Health.Infrastructure.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Health.Infrastructure.Data.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20260713022401_AddPushAndDndPreferences")]
+ partial class AddPushAndDndPreferences
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Health.Domain.Entities.Consultation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ClosedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DoctorId")
+ .HasColumnType("uuid");
+
+ b.Property("Month")
+ .HasColumnType("integer");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DoctorId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Consultations");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.ConsultationMessage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ConsultationId")
+ .HasColumnType("uuid");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("SenderName")
+ .HasColumnType("text");
+
+ b.Property("SenderType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ConsultationId", "CreatedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("ConsultationMessages");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.Conversation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AgentType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MessageCount")
+ .HasColumnType("integer");
+
+ b.Property("Summary")
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "UpdatedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("Conversations");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.ConversationMessage", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ConversationId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Intent")
+ .HasColumnType("text");
+
+ b.Property("MetadataJson")
+ .HasColumnType("jsonb");
+
+ b.Property("Role")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ConversationId", "CreatedAt");
+
+ b.ToTable("ConversationMessages");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.DeviceToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean");
+
+ b.Property("Platform")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("PushToken")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("DeviceTokens");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.DietFoodItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Calories")
+ .HasColumnType("integer");
+
+ b.Property("CarbsGrams")
+ .HasColumnType("numeric");
+
+ b.Property("DietRecordId")
+ .HasColumnType("uuid");
+
+ b.Property("FatGrams")
+ .HasColumnType("numeric");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Portion")
+ .HasColumnType("text");
+
+ b.Property("ProteinGrams")
+ .HasColumnType("numeric");
+
+ b.Property("SortOrder")
+ .HasColumnType("integer");
+
+ b.Property("Warning")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DietRecordId");
+
+ b.ToTable("DietFoodItems");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.DietRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("HealthScore")
+ .HasColumnType("integer");
+
+ b.Property("MealType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RecordedAt")
+ .HasColumnType("date");
+
+ b.Property("TotalCalories")
+ .HasColumnType("integer");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "RecordedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("DietRecords");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.Doctor", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AvatarUrl")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Department")
+ .HasColumnType("text");
+
+ b.Property("Introduction")
+ .HasColumnType("text");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Phone")
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("ProfessionalDirection")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("Title")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Doctors");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.DoctorProfile", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AvatarUrl")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Department")
+ .HasColumnType("text");
+
+ b.Property("DoctorId")
+ .HasColumnType("uuid");
+
+ b.Property("Hospital")
+ .HasColumnType("text");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean");
+
+ b.Property("IsOnline")
+ .HasColumnType("boolean");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DoctorId");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("DoctorProfiles");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.ExercisePlan", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("EndDate")
+ .HasColumnType("date");
+
+ b.Property("ReminderTime")
+ .HasColumnType("time without time zone");
+
+ b.Property("StartDate")
+ .HasColumnType("date");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "StartDate", "EndDate");
+
+ b.ToTable("ExercisePlans");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.ExercisePlanItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DurationMinutes")
+ .HasColumnType("integer");
+
+ b.Property("ExerciseType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsCompleted")
+ .HasColumnType("boolean");
+
+ b.Property("IsRestDay")
+ .HasColumnType("boolean");
+
+ b.Property("PlanId")
+ .HasColumnType("uuid");
+
+ b.Property("ScheduledDate")
+ .HasColumnType("date");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PlanId", "ScheduledDate")
+ .IsUnique();
+
+ b.ToTable("ExercisePlanItems");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.FollowUp", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Department")
+ .HasColumnType("text");
+
+ b.Property("DoctorName")
+ .HasColumnType("text");
+
+ b.Property("Notes")
+ .HasColumnType("text");
+
+ b.Property("ScheduledAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("FollowUps");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.HealthArchive", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.PrimitiveCollection>("Allergies")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.PrimitiveCollection>("ChronicDiseases")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.Property("Diagnosis")
+ .HasColumnType("text");
+
+ b.PrimitiveCollection>("DietRestrictions")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.Property("FamilyHistory")
+ .HasColumnType("text");
+
+ b.Property("SurgeryDate")
+ .HasColumnType("date");
+
+ b.Property("SurgeryType")
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("HealthArchives");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.HealthArchiveSurgery", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Date")
+ .HasColumnType("date");
+
+ b.Property("HealthArchiveId")
+ .HasColumnType("uuid");
+
+ b.Property("SortOrder")
+ .HasColumnType("integer");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("HealthArchiveId", "SortOrder");
+
+ b.ToTable("HealthArchiveSurgeries", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.HealthRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Diastolic")
+ .HasColumnType("integer");
+
+ b.Property("IsAbnormal")
+ .HasColumnType("boolean");
+
+ b.Property("MetricType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RecordedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Systolic")
+ .HasColumnType("integer");
+
+ b.Property("Unit")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.Property("Value")
+ .HasColumnType("numeric");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "MetricType");
+
+ b.HasIndex("UserId", "RecordedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("HealthRecords");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.Medication", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Dosage")
+ .HasColumnType("text");
+
+ b.Property("EndDate")
+ .HasColumnType("date");
+
+ b.Property("Frequency")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Notes")
+ .HasColumnType("text");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("StartDate")
+ .HasColumnType("date");
+
+ b.PrimitiveCollection>("TimeOfDay")
+ .IsRequired()
+ .HasColumnType("time[]");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "IsActive");
+
+ b.ToTable("Medications");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.MedicationLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ConfirmedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MedicationId")
+ .HasColumnType("uuid");
+
+ b.Property("ScheduledTime")
+ .HasColumnType("time without time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MedicationId", "CreatedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("MedicationLogs");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.NotificationPreference", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AbnormalAlert")
+ .HasColumnType("boolean");
+
+ b.Property("DndEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("DndEndMinutes")
+ .HasColumnType("integer");
+
+ b.Property("DndStartMinutes")
+ .HasColumnType("integer");
+
+ b.Property("DoctorReply")
+ .HasColumnType("boolean");
+
+ b.Property("FollowUpReminder")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminder")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminderBloodPressure")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminderGlucose")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminderHeartRate")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminderSpO2")
+ .HasColumnType("boolean");
+
+ b.Property("HealthRecordReminderWeight")
+ .HasColumnType("boolean");
+
+ b.Property("MedicationReminder")
+ .HasColumnType("boolean");
+
+ b.Property("PushEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("NotificationPreferences");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.RefreshToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsRevoked")
+ .HasColumnType("boolean");
+
+ b.Property("Token")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.ToTable("RefreshTokens");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.Report", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AiIndicators")
+ .HasColumnType("jsonb");
+
+ b.Property("AiSummary")
+ .HasColumnType("text");
+
+ b.Property("Category")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DoctorComment")
+ .HasColumnType("text");
+
+ b.Property("DoctorName")
+ .HasColumnType("text");
+
+ b.Property("DoctorRecommendation")
+ .HasColumnType("text");
+
+ b.Property("FileType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("FileUrl")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ReviewedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Severity")
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("Reports");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.User", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AvatarUrl")
+ .HasColumnType("text");
+
+ b.Property("BirthDate")
+ .HasColumnType("date");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DoctorId")
+ .HasColumnType("uuid");
+
+ b.Property("Gender")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Phone")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Role")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasDefaultValue("User");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DoctorId");
+
+ b.HasIndex("Phone")
+ .IsUnique();
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.UserNotification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ActionTargetId")
+ .HasColumnType("text");
+
+ b.Property("ActionType")
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean");
+
+ b.Property("IsRead")
+ .HasColumnType("boolean");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ReadAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Severity")
+ .IsRequired()
+ .HasMaxLength(16)
+ .HasColumnType("character varying(16)");
+
+ b.Property("SourceId")
+ .HasColumnType("uuid");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SourceId")
+ .IsUnique();
+
+ b.HasIndex("UserId", "IsDeleted", "IsRead", "CreatedAt");
+
+ b.ToTable("UserNotifications", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Domain.Entities.VerificationCode", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("IsUsed")
+ .HasColumnType("boolean");
+
+ b.Property("Phone")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Phone", "CreatedAt")
+ .IsDescending(false, true);
+
+ b.ToTable("VerificationCodes");
+ });
+
+ modelBuilder.Entity("Health.Infrastructure.Data.Records.AiWriteCommandRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Arguments")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpiresAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("ToolName")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId", "Status", "ExpiresAt");
+
+ b.ToTable("AiWriteCommands", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Infrastructure.Data.Records.DietImageAnalysisTaskRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Attempts")
+ .HasColumnType("integer");
+
+ b.Property("AvailableAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("FilePaths")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("LastError")
+ .HasColumnType("text");
+
+ b.Property("ResultCode")
+ .HasColumnType("integer");
+
+ b.Property("ResultData")
+ .HasColumnType("text");
+
+ b.Property("ResultMessage")
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Status", "AvailableAt");
+
+ b.ToTable("DietImageAnalysisTasks", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Infrastructure.Data.Records.MedicationReminderTaskRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Attempts")
+ .HasColumnType("integer");
+
+ b.Property("AvailableAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Dosage")
+ .HasColumnType("text");
+
+ b.Property("LastError")
+ .HasColumnType("text");
+
+ b.Property("MedicationId")
+ .HasColumnType("uuid");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ScheduledDate")
+ .HasColumnType("date");
+
+ b.Property("ScheduledTime")
+ .HasColumnType("time without time zone");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Status", "AvailableAt");
+
+ b.HasIndex("MedicationId", "ScheduledDate", "ScheduledTime")
+ .IsUnique();
+
+ b.ToTable("MedicationReminderTasks", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Infrastructure.Data.Records.NotificationOutboxRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Attempts")
+ .HasColumnType("integer");
+
+ b.Property("AvailableAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LastError")
+ .HasColumnType("text");
+
+ b.Property("Payload")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.Property("SourceTaskId")
+ .HasColumnType("uuid");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SourceTaskId")
+ .IsUnique();
+
+ b.HasIndex("Status", "AvailableAt");
+
+ b.ToTable("NotificationOutbox", (string)null);
+ });
+
+ modelBuilder.Entity("Health.Infrastructure.Data.Records.ReportAnalysisTaskRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property