fix(ci): close migration and toxiproxy gates
CI - Build & Test / Backend (.NET) (push) Successful in 50s
CI - Build & Test / Backend integration (PostgreSQL/Toxiproxy) (push) Failing after 56s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m50s
CI - Build & Test / Security Check (push) Successful in 6s
CI - Build & Test / Deploy Nexus (push) Has been skipped

This commit is contained in:
AzuTear
2026-08-01 01:38:06 +02:00
parent ce5555abc0
commit 3dac335767
7 changed files with 1072 additions and 45 deletions
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "10.0.8",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
+9
View File
@@ -35,6 +35,15 @@ jobs:
- name: Build - name: Build
run: dotnet build backend-tests/Nexus.Api.Tests.csproj --no-restore --configuration Release run: dotnet build backend-tests/Nexus.Api.Tests.csproj --no-restore --configuration Release
- name: Verify EF migration model
run: |
dotnet tool restore
dotnet tool run dotnet-ef migrations has-pending-model-changes \
--project backend/Nexus.Api.csproj \
--startup-project backend/Nexus.Api.csproj \
--configuration Release \
--no-build
- name: Block high or critical backend vulnerabilities - name: Block high or critical backend vulnerabilities
run: | run: |
dotnet list backend/Nexus.Api.csproj package --vulnerable --include-transitive --format json > /tmp/nexus-dotnet-vulnerabilities.json dotnet list backend/Nexus.Api.csproj package --vulnerable --include-transitive --format json > /tmp/nexus-dotnet-vulnerabilities.json
@@ -106,11 +106,11 @@ public sealed class ToxiproxyAgentProvisioningIntegrationTests
"/proxies/openclaw/toxics", "/proxies/openclaw/toxics",
new new
{ {
name = "drop-all-create-responses", name = "delay-create-response",
type = "timeout", type = "latency",
stream = "downstream", stream = "downstream",
toxicity = 1.0, toxicity = 1.0,
attributes = new { timeout = 0 } attributes = new { latency = 1500, jitter = 0 }
}, },
cancellationToken); cancellationToken);
toxicResponse.EnsureSuccessStatusCode(); toxicResponse.EnsureSuccessStatusCode();
@@ -125,7 +125,7 @@ public sealed class ToxiproxyAgentProvisioningIntegrationTests
Assert.Equal(1, gateway.CreateCalls); Assert.Equal(1, gateway.CreateCalls);
using (var removeToxic = await toxiproxyAdmin.DeleteAsync( using (var removeToxic = await toxiproxyAdmin.DeleteAsync(
"/proxies/openclaw/toxics/drop-all-create-responses")) "/proxies/openclaw/toxics/delay-create-response"))
{ {
removeToxic.EnsureSuccessStatusCode(); removeToxic.EnsureSuccessStatusCode();
} }
@@ -200,7 +200,7 @@ public sealed class ToxiproxyAgentProvisioningIntegrationTests
# The mutation is committed before the response. Toxiproxy # The mutation is committed before the response. Toxiproxy
# blocks downstream bytes, recreating an uncertain dispatch. # blocks downstream bytes, recreating an uncertain dispatch.
time.sleep(1.5) time.sleep(0.1)
self.send_json(200, { self.send_json(200, {
"ok": True, "ok": True,
"agentId": agent_id, "agentId": agent_id,
@@ -0,0 +1,977 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Nexus.Api.Data;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Nexus.Api.Migrations
{
[DbContext(typeof(NexusDbContext))]
[Migration("20260731233006_RemoveRedundantTaskParentIndex")]
partial class RemoveRedundantTaskParentIndex
{
/// <inheritdoc />
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("Nexus.Api.Data.ActivityEvent", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Message")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<Guid?>("TaskId")
.HasColumnType("uuid");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CreatedAt");
b.HasIndex("TaskId");
b.HasIndex("TaskId", "CreatedAt", "Id")
.IsDescending(false, true, true)
.HasDatabaseName("IX_Activity_TaskId_CreatedAt_Id")
.HasFilter("\"TaskId\" IS NOT NULL");
b.ToTable("Activity");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProposal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset?>("ApprovedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ApprovedBy")
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("Avatar")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<DateTimeOffset?>("CompletedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasMaxLength(4000)
.HasColumnType("character varying(4000)");
b.Property<string>("Emoji")
.HasMaxLength(32)
.HasColumnType("character varying(32)");
b.Property<string>("LastErrorCode")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<string>("LastErrorMessage")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<string>("Model")
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("OpenClawAgentId")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("OpenClawWorkspace")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<DateTimeOffset?>("RejectedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("RejectedBy")
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("RejectionReason")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("RequestedAgentId")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("RequestedBy")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("RequestedName")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("character varying(80)");
b.Property<int>("Revision")
.IsConcurrencyToken()
.HasColumnType("integer");
b.Property<string>("Role")
.HasMaxLength(160)
.HasColumnType("character varying(160)");
b.Property<string>("Source")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("StandardFilesHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("StandardFilesJson")
.IsRequired()
.HasColumnType("jsonb");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Workspace")
.IsRequired()
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.HasKey("Id");
b.HasIndex("OpenClawAgentId");
b.HasIndex("RequestedAgentId");
b.HasIndex("Status", "UpdatedAt");
b.ToTable("AgentProposals");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProvisionRequest", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Actor")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<int>("Attempt")
.HasColumnType("integer");
b.Property<DateTimeOffset?>("CompletedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("CorrelationId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("DispatchStartedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("IdempotencyKeyHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("LastErrorCode")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<string>("LastErrorMessage")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<string>("LeaseOwner")
.HasMaxLength(160)
.HasColumnType("character varying(160)");
b.Property<DateTimeOffset?>("LeaseUntil")
.HasColumnType("timestamp with time zone");
b.Property<string>("OpenClawAgentId")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<Guid>("ProposalId")
.HasColumnType("uuid");
b.Property<int>("Revision")
.IsConcurrencyToken()
.HasColumnType("integer");
b.Property<string>("Stage")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("TraceParent")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("LeaseUntil");
b.HasIndex("ProposalId", "Attempt")
.IsUnique();
b.HasIndex("Status", "CreatedAt");
b.ToTable("AgentProvisionRequests");
});
modelBuilder.Entity("Nexus.Api.Data.NexusUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<DateTimeOffset?>("LastLoginAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Role")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Nexus.Api.Data.Notification", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ForUser")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<bool>("IsRead")
.HasColumnType("boolean");
b.Property<string>("Message")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<Guid?>("TaskId")
.HasColumnType("uuid");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.HasKey("Id");
b.HasIndex("ForUser", "IsRead", "CreatedAt");
b.ToTable("Notifications");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawConnectionProfile", b =>
{
b.Property<string>("ProfileId")
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<DateTimeOffset?>("AdoptedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("AdoptionState")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("CapabilityHash")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("DeviceId")
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("DiscoverySource")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("character varying(80)");
b.Property<string>("Endpoint")
.IsRequired()
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<DateTimeOffset?>("LastProbedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("LastVerifiedAt")
.HasColumnType("timestamp with time zone");
b.Property<bool>("ManagementEnabled")
.HasColumnType("boolean");
b.Property<string>("RequiredVersion")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<int>("Revision")
.IsConcurrencyToken()
.HasColumnType("integer");
b.Property<string>("TlsCertificateFingerprint")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("ProfileId");
b.ToTable("OpenClawConnectionProfiles", null, t =>
{
t.HasCheckConstraint("CK_OpenClawConnectionProfiles_Primary", "\"ProfileId\" = 'primary'");
});
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Actor")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("AgentId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("CorrelationId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("FinishedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("LastError")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<long?>("LastGatewaySequence")
.HasColumnType("bigint");
b.Property<string>("OpenClawRunId")
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<Guid?>("ProjectId")
.HasColumnType("uuid");
b.Property<string>("Prompt")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("RetriedFromRunId")
.HasColumnType("uuid");
b.Property<int>("Revision")
.IsConcurrencyToken()
.HasColumnType("integer");
b.Property<bool>("SequenceGapDetected")
.HasColumnType("boolean");
b.Property<string>("SessionKey")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("StartIdempotencyKey")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<DateTimeOffset?>("StartedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<Guid?>("TaskId")
.HasColumnType("uuid");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(160)
.HasColumnType("character varying(160)");
b.Property<string>("TraceParent")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("OpenClawRunId")
.IsUnique();
b.HasIndex("ProjectId");
b.HasIndex("RetriedFromRunId");
b.HasIndex("SessionKey");
b.HasIndex("StartIdempotencyKey")
.IsUnique();
b.HasIndex("TaskId");
b.HasIndex("Status", "UpdatedAt");
b.ToTable("OpenClawRuns");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRunHistory", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("Action")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("character varying(80)");
b.Property<string>("Actor")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<string>("CorrelationId")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("FromStatus")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("GatewayEventId")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<long?>("GatewaySequence")
.HasColumnType("bigint");
b.Property<string>("IdempotencyKey")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Message")
.IsRequired()
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<DateTimeOffset>("OccurredAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid?>("ResultRunId")
.HasColumnType("uuid");
b.Property<Guid>("RunId")
.HasColumnType("uuid");
b.Property<bool>("SequenceGapDetected")
.HasColumnType("boolean");
b.Property<string>("ToStatus")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.Property<string>("TraceParent")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.HasKey("Id");
b.HasIndex("GatewayEventId")
.IsUnique();
b.HasIndex("RunId", "OccurredAt");
b.HasIndex("RunId", "Action", "IdempotencyKey")
.IsUnique();
b.ToTable("OpenClawRunHistory");
});
modelBuilder.Entity("Nexus.Api.Data.OperationClaim", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTimeOffset?>("CompletedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset>("ExpiresAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("IdempotencyKeyHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("Operation")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("RequestHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<Guid?>("ResourceId")
.HasColumnType("uuid");
b.Property<string>("ResultCode")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<string>("State")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("character varying(40)");
b.HasKey("Id");
b.HasIndex("ExpiresAt");
b.HasIndex("Operation", "IdempotencyKeyHash")
.IsUnique();
b.ToTable("OperationClaims");
});
modelBuilder.Entity("Nexus.Api.Data.OutboxEvent", b =>
{
b.Property<long>("Sequence")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Sequence"));
b.Property<string>("AggregateId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<int>("AggregateRevision")
.HasColumnType("integer");
b.Property<string>("AggregateType")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("character varying(80)");
b.Property<Guid>("EventId")
.HasColumnType("uuid");
b.Property<string>("LastErrorCode")
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.Property<DateTimeOffset>("OccurredAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("PayloadJson")
.IsRequired()
.HasColumnType("jsonb");
b.Property<int>("PublishAttempts")
.HasColumnType("integer");
b.Property<DateTimeOffset?>("PublishedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(120)
.HasColumnType("character varying(120)");
b.HasKey("Sequence");
b.HasIndex("EventId")
.IsUnique();
b.HasIndex("OccurredAt");
b.HasIndex("PublishedAt", "Sequence");
b.ToTable("OutboxEvents");
});
modelBuilder.Entity("Nexus.Api.Data.Project", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(160)
.HasColumnType("character varying(160)");
b.Property<int>("Progress")
.HasColumnType("integer");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.ToTable("Projects");
});
modelBuilder.Entity("Nexus.Api.Data.RefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("uuid");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset>("ExpiresAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("FamilyId")
.HasColumnType("uuid");
b.Property<string>("ReplacedByTokenHash")
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<DateTimeOffset?>("RevokedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("TokenHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("TokenHash")
.IsUnique();
b.HasIndex("UserId", "FamilyId");
b.ToTable("RefreshTokens");
});
modelBuilder.Entity("Nexus.Api.Data.SeedAudit", b =>
{
b.Property<string>("Key")
.HasMaxLength(80)
.HasColumnType("character varying(80)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Key");
b.ToTable("SeedAudit");
});
modelBuilder.Entity("Nexus.Api.Data.WorkTask", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AssignedTo")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Detail")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<DateTimeOffset?>("DueDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("ExpectedFrom")
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<bool>("IsAgentTask")
.HasColumnType("boolean");
b.Property<Guid?>("ParentTaskId")
.HasColumnType("uuid");
b.Property<string>("Priority")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("ProjectId")
.HasColumnType("uuid");
b.Property<string>("Source")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("character varying(60)");
b.Property<string>("State")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(240)
.HasColumnType("character varying(240)");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("AssignedTo");
b.HasIndex("ExpectedFrom");
b.HasIndex("IsAgentTask");
b.HasIndex("Source");
b.HasIndex("ParentTaskId", "State")
.HasDatabaseName("IX_Tasks_ParentTaskId_State")
.HasFilter("\"ParentTaskId\" IS NOT NULL");
b.HasIndex("UpdatedAt", "Id")
.IsDescending()
.HasDatabaseName("IX_Tasks_Done_UpdatedAt_Id")
.HasFilter("\"State\" = 'Done'");
b.HasIndex("State", "UpdatedAt", "Id")
.IsDescending(false, true, false)
.HasDatabaseName("IX_Tasks_State_UpdatedAt_Id_Board");
b.HasIndex("ExpectedFrom", "State", "UpdatedAt", "Id")
.IsDescending(false, false, true, false)
.HasDatabaseName("IX_Tasks_AgentWorkflow")
.HasFilter("\"IsAgentTask\" = TRUE");
b.ToTable("Tasks");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProvisionRequest", b =>
{
b.HasOne("Nexus.Api.Data.AgentProposal", "Proposal")
.WithMany("ProvisionRequests")
.HasForeignKey("ProposalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Proposal");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b =>
{
b.HasOne("Nexus.Api.Data.Project", null)
.WithMany()
.HasForeignKey("ProjectId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Nexus.Api.Data.WorkTask", null)
.WithMany()
.HasForeignKey("TaskId")
.OnDelete(DeleteBehavior.SetNull);
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRunHistory", b =>
{
b.HasOne("Nexus.Api.Data.OpenClawRun", "Run")
.WithMany("History")
.HasForeignKey("RunId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Run");
});
modelBuilder.Entity("Nexus.Api.Data.RefreshToken", b =>
{
b.HasOne("Nexus.Api.Data.NexusUser", "User")
.WithMany("RefreshTokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Nexus.Api.Data.WorkTask", b =>
{
b.HasOne("Nexus.Api.Data.WorkTask", "ParentTask")
.WithMany("ChildTasks")
.HasForeignKey("ParentTaskId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("ParentTask");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProposal", b =>
{
b.Navigation("ProvisionRequests");
});
modelBuilder.Entity("Nexus.Api.Data.NexusUser", b =>
{
b.Navigation("RefreshTokens");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b =>
{
b.Navigation("History");
});
modelBuilder.Entity("Nexus.Api.Data.WorkTask", b =>
{
b.Navigation("ChildTasks");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Nexus.Api.Migrations
{
/// <inheritdoc />
public partial class RemoveRedundantTaskParentIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Tasks_ParentTaskId",
table: "Tasks");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_Tasks_ParentTaskId",
table: "Tasks",
column: "ParentTaskId");
}
}
}
@@ -65,13 +65,13 @@ namespace Nexus.Api.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<DateTimeOffset?>("ApprovedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("ApprovedBy") b.Property<string>("ApprovedBy")
.HasMaxLength(240) .HasMaxLength(240)
.HasColumnType("character varying(240)"); .HasColumnType("character varying(240)");
b.Property<DateTimeOffset?>("ApprovedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Avatar") b.Property<string>("Avatar")
.HasMaxLength(2048) .HasMaxLength(2048)
.HasColumnType("character varying(2048)"); .HasColumnType("character varying(2048)");
@@ -110,13 +110,13 @@ namespace Nexus.Api.Migrations
.HasMaxLength(2048) .HasMaxLength(2048)
.HasColumnType("character varying(2048)"); .HasColumnType("character varying(2048)");
b.Property<DateTimeOffset?>("RejectedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("RejectedBy") b.Property<string>("RejectedBy")
.HasMaxLength(240) .HasMaxLength(240)
.HasColumnType("character varying(240)"); .HasColumnType("character varying(240)");
b.Property<DateTimeOffset?>("RejectedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("RejectionReason") b.Property<string>("RejectionReason")
.HasMaxLength(1000) .HasMaxLength(1000)
.HasColumnType("character varying(1000)"); .HasColumnType("character varying(1000)");
@@ -698,12 +698,12 @@ namespace Nexus.Api.Migrations
.IsRequired() .IsRequired()
.HasColumnType("jsonb"); .HasColumnType("jsonb");
b.Property<DateTimeOffset?>("PublishedAt")
.HasColumnType("timestamp with time zone");
b.Property<int>("PublishAttempts") b.Property<int>("PublishAttempts")
.HasColumnType("integer"); .HasColumnType("integer");
b.Property<DateTimeOffset?>("PublishedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Type") b.Property<string>("Type")
.IsRequired() .IsRequired()
.HasMaxLength(120) .HasMaxLength(120)
@@ -870,31 +870,40 @@ namespace Nexus.Api.Migrations
b.HasIndex("IsAgentTask"); b.HasIndex("IsAgentTask");
b.HasIndex("ParentTaskId");
b.HasIndex("Source"); b.HasIndex("Source");
b.HasIndex("ParentTaskId", "State")
.HasDatabaseName("IX_Tasks_ParentTaskId_State")
.HasFilter("\"ParentTaskId\" IS NOT NULL");
b.HasIndex("UpdatedAt", "Id")
.IsDescending()
.HasDatabaseName("IX_Tasks_Done_UpdatedAt_Id")
.HasFilter("\"State\" = 'Done'");
b.HasIndex("State", "UpdatedAt", "Id")
.IsDescending(false, true, false)
.HasDatabaseName("IX_Tasks_State_UpdatedAt_Id_Board");
b.HasIndex("ExpectedFrom", "State", "UpdatedAt", "Id") b.HasIndex("ExpectedFrom", "State", "UpdatedAt", "Id")
.IsDescending(false, false, true, false) .IsDescending(false, false, true, false)
.HasDatabaseName("IX_Tasks_AgentWorkflow") .HasDatabaseName("IX_Tasks_AgentWorkflow")
.HasFilter("\"IsAgentTask\" = TRUE"); .HasFilter("\"IsAgentTask\" = TRUE");
b.HasIndex("ParentTaskId", "State")
.HasDatabaseName("IX_Tasks_ParentTaskId_State")
.HasFilter("\"ParentTaskId\" IS NOT NULL");
b.HasIndex("State", "UpdatedAt", "Id")
.IsDescending(false, true, false)
.HasDatabaseName("IX_Tasks_State_UpdatedAt_Id_Board");
b.HasIndex("UpdatedAt", "Id")
.IsDescending(true, true)
.HasDatabaseName("IX_Tasks_Done_UpdatedAt_Id")
.HasFilter("\"State\" = 'Done'");
b.ToTable("Tasks"); b.ToTable("Tasks");
}); });
modelBuilder.Entity("Nexus.Api.Data.AgentProvisionRequest", b =>
{
b.HasOne("Nexus.Api.Data.AgentProposal", "Proposal")
.WithMany("ProvisionRequests")
.HasForeignKey("ProposalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Proposal");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b => modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b =>
{ {
b.HasOne("Nexus.Api.Data.Project", null) b.HasOne("Nexus.Api.Data.Project", null)
@@ -940,27 +949,16 @@ namespace Nexus.Api.Migrations
b.Navigation("ParentTask"); b.Navigation("ParentTask");
}); });
modelBuilder.Entity("Nexus.Api.Data.NexusUser", b =>
{
b.Navigation("RefreshTokens");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProvisionRequest", b =>
{
b.HasOne("Nexus.Api.Data.AgentProposal", "Proposal")
.WithMany("ProvisionRequests")
.HasForeignKey("ProposalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Proposal");
});
modelBuilder.Entity("Nexus.Api.Data.AgentProposal", b => modelBuilder.Entity("Nexus.Api.Data.AgentProposal", b =>
{ {
b.Navigation("ProvisionRequests"); b.Navigation("ProvisionRequests");
}); });
modelBuilder.Entity("Nexus.Api.Data.NexusUser", b =>
{
b.Navigation("RefreshTokens");
});
modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b => modelBuilder.Entity("Nexus.Api.Data.OpenClawRun", b =>
{ {
b.Navigation("History"); b.Navigation("History");
+3
View File
@@ -1,5 +1,6 @@
using Nexus.Api.Extensions; using Nexus.Api.Extensions;
using Nexus.Api.Http; using Nexus.Api.Http;
using Microsoft.AspNetCore.DataProtection;
using System.Reflection; using System.Reflection;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@@ -11,6 +12,8 @@ if (isOpenApiGeneration)
// auth services, so use an ephemeral contract-only signing value. // auth services, so use an ephemeral contract-only signing value.
builder.Configuration["Jwt:Key"] = builder.Configuration["Jwt:Key"] =
"openapi-contract-generation-only-000000000000000000"; "openapi-contract-generation-only-000000000000000000";
builder.Services.AddDataProtection()
.UseEphemeralDataProtectionProvider();
} }
// --- Service Registration --- // --- Service Registration ---