feat(CUB-56): Agent State Database Migration

This commit is contained in:
cubecraft-agents[bot]
2026-04-26 10:18:06 +00:00
parent f490098af6
commit 7b7b070dac
15 changed files with 581 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
using ControlCenter.Api.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace ControlCenter.Api.Configurations;
/// <summary>
/// EF Core entity type configuration for the agents table.
/// Enforces snake_case naming, required fields, and index design.
/// </summary>
public class AgentConfiguration : IEntityTypeConfiguration<Agent>
{
public void Configure(EntityTypeBuilder<Agent> builder)
{
// Table name — snake_case
builder.ToTable("agents");
// Primary key
builder.HasKey(a => a.Id);
builder.Property(a => a.Id)
.HasColumnName("id")
.ValueGeneratedOnAdd();
// Status — stored as PostgreSQL enum via Npgsql
builder.Property(a => a.Status)
.HasColumnName("status")
.HasColumnType("agent_status")
.IsRequired();
// Task — nullable text
builder.Property(a => a.Task)
.HasColumnName("task")
.HasColumnType("text");
// Progress — nullable integer (0100)
builder.Property(a => a.Progress)
.HasColumnName("progress");
// Session key — required, not null
builder.Property(a => a.SessionKey)
.HasColumnName("session_key")
.HasColumnType("text")
.IsRequired();
// Channel — required, not null
builder.Property(a => a.Channel)
.HasColumnName("channel")
.HasColumnType("text")
.IsRequired();
// Last activity — required, defaults to now()
builder.Property(a => a.LastActivity)
.HasColumnName("last_activity")
.HasColumnType("timestamptz")
.IsRequired();
// Created at — auto-set on insert
builder.Property(a => a.CreatedAt)
.HasColumnName("created_at")
.HasColumnType("timestamptz")
.IsRequired()
.HasDefaultValueSql("now()");
// Updated at — auto-set on insert and update
builder.Property(a => a.UpdatedAt)
.HasColumnName("updated_at")
.HasColumnType("timestamptz")
.IsRequired()
.HasDefaultValueSql("now()");
// Indexes
// Sessions are looked up by session_key frequently
builder.HasIndex(a => a.SessionKey)
.HasDatabaseName("ix_agents_session_key")
.IsUnique();
// Agents are filtered by channel for channel-specific queries
builder.HasIndex(a => a.Channel)
.HasDatabaseName("ix_agents_channel");
// Agents are filtered by status for fleet health monitoring
builder.HasIndex(a => a.Status)
.HasDatabaseName("ix_agents_status");
// Check constraint: progress must be 0100 if present
builder.ToTable(t => t.HasCheckConstraint("ck_agents_progress_range", "progress IS NULL OR (progress >= 0 AND progress <= 100)"));
}
}