feat: add feedback backend foundation

This commit is contained in:
2026-04-30 03:31:42 -04:00
parent f9960b4fc9
commit cb6948aa14
27 changed files with 3428 additions and 25 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Socialize.Api.Migrations
{
/// <inheritdoc />
public partial class AddFeedbackFoundation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "FeedbackReports",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
Status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
Description = table.Column<string>(type: "character varying(8000)", maxLength: 8000, nullable: false),
ReporterUserId = table.Column<Guid>(type: "uuid", nullable: false),
ReporterDisplayName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
ReporterEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
SubmittedPath = table.Column<string>(type: "character varying(2048)", maxLength: 2048, nullable: false),
BrowserUserAgent = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
ViewportWidth = table.Column<int>(type: "integer", nullable: true),
ViewportHeight = table.Column<int>(type: "integer", nullable: true),
AppVersion = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
WorkspaceId = table.Column<Guid>(type: "uuid", nullable: true),
WorkspaceName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ClientId = table.Column<Guid>(type: "uuid", nullable: true),
ClientName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ProjectId = table.Column<Guid>(type: "uuid", nullable: true),
ProjectName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
ContentItemId = table.Column<Guid>(type: "uuid", nullable: true),
ContentItemTitle = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "CURRENT_TIMESTAMP"),
LastActivityAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
CancelledAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
CancelledByUserId = table.Column<Guid>(type: "uuid", nullable: true),
CancellationReason = table.Column<string>(type: "character varying(2000)", maxLength: 2000, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_FeedbackReports", x => x.Id);
});
migrationBuilder.CreateTable(
name: "FeedbackTags",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
FeedbackReportId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
NormalizedName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FeedbackTags", x => x.Id);
table.ForeignKey(
name: "FK_FeedbackTags_FeedbackReports_FeedbackReportId",
column: x => x.FeedbackReportId,
principalTable: "FeedbackReports",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_FeedbackReports_LastActivityAt",
table: "FeedbackReports",
column: "LastActivityAt");
migrationBuilder.CreateIndex(
name: "IX_FeedbackReports_ReporterUserId",
table: "FeedbackReports",
column: "ReporterUserId");
migrationBuilder.CreateIndex(
name: "IX_FeedbackReports_Status",
table: "FeedbackReports",
column: "Status");
migrationBuilder.CreateIndex(
name: "IX_FeedbackReports_Type",
table: "FeedbackReports",
column: "Type");
migrationBuilder.CreateIndex(
name: "IX_FeedbackReports_WorkspaceId",
table: "FeedbackReports",
column: "WorkspaceId");
migrationBuilder.CreateIndex(
name: "IX_FeedbackTags_FeedbackReportId_NormalizedName",
table: "FeedbackTags",
columns: new[] { "FeedbackReportId", "NormalizedName" },
unique: true);
migrationBuilder.CreateIndex(
name: "IX_FeedbackTags_NormalizedName",
table: "FeedbackTags",
column: "NormalizedName");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "FeedbackTags");
migrationBuilder.DropTable(
name: "FeedbackReports");
}
}
}

View File

@@ -125,7 +125,7 @@ namespace Socialize.Api.Migrations
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Approvals.Data.ApprovalDecision", b =>
modelBuilder.Entity("Socialize.Api.Modules.Approvals.Data.ApprovalDecision", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -168,7 +168,7 @@ namespace Socialize.Api.Migrations
b.ToTable("ApprovalDecisions", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Approvals.Data.ApprovalRequest", b =>
modelBuilder.Entity("Socialize.Api.Modules.Approvals.Data.ApprovalRequest", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -230,7 +230,7 @@ namespace Socialize.Api.Migrations
b.ToTable("ApprovalRequests", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Assets.Data.Asset", b =>
modelBuilder.Entity("Socialize.Api.Modules.Assets.Data.Asset", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -286,7 +286,7 @@ namespace Socialize.Api.Migrations
b.ToTable("Assets", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Assets.Data.AssetRevision", b =>
modelBuilder.Entity("Socialize.Api.Modules.Assets.Data.AssetRevision", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -329,7 +329,7 @@ namespace Socialize.Api.Migrations
b.ToTable("AssetRevisions", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Clients.Data.Client", b =>
modelBuilder.Entity("Socialize.Api.Modules.Clients.Data.Client", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -379,7 +379,7 @@ namespace Socialize.Api.Migrations
b.ToTable("Clients", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Comments.Data.Comment", b =>
modelBuilder.Entity("Socialize.Api.Modules.Comments.Data.Comment", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -434,7 +434,7 @@ namespace Socialize.Api.Migrations
b.ToTable("Comments", (string)null);
});
modelBuilder.Entity("Socialize.Modules.ContentItems.Data.ContentItem", b =>
modelBuilder.Entity("Socialize.Api.Modules.ContentItems.Data.ContentItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -500,7 +500,7 @@ namespace Socialize.Api.Migrations
b.ToTable("ContentItems", (string)null);
});
modelBuilder.Entity("Socialize.Modules.ContentItems.Data.ContentItemRevision", b =>
modelBuilder.Entity("Socialize.Api.Modules.ContentItems.Data.ContentItemRevision", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -558,7 +558,150 @@ namespace Socialize.Api.Migrations
b.ToTable("ContentItemRevisions", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Identity.Data.Role", b =>
modelBuilder.Entity("Socialize.Api.Modules.Feedback.Data.FeedbackReport", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AppVersion")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("BrowserUserAgent")
.HasMaxLength(1024)
.HasColumnType("character varying(1024)");
b.Property<string>("CancellationReason")
.HasMaxLength(2000)
.HasColumnType("character varying(2000)");
b.Property<DateTimeOffset?>("CancelledAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid?>("CancelledByUserId")
.HasColumnType("uuid");
b.Property<Guid?>("ClientId")
.HasColumnType("uuid");
b.Property<string>("ClientName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<Guid?>("ContentItemId")
.HasColumnType("uuid");
b.Property<string>("ContentItemTitle")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<DateTimeOffset>("CreatedAt")
.ValueGeneratedOnAdd()
.HasColumnType("timestamp with time zone")
.HasDefaultValueSql("CURRENT_TIMESTAMP");
b.Property<string>("Description")
.IsRequired()
.HasMaxLength(8000)
.HasColumnType("character varying(8000)");
b.Property<DateTimeOffset>("LastActivityAt")
.HasColumnType("timestamp with time zone");
b.Property<Guid?>("ProjectId")
.HasColumnType("uuid");
b.Property<string>("ProjectName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("ReporterDisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("ReporterEmail")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<Guid>("ReporterUserId")
.HasColumnType("uuid");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)");
b.Property<string>("SubmittedPath")
.IsRequired()
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("Type")
.IsRequired()
.HasMaxLength(32)
.HasColumnType("character varying(32)");
b.Property<int?>("ViewportHeight")
.HasColumnType("integer");
b.Property<int?>("ViewportWidth")
.HasColumnType("integer");
b.Property<Guid?>("WorkspaceId")
.HasColumnType("uuid");
b.Property<string>("WorkspaceName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("LastActivityAt");
b.HasIndex("ReporterUserId");
b.HasIndex("Status");
b.HasIndex("Type");
b.HasIndex("WorkspaceId");
b.ToTable("FeedbackReports", (string)null);
});
modelBuilder.Entity("Socialize.Api.Modules.Feedback.Data.FeedbackTag", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("FeedbackReportId")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.Property<string>("NormalizedName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
b.HasKey("Id");
b.HasIndex("NormalizedName");
b.HasIndex("FeedbackReportId", "NormalizedName")
.IsUnique();
b.ToTable("FeedbackTags", (string)null);
});
modelBuilder.Entity("Socialize.Api.Modules.Identity.Data.Role", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -585,7 +728,7 @@ namespace Socialize.Api.Migrations
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Identity.Data.User", b =>
modelBuilder.Entity("Socialize.Api.Modules.Identity.Data.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -688,7 +831,7 @@ namespace Socialize.Api.Migrations
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Notifications.Data.NotificationEvent", b =>
modelBuilder.Entity("Socialize.Api.Modules.Notifications.Data.NotificationEvent", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -750,7 +893,7 @@ namespace Socialize.Api.Migrations
b.ToTable("NotificationEvents", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Projects.Data.Project", b =>
modelBuilder.Entity("Socialize.Api.Modules.Projects.Data.Project", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -803,7 +946,7 @@ namespace Socialize.Api.Migrations
b.ToTable("Projects", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Workspaces.Data.Workspace", b =>
modelBuilder.Entity("Socialize.Api.Modules.Workspaces.Data.Workspace", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -814,15 +957,15 @@ namespace Socialize.Api.Migrations
.HasColumnType("timestamp with time zone")
.HasDefaultValueSql("CURRENT_TIMESTAMP");
b.Property<string>("LogoUrl")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("LogoUrl")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<Guid>("OwnerUserId")
.HasColumnType("uuid");
@@ -846,7 +989,7 @@ namespace Socialize.Api.Migrations
b.ToTable("Workspaces", (string)null);
});
modelBuilder.Entity("Socialize.Modules.Workspaces.Data.WorkspaceInvite", b =>
modelBuilder.Entity("Socialize.Api.Modules.Workspaces.Data.WorkspaceInvite", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
@@ -889,7 +1032,7 @@ namespace Socialize.Api.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Socialize.Modules.Identity.Data.Role", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
@@ -898,7 +1041,7 @@ namespace Socialize.Api.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
{
b.HasOne("Socialize.Modules.Identity.Data.User", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -907,7 +1050,7 @@ namespace Socialize.Api.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
{
b.HasOne("Socialize.Modules.Identity.Data.User", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -916,13 +1059,13 @@ namespace Socialize.Api.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
{
b.HasOne("Socialize.Modules.Identity.Data.Role", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Socialize.Modules.Identity.Data.User", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@@ -931,12 +1074,28 @@ namespace Socialize.Api.Migrations
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
{
b.HasOne("Socialize.Modules.Identity.Data.User", null)
b.HasOne("Socialize.Api.Modules.Identity.Data.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Socialize.Api.Modules.Feedback.Data.FeedbackTag", b =>
{
b.HasOne("Socialize.Api.Modules.Feedback.Data.FeedbackReport", "FeedbackReport")
.WithMany("Tags")
.HasForeignKey("FeedbackReportId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("FeedbackReport");
});
modelBuilder.Entity("Socialize.Api.Modules.Feedback.Data.FeedbackReport", b =>
{
b.Navigation("Tags");
});
#pragma warning restore 612, 618
}
}