diff --git a/TimetableDesigner.Backend.Services.Authentication.Database/Configuration/EventConfiguration.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Configuration/EventConfiguration.cs new file mode 100644 index 0000000..0b39aef --- /dev/null +++ b/TimetableDesigner.Backend.Services.Authentication.Database/Configuration/EventConfiguration.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using TimetableDesigner.Backend.Services.Authentication.Database.Model; + +namespace TimetableDesigner.Backend.Services.Authentication.Database.Configuration; + +public class EventConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.HasIndex(x => x.Id) + .IsUnique(); + builder.Property(x => x.Id) + .IsRequired(); + + builder.Property(x => x.Payload) + .IsRequired(); + + builder.Property(x => x.PayloadType) + .IsRequired(); + + builder.Property(x => x.OccuredOn) + .IsRequired(); + + builder.Property(x => x.ProcessedOn); + + builder.Property(x => x.RetryCount) + .IsRequired(); + + builder.Property(b => b.Version) + .IsRowVersion(); + } +} \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20250924120541_Initial.Designer.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20250924120541_Initial.Designer.cs similarity index 100% rename from TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20250924120541_Initial.Designer.cs rename to TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20250924120541_Initial.Designer.cs diff --git a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20250924120541_Initial.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20250924120541_Initial.cs similarity index 100% rename from TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20250924120541_Initial.cs rename to TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20250924120541_Initial.cs diff --git a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20260114231600_Account changes.Designer.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260114231600_Account changes.Designer.cs similarity index 100% rename from TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20260114231600_Account changes.Designer.cs rename to TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260114231600_Account changes.Designer.cs diff --git a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20260114231600_Account changes.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260114231600_Account changes.cs similarity index 100% rename from TimetableDesigner.Backend.Services.Authentication/Database/Migrations/20260114231600_Account changes.cs rename to TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260114231600_Account changes.cs diff --git a/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.Designer.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.Designer.cs new file mode 100644 index 0000000..3305226 --- /dev/null +++ b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.Designer.cs @@ -0,0 +1,151 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TimetableDesigner.Backend.Services.Authentication.Database; + +#nullable disable + +namespace TimetableDesigner.Backend.Services.Authentication.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20260127191240_Outbox_Pattern")] + partial class Outbox_Pattern + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("PasswordSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Version") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("OccuredOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("text"); + + b.Property("PayloadType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProcessedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("RetryCount") + .HasColumnType("bigint"); + + b.Property("Version") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Event"); + }); + + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.RefreshToken", b => + { + b.Property("Token") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("IsExtendable") + .HasColumnType("boolean"); + + b.Property("Version") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Token"); + + b.HasIndex("AccountId"); + + b.HasIndex("Token") + .IsUnique(); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.RefreshToken", b => + { + b.HasOne("TimetableDesigner.Backend.Services.Authentication.Database.Model.Account", "Account") + .WithMany("RefreshTokens") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.Account", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.cs new file mode 100644 index 0000000..4e3a36d --- /dev/null +++ b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/20260127191240_Outbox_Pattern.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TimetableDesigner.Backend.Services.Authentication.Database.Migrations +{ + /// + public partial class Outbox_Pattern : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Event", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Payload = table.Column(type: "text", nullable: false), + PayloadType = table.Column(type: "text", nullable: false), + OccuredOn = table.Column(type: "timestamp with time zone", nullable: false), + ProcessedOn = table.Column(type: "timestamp with time zone", nullable: true), + RetryCount = table.Column(type: "bigint", nullable: false), + xmin = table.Column(type: "xid", rowVersion: true, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Event", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_Event_Id", + table: "Event", + column: "Id", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Event"); + } + } +} diff --git a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/DatabaseContextModelSnapshot.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/DatabaseContextModelSnapshot.cs similarity index 74% rename from TimetableDesigner.Backend.Services.Authentication/Database/Migrations/DatabaseContextModelSnapshot.cs rename to TimetableDesigner.Backend.Services.Authentication.Database/Migrations/DatabaseContextModelSnapshot.cs index bed91a8..17a4968 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Database/Migrations/DatabaseContextModelSnapshot.cs +++ b/TimetableDesigner.Backend.Services.Authentication.Database/Migrations/DatabaseContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace TimetableDesigner.Backend.Services.Authentication.Database.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("ProductVersion", "10.0.2") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -59,6 +59,43 @@ namespace TimetableDesigner.Backend.Services.Authentication.Database.Migrations b.ToTable("Accounts"); }); + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("OccuredOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("text"); + + b.Property("PayloadType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProcessedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("RetryCount") + .HasColumnType("bigint"); + + b.Property("Version") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("xid") + .HasColumnName("xmin"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Event"); + }); + modelBuilder.Entity("TimetableDesigner.Backend.Services.Authentication.Database.Model.RefreshToken", b => { b.Property("Token") diff --git a/TimetableDesigner.Backend.Services.Authentication.Database/Model/Event.cs b/TimetableDesigner.Backend.Services.Authentication.Database/Model/Event.cs new file mode 100644 index 0000000..0b701bd --- /dev/null +++ b/TimetableDesigner.Backend.Services.Authentication.Database/Model/Event.cs @@ -0,0 +1,12 @@ +namespace TimetableDesigner.Backend.Services.Authentication.Database.Model; + +public class Event +{ + public Guid Id { get; set; } + public required string Payload { get; set; } + public required string PayloadType { get; set; } + public DateTimeOffset OccuredOn { get; set; } = DateTimeOffset.UtcNow; + public DateTimeOffset? ProcessedOn { get; set; } + public uint RetryCount { get; set; } + public uint Version { get; set; } +} \ No newline at end of file