diff --git a/Backend/src/NexusRMM.Api/NexusRMM.Api.csproj b/Backend/src/NexusRMM.Api/NexusRMM.Api.csproj
index 04244d5..b2863d4 100644
--- a/Backend/src/NexusRMM.Api/NexusRMM.Api.csproj
+++ b/Backend/src/NexusRMM.Api/NexusRMM.Api.csproj
@@ -18,6 +18,7 @@
+
diff --git a/Backend/src/NexusRMM.Api/appsettings.json b/Backend/src/NexusRMM.Api/appsettings.json
index b0f7a70..9720bbd 100644
--- a/Backend/src/NexusRMM.Api/appsettings.json
+++ b/Backend/src/NexusRMM.Api/appsettings.json
@@ -1,6 +1,6 @@
{
"ConnectionStrings": {
- "DefaultConnection": "Host=localhost;Port=5432;Database=nexusrmm;Username=nexusrmm;Password=nexusrmm_dev"
+ "DefaultConnection": "Host=localhost;Port=5433;Database=nexusrmm;Username=nexusrmm;Password=nexusrmm_dev"
},
"Cors": {
"Origins": ["http://localhost:5173"]
diff --git a/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.Designer.cs b/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.Designer.cs
new file mode 100644
index 0000000..1f986f4
--- /dev/null
+++ b/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.Designer.cs
@@ -0,0 +1,321 @@
+//
+using System;
+using System.Text.Json;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using NexusRMM.Infrastructure.Data;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NexusRMM.Infrastructure.Migrations
+{
+ [DbContext(typeof(RmmDbContext))]
+ [Migration("20260319104027_InitialCreate")]
+ partial class InitialCreate
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.5")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Agent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AgentVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EnrolledAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Hostname")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IpAddress")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastSeen")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MacAddress")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("MeshAgentId")
+ .HasColumnType("text");
+
+ b.Property("OsType")
+ .HasColumnType("integer");
+
+ b.Property("OsVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.PrimitiveCollection("Tags")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Hostname");
+
+ b.HasIndex("MacAddress");
+
+ b.ToTable("Agents");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AgentMetric", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("Metrics")
+ .HasColumnType("jsonb");
+
+ b.Property("Timestamp")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.HasIndex("Timestamp");
+
+ b.ToTable("AgentMetrics");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Alert", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Acknowledged")
+ .HasColumnType("boolean");
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RuleId")
+ .HasColumnType("integer");
+
+ b.Property("Severity")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("RuleId");
+
+ b.ToTable("Alerts");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AlertRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Enabled")
+ .HasColumnType("boolean");
+
+ b.Property("MetricPath")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Operator")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Severity")
+ .HasColumnType("integer");
+
+ b.Property("Threshold")
+ .HasColumnType("double precision");
+
+ b.HasKey("Id");
+
+ b.ToTable("AlertRules");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.TaskItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Payload")
+ .HasColumnType("jsonb");
+
+ b.Property("Result")
+ .HasColumnType("jsonb");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.ToTable("Tasks");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Ticket", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Priority")
+ .HasColumnType("integer");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.ToTable("Tickets");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AgentMetric", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Metrics")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Alert", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Alerts")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("NexusRMM.Core.Models.AlertRule", "Rule")
+ .WithMany("Alerts")
+ .HasForeignKey("RuleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+
+ b.Navigation("Rule");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.TaskItem", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Tasks")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Ticket", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Tickets")
+ .HasForeignKey("AgentId");
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Agent", b =>
+ {
+ b.Navigation("Alerts");
+
+ b.Navigation("Metrics");
+
+ b.Navigation("Tasks");
+
+ b.Navigation("Tickets");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AlertRule", b =>
+ {
+ b.Navigation("Alerts");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.cs b/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.cs
new file mode 100644
index 0000000..75f296b
--- /dev/null
+++ b/Backend/src/NexusRMM.Infrastructure/Migrations/20260319104027_InitialCreate.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Text.Json;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NexusRMM.Infrastructure.Migrations
+{
+ ///
+ public partial class InitialCreate : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "Agents",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ Hostname = table.Column(type: "text", nullable: false),
+ OsType = table.Column(type: "integer", nullable: false),
+ OsVersion = table.Column(type: "text", nullable: false),
+ IpAddress = table.Column(type: "text", nullable: false),
+ MacAddress = table.Column(type: "text", nullable: false),
+ AgentVersion = table.Column(type: "text", nullable: false),
+ Status = table.Column(type: "integer", nullable: false),
+ Tags = table.Column(type: "jsonb", nullable: false),
+ LastSeen = table.Column(type: "timestamp with time zone", nullable: false),
+ EnrolledAt = table.Column(type: "timestamp with time zone", nullable: false),
+ MeshAgentId = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Agents", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AlertRules",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Name = table.Column(type: "text", nullable: false),
+ MetricPath = table.Column(type: "text", nullable: false),
+ Operator = table.Column(type: "text", nullable: false),
+ Threshold = table.Column(type: "double precision", nullable: false),
+ Severity = table.Column(type: "integer", nullable: false),
+ Enabled = table.Column(type: "boolean", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AlertRules", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AgentMetrics",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ AgentId = table.Column(type: "uuid", nullable: false),
+ Timestamp = table.Column(type: "timestamp with time zone", nullable: false),
+ Metrics = table.Column(type: "jsonb", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AgentMetrics", x => x.Id);
+ table.ForeignKey(
+ name: "FK_AgentMetrics_Agents_AgentId",
+ column: x => x.AgentId,
+ principalTable: "Agents",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Tasks",
+ columns: table => new
+ {
+ Id = table.Column(type: "uuid", nullable: false),
+ AgentId = table.Column(type: "uuid", nullable: false),
+ Type = table.Column(type: "integer", nullable: false),
+ Payload = table.Column(type: "jsonb", nullable: true),
+ Status = table.Column(type: "integer", nullable: false),
+ Result = table.Column(type: "jsonb", nullable: true),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ CompletedAt = table.Column(type: "timestamp with time zone", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Tasks", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Tasks_Agents_AgentId",
+ column: x => x.AgentId,
+ principalTable: "Agents",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Tickets",
+ columns: table => new
+ {
+ Id = table.Column(type: "integer", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ Title = table.Column(type: "text", nullable: false),
+ Description = table.Column(type: "text", nullable: false),
+ Status = table.Column(type: "integer", nullable: false),
+ Priority = table.Column(type: "integer", nullable: false),
+ AgentId = table.Column(type: "uuid", nullable: true),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false),
+ UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Tickets", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Tickets_Agents_AgentId",
+ column: x => x.AgentId,
+ principalTable: "Agents",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "Alerts",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+ RuleId = table.Column(type: "integer", nullable: false),
+ AgentId = table.Column(type: "uuid", nullable: false),
+ Message = table.Column(type: "text", nullable: false),
+ Severity = table.Column(type: "integer", nullable: false),
+ Acknowledged = table.Column(type: "boolean", nullable: false),
+ CreatedAt = table.Column(type: "timestamp with time zone", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Alerts", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Alerts_Agents_AgentId",
+ column: x => x.AgentId,
+ principalTable: "Agents",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_Alerts_AlertRules_RuleId",
+ column: x => x.RuleId,
+ principalTable: "AlertRules",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AgentMetrics_AgentId",
+ table: "AgentMetrics",
+ column: "AgentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_AgentMetrics_Timestamp",
+ table: "AgentMetrics",
+ column: "Timestamp");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Agents_Hostname",
+ table: "Agents",
+ column: "Hostname");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Agents_MacAddress",
+ table: "Agents",
+ column: "MacAddress");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Alerts_AgentId",
+ table: "Alerts",
+ column: "AgentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Alerts_CreatedAt",
+ table: "Alerts",
+ column: "CreatedAt");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Alerts_RuleId",
+ table: "Alerts",
+ column: "RuleId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Tasks_AgentId",
+ table: "Tasks",
+ column: "AgentId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Tickets_AgentId",
+ table: "Tickets",
+ column: "AgentId");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "AgentMetrics");
+
+ migrationBuilder.DropTable(
+ name: "Alerts");
+
+ migrationBuilder.DropTable(
+ name: "Tasks");
+
+ migrationBuilder.DropTable(
+ name: "Tickets");
+
+ migrationBuilder.DropTable(
+ name: "AlertRules");
+
+ migrationBuilder.DropTable(
+ name: "Agents");
+ }
+ }
+}
diff --git a/Backend/src/NexusRMM.Infrastructure/Migrations/RmmDbContextModelSnapshot.cs b/Backend/src/NexusRMM.Infrastructure/Migrations/RmmDbContextModelSnapshot.cs
new file mode 100644
index 0000000..ac19005
--- /dev/null
+++ b/Backend/src/NexusRMM.Infrastructure/Migrations/RmmDbContextModelSnapshot.cs
@@ -0,0 +1,318 @@
+//
+using System;
+using System.Text.Json;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using NexusRMM.Infrastructure.Data;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NexusRMM.Infrastructure.Migrations
+{
+ [DbContext(typeof(RmmDbContext))]
+ partial class RmmDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.5")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Agent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AgentVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EnrolledAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Hostname")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("IpAddress")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("LastSeen")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MacAddress")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("MeshAgentId")
+ .HasColumnType("text");
+
+ b.Property("OsType")
+ .HasColumnType("integer");
+
+ b.Property("OsVersion")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.PrimitiveCollection("Tags")
+ .IsRequired()
+ .HasColumnType("jsonb");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Hostname");
+
+ b.HasIndex("MacAddress");
+
+ b.ToTable("Agents");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AgentMetric", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("Metrics")
+ .HasColumnType("jsonb");
+
+ b.Property("Timestamp")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.HasIndex("Timestamp");
+
+ b.ToTable("AgentMetrics");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Alert", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Acknowledged")
+ .HasColumnType("boolean");
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Message")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("RuleId")
+ .HasColumnType("integer");
+
+ b.Property("Severity")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.HasIndex("CreatedAt");
+
+ b.HasIndex("RuleId");
+
+ b.ToTable("Alerts");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AlertRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Enabled")
+ .HasColumnType("boolean");
+
+ b.Property("MetricPath")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Operator")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Severity")
+ .HasColumnType("integer");
+
+ b.Property("Threshold")
+ .HasColumnType("double precision");
+
+ b.HasKey("Id");
+
+ b.ToTable("AlertRules");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.TaskItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Payload")
+ .HasColumnType("jsonb");
+
+ b.Property("Result")
+ .HasColumnType("jsonb");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.ToTable("Tasks");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Ticket", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AgentId")
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Priority")
+ .HasColumnType("integer");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AgentId");
+
+ b.ToTable("Tickets");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AgentMetric", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Metrics")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Alert", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Alerts")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("NexusRMM.Core.Models.AlertRule", "Rule")
+ .WithMany("Alerts")
+ .HasForeignKey("RuleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+
+ b.Navigation("Rule");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.TaskItem", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Tasks")
+ .HasForeignKey("AgentId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Ticket", b =>
+ {
+ b.HasOne("NexusRMM.Core.Models.Agent", "Agent")
+ .WithMany("Tickets")
+ .HasForeignKey("AgentId");
+
+ b.Navigation("Agent");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.Agent", b =>
+ {
+ b.Navigation("Alerts");
+
+ b.Navigation("Metrics");
+
+ b.Navigation("Tasks");
+
+ b.Navigation("Tickets");
+ });
+
+ modelBuilder.Entity("NexusRMM.Core.Models.AlertRule", b =>
+ {
+ b.Navigation("Alerts");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..29c8b61
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+services:
+ nexusrmm-postgres:
+ image: postgres:17
+ container_name: nexusrmm-postgres
+ environment:
+ POSTGRES_DB: nexusrmm
+ POSTGRES_USER: nexusrmm
+ POSTGRES_PASSWORD: nexusrmm_dev
+ ports:
+ - "5433:5432"
+ volumes:
+ - nexusrmm_pgdata:/var/lib/postgresql/data
+ restart: unless-stopped
+
+volumes:
+ nexusrmm_pgdata:
+ name: nexusrmm_pgdata