feat: 后端架构重构 — Endpoint→Service→Repository分层 + AI确认机制 + 异步任务持久化
- 核心业务拆分为 Endpoint → Application Service → Repository 三层 - AI写入操作必须用户确认后才写库(确认卡片机制) - 报告/饮食/用药分析改为持久化任务队列(原子领取/重试/重启恢复) - 运动计划修复: 连续真实日期替代周模板 - 用药提醒去重 + 通知Outbox预留 - 认证收拢到AuthService, 管理员收拢到AdminService - AI会话加用户归属校验防串号 - 提示词调整为患者视角 - 开发假数据已关闭 - 21/21测试通过, 0警告0错误
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Health.Infrastructure.Data.Records;
|
||||
|
||||
namespace Health.Infrastructure.Data;
|
||||
|
||||
@@ -33,6 +34,11 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbCon
|
||||
public DbSet<VerificationCode> VerificationCodes => Set<VerificationCode>();
|
||||
public DbSet<NotificationPreference> NotificationPreferences => Set<NotificationPreference>();
|
||||
public DbSet<DeviceToken> DeviceTokens => Set<DeviceToken>();
|
||||
public DbSet<AiWriteCommandRecord> AiWriteCommands => Set<AiWriteCommandRecord>();
|
||||
public DbSet<ReportAnalysisTaskRecord> ReportAnalysisTasks => Set<ReportAnalysisTaskRecord>();
|
||||
public DbSet<DietImageAnalysisTaskRecord> DietImageAnalysisTasks => Set<DietImageAnalysisTaskRecord>();
|
||||
public DbSet<MedicationReminderTaskRecord> MedicationReminderTasks => Set<MedicationReminderTaskRecord>();
|
||||
public DbSet<NotificationOutboxRecord> NotificationOutbox => Set<NotificationOutboxRecord>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
@@ -95,7 +101,12 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbCon
|
||||
// ---- ExercisePlan ----
|
||||
builder.Entity<ExercisePlan>(e =>
|
||||
{
|
||||
e.HasIndex(p => new { p.UserId, p.WeekStartDate }).IsDescending(false, true);
|
||||
e.HasIndex(p => new { p.UserId, p.StartDate, p.EndDate });
|
||||
});
|
||||
|
||||
builder.Entity<ExercisePlanItem>(e =>
|
||||
{
|
||||
e.HasIndex(i => new { i.PlanId, i.ScheduledDate }).IsUnique();
|
||||
});
|
||||
|
||||
// ---- Report ----
|
||||
@@ -148,5 +159,48 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbCon
|
||||
{
|
||||
e.HasIndex(a => a.UserId).IsUnique();
|
||||
});
|
||||
|
||||
builder.Entity<AiWriteCommandRecord>(e =>
|
||||
{
|
||||
e.ToTable("AiWriteCommands");
|
||||
e.HasIndex(x => new { x.UserId, x.Status, x.ExpiresAt });
|
||||
e.Property(x => x.ToolName).HasMaxLength(64);
|
||||
e.Property(x => x.Status).HasMaxLength(32);
|
||||
e.Property(x => x.Arguments).HasColumnType("jsonb");
|
||||
});
|
||||
|
||||
builder.Entity<ReportAnalysisTaskRecord>(e =>
|
||||
{
|
||||
e.ToTable("ReportAnalysisTasks");
|
||||
e.HasIndex(x => new { x.Status, x.AvailableAt });
|
||||
e.HasIndex(x => x.ReportId);
|
||||
e.Property(x => x.Status).HasMaxLength(32);
|
||||
});
|
||||
|
||||
builder.Entity<DietImageAnalysisTaskRecord>(e =>
|
||||
{
|
||||
e.ToTable("DietImageAnalysisTasks");
|
||||
e.HasIndex(x => new { x.Status, x.AvailableAt });
|
||||
e.Property(x => x.FilePaths).HasColumnType("jsonb");
|
||||
e.Property(x => x.Status).HasMaxLength(32);
|
||||
});
|
||||
|
||||
builder.Entity<MedicationReminderTaskRecord>(e =>
|
||||
{
|
||||
e.ToTable("MedicationReminderTasks");
|
||||
e.HasIndex(x => new { x.Status, x.AvailableAt });
|
||||
e.HasIndex(x => new { x.MedicationId, x.ScheduledDate, x.ScheduledTime }).IsUnique();
|
||||
e.Property(x => x.Status).HasMaxLength(32);
|
||||
});
|
||||
|
||||
builder.Entity<NotificationOutboxRecord>(e =>
|
||||
{
|
||||
e.ToTable("NotificationOutbox");
|
||||
e.HasIndex(x => x.SourceTaskId).IsUnique();
|
||||
e.HasIndex(x => new { x.Status, x.AvailableAt });
|
||||
e.Property(x => x.Type).HasMaxLength(64);
|
||||
e.Property(x => x.Status).HasMaxLength(32);
|
||||
e.Property(x => x.Payload).HasColumnType("jsonb");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user