diff --git a/server/Directory.Packages.props b/server/Directory.Packages.props
index 8199c09..a803184 100644
--- a/server/Directory.Packages.props
+++ b/server/Directory.Packages.props
@@ -9,10 +9,12 @@
+
+
diff --git a/server/src/Application/Abstractions/Persistence/IAppDbContext.cs b/server/src/Application/Abstractions/Persistence/IAppDbContext.cs
index f5adbb6..cdf5682 100644
--- a/server/src/Application/Abstractions/Persistence/IAppDbContext.cs
+++ b/server/src/Application/Abstractions/Persistence/IAppDbContext.cs
@@ -28,6 +28,6 @@ public interface IAppDbContext
DbSet Tags { get; }
DbSet Cards { get; }
-
+ DbSet CardComments { get; }
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/server/src/Application/Boards/Create/CreateBoardCommand.cs b/server/src/Application/Boards/Create/CreateBoardCommand.cs
index 6a3a2e4..e84ed38 100644
--- a/server/src/Application/Boards/Create/CreateBoardCommand.cs
+++ b/server/src/Application/Boards/Create/CreateBoardCommand.cs
@@ -7,5 +7,5 @@ public sealed record CreateBoardMemberRequest(int UserId, MemberRole Role);
public sealed record CreateBoardCommand(
string Title,
- string Description,
+ string? Description,
IReadOnlyList? Members = null) : ICommand;
\ No newline at end of file
diff --git a/server/src/Application/Boards/Get/GetBoardsResponse.cs b/server/src/Application/Boards/Get/GetBoardsResponse.cs
index aaac80c..9a10fc9 100644
--- a/server/src/Application/Boards/Get/GetBoardsResponse.cs
+++ b/server/src/Application/Boards/Get/GetBoardsResponse.cs
@@ -15,7 +15,7 @@ public sealed record UserDto(int Id, string UserName)
public sealed record BoardDto(
int Id,
string Title,
- string Description,
+ string? Description,
MemberRole YourRole,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
diff --git a/server/src/Application/Boards/GetById/GetBoardByIdHandler.cs b/server/src/Application/Boards/GetById/GetBoardByIdHandler.cs
index 14a8b0f..f78aab8 100644
--- a/server/src/Application/Boards/GetById/GetBoardByIdHandler.cs
+++ b/server/src/Application/Boards/GetById/GetBoardByIdHandler.cs
@@ -46,7 +46,16 @@ public async Task> Handle(GetBoardByIdQuery query,
c.CreatedAt,
UserDto.From(c.CreatedBy),
c.UpdatedAt,
- UserDto.From(c.UpdatedBy)))
+ UserDto.From(c.UpdatedBy),
+ c.Comments
+ .OrderBy(comm => comm.CreatedAt)
+ .Select(comm => new CardCommentDto(
+ comm.Id,
+ comm.UserId,
+ comm.User.UserName ?? "Unknown",
+ comm.Content,
+ comm.CreatedAt))
+ .ToList()))
.ToList()))
.ToList()))
.ToList()))
diff --git a/server/src/Application/Boards/GetById/GetBoardByIdResponse.cs b/server/src/Application/Boards/GetById/GetBoardByIdResponse.cs
index 0caa6b4..2ef7c35 100644
--- a/server/src/Application/Boards/GetById/GetBoardByIdResponse.cs
+++ b/server/src/Application/Boards/GetById/GetBoardByIdResponse.cs
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
+using Snapflow.Application.Cards.AddComment;
using static Snapflow.Application.Boards.GetById.GetBoardByIdResponse;
namespace Snapflow.Application.Boards.GetById;
@@ -6,7 +7,7 @@ namespace Snapflow.Application.Boards.GetById;
public sealed record GetBoardByIdResponse(
int Id,
string Title,
- string Description,
+ string? Description,
IReadOnlyList Swimlanes)
{
public sealed record UserDto(int Id, string UserName)
@@ -34,10 +35,17 @@ public sealed record ListDto(
public sealed record CardDto(
int Id,
string Title,
- string Description,
+ string? Description,
string Rank,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
DateTimeOffset? UpdatedAt,
- UserDto? UpdatedBy);
+ UserDto? UpdatedBy,
+ List Comments);
+ public sealed record CardCommentDto(
+ int Id,
+ int UserId,
+ string UserName,
+ string Content,
+ DateTimeOffset CreatedAt);
}
\ No newline at end of file
diff --git a/server/src/Application/Boards/GetDetails/GetBoardDetailsResponse.cs b/server/src/Application/Boards/GetDetails/GetBoardDetailsResponse.cs
index 0453e20..b56356b 100644
--- a/server/src/Application/Boards/GetDetails/GetBoardDetailsResponse.cs
+++ b/server/src/Application/Boards/GetDetails/GetBoardDetailsResponse.cs
@@ -5,7 +5,7 @@ namespace Snapflow.Application.Boards.GetDetails;
public sealed record GetBoardDetailsResponse(
int Id,
string Title,
- string Description,
+ string? Description,
IReadOnlyList Members);
public sealed record GetBoardDetailsMemberResponse(
diff --git a/server/src/Application/Cards/AppComment/AddCardCommentCommand.cs b/server/src/Application/Cards/AppComment/AddCardCommentCommand.cs
new file mode 100644
index 0000000..09d1d42
--- /dev/null
+++ b/server/src/Application/Cards/AppComment/AddCardCommentCommand.cs
@@ -0,0 +1,7 @@
+using Snapflow.Application.Abstractions.Messaging;
+using Snapflow.Application.Boards.GetById;
+
+namespace Snapflow.Application.Cards.AddComment;
+
+public sealed record AddCardCommentCommand(int CardId, int UserId, string Content)
+ : ICommand;
\ No newline at end of file
diff --git a/server/src/Application/Cards/AppComment/AddCardCommentHandler.cs b/server/src/Application/Cards/AppComment/AddCardCommentHandler.cs
new file mode 100644
index 0000000..f8e270a
--- /dev/null
+++ b/server/src/Application/Cards/AppComment/AddCardCommentHandler.cs
@@ -0,0 +1,46 @@
+using Microsoft.EntityFrameworkCore;
+using Snapflow.Application.Abstractions.Messaging;
+using Snapflow.Application.Abstractions.Persistence;
+using Snapflow.Application.Boards.GetById;
+using Snapflow.Common;
+using Snapflow.Domain.Cards;
+
+namespace Snapflow.Application.Cards.AddComment;
+
+internal sealed class AddCardCommentCommandHandler(
+ IAppDbContext context) : ICommandHandler // <--- ZMIANA 1: Zwracamy DTO zamiast int
+{
+ public async Task> Handle(AddCardCommentCommand request, CancellationToken cancellationToken = default)
+ {
+ var card = await context.Cards
+ .FirstOrDefaultAsync(c => c.Id == request.CardId && !c.IsDeleted, cancellationToken);
+
+ if (card is null)
+ {
+ return Result.Failure(CardErrors.NotFound(request.CardId));
+ }
+
+ var user = await context.Users
+ .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);
+
+ if (user is null)
+ {
+ return Result.Failure(new Error("User.NotFound", "User not found", ErrorType.NotFound));
+ }
+
+ var comment = CardComment.Create(request.CardId, request.UserId, request.Content);
+
+ context.CardComments.Add(comment);
+ await context.SaveChangesAsync(cancellationToken);
+
+ var dto = new GetBoardByIdResponse.CardCommentDto(
+ comment.Id,
+ user.Id,
+ user.UserName ?? "Unknown",
+ comment.Content,
+ comment.CreatedAt
+ );
+
+ return dto;
+ }
+}
\ No newline at end of file
diff --git a/server/src/Application/Cards/GetByBoardId/GetCardsByBoardIdResponse.cs b/server/src/Application/Cards/GetByBoardId/GetCardsByBoardIdResponse.cs
index a96a3b6..efe9042 100644
--- a/server/src/Application/Cards/GetByBoardId/GetCardsByBoardIdResponse.cs
+++ b/server/src/Application/Cards/GetByBoardId/GetCardsByBoardIdResponse.cs
@@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
- string Description,
+ string? Description,
string Rank);
}
\ No newline at end of file
diff --git a/server/src/Application/Cards/GetById/GetCardByIdResponse.cs b/server/src/Application/Cards/GetById/GetCardByIdResponse.cs
index 1d97e80..bbcbba8 100644
--- a/server/src/Application/Cards/GetById/GetCardByIdResponse.cs
+++ b/server/src/Application/Cards/GetById/GetCardByIdResponse.cs
@@ -9,7 +9,7 @@ public sealed record GetCardByIdResponse(
int SwimlaneId,
int BoardId,
string Title,
- string Description,
+ string? Description,
string Rank,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
diff --git a/server/src/Application/Cards/GetByListId/GetCardsByListIdResponse.cs b/server/src/Application/Cards/GetByListId/GetCardsByListIdResponse.cs
index b7bd651..8f9658a 100644
--- a/server/src/Application/Cards/GetByListId/GetCardsByListIdResponse.cs
+++ b/server/src/Application/Cards/GetByListId/GetCardsByListIdResponse.cs
@@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
- string Description,
+ string? Description,
string Rank);
}
\ No newline at end of file
diff --git a/server/src/Application/Cards/GetBySwimlaneId/GetCardsBySwimlaneIdResponse.cs b/server/src/Application/Cards/GetBySwimlaneId/GetCardsBySwimlaneIdResponse.cs
index 050fd9a..2cac8db 100644
--- a/server/src/Application/Cards/GetBySwimlaneId/GetCardsBySwimlaneIdResponse.cs
+++ b/server/src/Application/Cards/GetBySwimlaneId/GetCardsBySwimlaneIdResponse.cs
@@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
- string Description,
+ string? Description,
string Rank);
}
\ No newline at end of file
diff --git a/server/src/Application/Cards/Update/UpdateCardCommand.cs b/server/src/Application/Cards/Update/UpdateCardCommand.cs
index 1c3183c..ab4844b 100644
--- a/server/src/Application/Cards/Update/UpdateCardCommand.cs
+++ b/server/src/Application/Cards/Update/UpdateCardCommand.cs
@@ -2,4 +2,4 @@
namespace Snapflow.Application.Cards.Update;
-public sealed record UpdateCardCommand(int Id, string Title, string Description) : ICommand;
\ No newline at end of file
+public sealed record UpdateCardCommand(int Id, string Title, string? Description) : ICommand;
\ No newline at end of file
diff --git a/server/src/Domain/Boards/Board.cs b/server/src/Domain/Boards/Board.cs
index 03beda6..8eb3e50 100644
--- a/server/src/Domain/Boards/Board.cs
+++ b/server/src/Domain/Boards/Board.cs
@@ -13,7 +13,7 @@ public class Board : Entity
public Board() { }
public string Title { get; private set; } = null!;
- public string Description { get; private set; } = "";
+ public string? Description { get; private set; } = "";
public DateTimeOffset CreatedAt { get; private set; }
public int CreatedById { get; private set; }
@@ -34,7 +34,7 @@ public Board() { }
public virtual ICollection Cards { get; private set; } = [];
public virtual ICollection Tags { get; private set; } = [];
- public static Board Create(string title, string description, int createdById, DateTimeOffset createdAt, string? connectionId = null)
+ public static Board Create(string title, string? description, int createdById, DateTimeOffset createdAt, string? connectionId = null)
{
var board = new Board
{
@@ -51,7 +51,7 @@ public static Board Create(string title, string description, int createdById, Da
return board;
}
- public void Update(string title, string description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
+ public void Update(string title, string? description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
{
Title = title;
Description = description;
diff --git a/server/src/Domain/Boards/BoardEvents.cs b/server/src/Domain/Boards/BoardEvents.cs
index 9cb8d5e..a47ee34 100644
--- a/server/src/Domain/Boards/BoardEvents.cs
+++ b/server/src/Domain/Boards/BoardEvents.cs
@@ -11,7 +11,7 @@ public sealed record BoardCreatedDomainEvent(
public sealed record BoardUpdatedDomainEvent(
int Id,
string Title,
- string Description,
+ string? Description,
string? ConnectionId) : IDomainEvent;
public sealed record BoardDeletedDomainEvent(
diff --git a/server/src/Domain/Cards/Card.cs b/server/src/Domain/Cards/Card.cs
index 3cbfdb5..9ed3cec 100644
--- a/server/src/Domain/Cards/Card.cs
+++ b/server/src/Domain/Cards/Card.cs
@@ -20,9 +20,8 @@ public Card() { }
public virtual List List { get; private set; } = null!;
public string Title { get; private set; } = null!;
- public string Description { get; private set; } = "";
+ public string? Description { get; private set; } = "";
public string Rank { get; set; } = null!;
-
public DateTimeOffset CreatedAt { get; private set; }
public int CreatedById { get; private set; }
public virtual IUser CreatedBy { get; private set; } = null!;
@@ -38,8 +37,10 @@ public Card() { }
public bool DeletedByCascade { get; private set; }
public virtual ICollection Tags { get; private set; } = [];
-
- public static Card Create(int boardId, int swimlaneId, int listId, string title, string description, string rank, int createdById, DateTimeOffset createdAt, string? connectionId = null)
+
+ private readonly List _comments = [];
+ public virtual IReadOnlyCollection Comments => _comments.AsReadOnly();
+ public static Card Create(int boardId, int swimlaneId, int listId, string title, string? description, string rank, int createdById, DateTimeOffset createdAt, string? connectionId = null)
{
var card = new Card
{
@@ -58,7 +59,7 @@ public static Card Create(int boardId, int swimlaneId, int listId, string title,
return card;
}
- public void Update(string title, string description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
+ public void Update(string title, string? description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
{
Title = title;
Description = description;
@@ -88,4 +89,8 @@ public void SoftDelete(int deletedById, DateTimeOffset deletedAt, string? connec
Raise(c => new CardDeletedDomainEvent(Id, BoardId, connectionId));
}
+ public void AddComment(int userId, string content)
+ {
+ _comments.Add(CardComment.Create(Id, userId, content));
+ }
}
\ No newline at end of file
diff --git a/server/src/Domain/Cards/CardComment.cs b/server/src/Domain/Cards/CardComment.cs
new file mode 100644
index 0000000..f699c95
--- /dev/null
+++ b/server/src/Domain/Cards/CardComment.cs
@@ -0,0 +1,24 @@
+using Snapflow.Domain.Users;
+using Snapflow.Common;
+
+namespace Snapflow.Domain.Cards;
+
+public class CardComment : Entity
+{
+ public int CardId { get; private set; }
+ public int UserId { get; private set; }
+ public string Content { get; private set; } = null!;
+ public DateTimeOffset CreatedAt { get; private set; }
+ public virtual IUser User { get; private set; } = null!;
+
+ public static CardComment Create(int cardId, int userId, string content)
+ {
+ return new CardComment
+ {
+ CardId = cardId,
+ UserId = userId,
+ Content = content,
+ CreatedAt = DateTimeOffset.UtcNow
+ };
+ }
+}
\ No newline at end of file
diff --git a/server/src/Domain/Cards/CardEvents.cs b/server/src/Domain/Cards/CardEvents.cs
index d5434d7..36ea785 100644
--- a/server/src/Domain/Cards/CardEvents.cs
+++ b/server/src/Domain/Cards/CardEvents.cs
@@ -8,7 +8,7 @@ public sealed record CardCreatedDomainEvent(
int SwimlaneId,
int ListId,
string Title,
- string Description,
+ string? Description,
string Rank,
string? ConnectionId) : IDomainEvent;
@@ -16,7 +16,7 @@ public sealed record CardUpdatedDomainEvent(
int Id,
int BoardId,
string Title,
- string Description,
+ string? Description,
string? ConnectionId) : IDomainEvent;
public sealed record CardMovedDomainEvent(
diff --git a/server/src/Infrastructure/Infrastructure.csproj b/server/src/Infrastructure/Infrastructure.csproj
index 7504989..b55c3c0 100644
--- a/server/src/Infrastructure/Infrastructure.csproj
+++ b/server/src/Infrastructure/Infrastructure.csproj
@@ -10,6 +10,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/server/src/Infrastructure/Persistence/AppDbContext.cs b/server/src/Infrastructure/Persistence/AppDbContext.cs
index 56dcbd6..4f43836 100644
--- a/server/src/Infrastructure/Persistence/AppDbContext.cs
+++ b/server/src/Infrastructure/Persistence/AppDbContext.cs
@@ -14,6 +14,7 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Snapflow.Domain.Roles;
+
namespace Snapflow.Infrastructure.Persistence;
public sealed class AppDbContext(
@@ -28,7 +29,7 @@ public sealed class AppDbContext(
public DbSet Members { get; private set; }
public DbSet Tags { get; private set; }
public DbSet Cards { get; private set; }
-
+ public DbSet CardComments => Set();
public DbSet DataProtectionKeys { get; private set; }
protected override void OnModelCreating(ModelBuilder builder)
@@ -44,5 +45,14 @@ protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity(entityType.ClrType).Ignore(nameof(IEntity.DomainEvents));
}
+ builder.Entity(entity =>
+ {
+ entity.HasOne(x => (AppUser)x.User)
+ .WithMany()
+ .HasForeignKey(x => x.UserId)
+ .OnDelete(DeleteBehavior.NoAction);
+
+ entity.ToTable("card_comments");
+ });
}
}
diff --git a/server/src/Infrastructure/Persistence/Configurations/CardConfiguration.cs b/server/src/Infrastructure/Persistence/Configurations/CardConfiguration.cs
index 1811120..a05e952 100644
--- a/server/src/Infrastructure/Persistence/Configurations/CardConfiguration.cs
+++ b/server/src/Infrastructure/Persistence/Configurations/CardConfiguration.cs
@@ -37,5 +37,8 @@ public void Configure(EntityTypeBuilder builder)
builder.HasIndex(c => c.ListId)
.HasFilter("is_deleted = false");
+ builder.Property(card => card.Description)
+ .HasMaxLength(2000)
+ .IsRequired(false);
}
}
diff --git a/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.Designer.cs b/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.Designer.cs
new file mode 100644
index 0000000..2f9e8c0
--- /dev/null
+++ b/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.Designer.cs
@@ -0,0 +1,1124 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Snapflow.Infrastructure.Persistence;
+
+#nullable disable
+
+namespace Snapflow.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20260505113154_AddCardDescription")]
+ partial class AddCardDescription
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("public")
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("CardTag", b =>
+ {
+ b.Property("CardsId")
+ .HasColumnType("integer")
+ .HasColumnName("cards_id");
+
+ b.Property("TagsId")
+ .HasColumnType("integer")
+ .HasColumnName("tags_id");
+
+ b.HasKey("CardsId", "TagsId")
+ .HasName("pk_card_tag");
+
+ b.HasIndex("TagsId")
+ .HasDatabaseName("ix_card_tag_tags_id");
+
+ b.ToTable("card_tag", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("FriendlyName")
+ .HasColumnType("text")
+ .HasColumnName("friendly_name");
+
+ b.Property("Xml")
+ .HasColumnType("text")
+ .HasColumnName("xml");
+
+ b.HasKey("Id")
+ .HasName("pk_data_protection_keys");
+
+ b.ToTable("data_protection_keys", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text")
+ .HasColumnName("claim_type");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text")
+ .HasColumnName("claim_value");
+
+ b.Property("RoleId")
+ .HasColumnType("integer")
+ .HasColumnName("role_id");
+
+ b.HasKey("Id")
+ .HasName("pk_role_claims");
+
+ b.HasIndex("RoleId")
+ .HasDatabaseName("ix_role_claims_role_id");
+
+ b.ToTable("role_claims", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text")
+ .HasColumnName("claim_type");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text")
+ .HasColumnName("claim_value");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("pk_user_claims");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_user_claims_user_id");
+
+ b.ToTable("user_claims", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("text")
+ .HasColumnName("login_provider");
+
+ b.Property("ProviderKey")
+ .HasColumnType("text")
+ .HasColumnName("provider_key");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("text")
+ .HasColumnName("provider_display_name");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.HasKey("LoginProvider", "ProviderKey")
+ .HasName("pk_user_logins");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_user_logins_user_id");
+
+ b.ToTable("user_logins", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("RoleId")
+ .HasColumnType("integer")
+ .HasColumnName("role_id");
+
+ b.HasKey("UserId", "RoleId")
+ .HasName("pk_user_roles");
+
+ b.HasIndex("RoleId")
+ .HasDatabaseName("ix_user_roles_role_id");
+
+ b.ToTable("user_roles", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("LoginProvider")
+ .HasColumnType("text")
+ .HasColumnName("login_provider");
+
+ b.Property("Name")
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.Property("Value")
+ .HasColumnType("text")
+ .HasColumnName("value");
+
+ b.HasKey("UserId", "LoginProvider", "Name")
+ .HasName("pk_user_tokens");
+
+ b.ToTable("user_tokens", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Boards.Board", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Description")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasDefaultValue("")
+ .HasColumnName("description");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_boards");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_boards_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_boards_deleted_by_id");
+
+ b.HasIndex("Title")
+ .HasDatabaseName("ix_boards_title")
+ .HasAnnotation("Npgsql:TsVectorConfig", "english");
+
+ NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Title"), "GIN");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_boards_updated_by_id");
+
+ b.ToTable("boards", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Cards.Card", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedByCascade")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted_by_cascade");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Description")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("description");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("ListId")
+ .HasColumnType("integer")
+ .HasColumnName("list_id");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(12)
+ .HasColumnType("character varying(12)")
+ .HasColumnName("rank");
+
+ b.Property("SwimlaneId")
+ .HasColumnType("integer")
+ .HasColumnName("swimlane_id");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_cards");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_cards_board_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_cards_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_cards_deleted_by_id");
+
+ b.HasIndex("ListId")
+ .HasDatabaseName("ix_cards_list_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("SwimlaneId")
+ .HasDatabaseName("ix_cards_swimlane_id");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_cards_updated_by_id");
+
+ b.HasIndex("ListId", "Rank")
+ .IsUnique()
+ .HasDatabaseName("ix_cards_list_id_rank")
+ .HasFilter("is_deleted = false");
+
+ b.ToTable("cards", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Lists.List", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedByCascade")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted_by_cascade");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(12)
+ .HasColumnType("character varying(12)")
+ .HasColumnName("rank");
+
+ b.Property("SwimlaneId")
+ .HasColumnType("integer")
+ .HasColumnName("swimlane_id");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.Property("Width")
+ .HasColumnType("integer")
+ .HasColumnName("width");
+
+ b.HasKey("Id")
+ .HasName("pk_lists");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_lists_board_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_lists_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_lists_deleted_by_id");
+
+ b.HasIndex("SwimlaneId")
+ .HasDatabaseName("ix_lists_swimlane_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_lists_updated_by_id");
+
+ b.HasIndex("SwimlaneId", "Rank")
+ .IsUnique()
+ .HasDatabaseName("ix_lists_swimlane_id_rank")
+ .HasFilter("is_deleted = false");
+
+ b.ToTable("lists", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Members.Member", b =>
+ {
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("Role")
+ .HasColumnType("integer")
+ .HasColumnName("role");
+
+ b.HasKey("BoardId", "UserId")
+ .HasName("pk_board_members");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_board_members_user_id");
+
+ b.HasIndex("BoardId", "Role")
+ .IsUnique()
+ .HasDatabaseName("ix_board_members_board_id_role")
+ .HasFilter("\"role\" = 0");
+
+ b.ToTable("board_members", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Swimlanes.Swimlane", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedByCascade")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted_by_cascade");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Height")
+ .HasColumnType("integer")
+ .HasColumnName("height");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(12)
+ .HasColumnType("character varying(12)")
+ .HasColumnName("rank");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_swimlanes");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_swimlanes_board_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_swimlanes_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_swimlanes_deleted_by_id");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_swimlanes_updated_by_id");
+
+ b.HasIndex("BoardId", "Rank")
+ .IsUnique()
+ .HasDatabaseName("ix_swimlanes_board_id_rank")
+ .HasFilter("is_deleted = false");
+
+ b.ToTable("swimlanes", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Tags.Tag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("Color")
+ .HasColumnType("integer")
+ .HasColumnName("color");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_tags");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_tags_board_id");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_tags_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_tags_deleted_by_id");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_tags_updated_by_id");
+
+ b.ToTable("tags", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Infrastructure.Auth.Entities.AppRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text")
+ .HasColumnName("concurrency_stamp");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("name");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("normalized_name");
+
+ b.HasKey("Id")
+ .HasName("pk_roles");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("roles", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Infrastructure.Auth.Entities.AppUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer")
+ .HasColumnName("access_failed_count");
+
+ b.Property("AvatarContentType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("avatar_content_type");
+
+ b.Property("AvatarData")
+ .HasColumnType("bytea")
+ .HasColumnName("avatar_data");
+
+ b.Property("AvatarType")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasDefaultValue(0)
+ .HasColumnName("avatar_type");
+
+ b.Property("AvatarUrl")
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasColumnName("avatar_url");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text")
+ .HasColumnName("concurrency_stamp");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("email");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("boolean")
+ .HasColumnName("email_confirmed");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(false)
+ .HasColumnName("is_deleted");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("boolean")
+ .HasColumnName("lockout_enabled");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("lockout_end");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("normalized_email");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("normalized_user_name");
+
+ b.Property("PasswordHash")
+ .HasColumnType("text")
+ .HasColumnName("password_hash");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("text")
+ .HasColumnName("phone_number");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean")
+ .HasColumnName("phone_number_confirmed");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("text")
+ .HasColumnName("security_stamp");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("boolean")
+ .HasColumnName("two_factor_enabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("user_name");
+
+ b.HasKey("Id")
+ .HasName("pk_users");
+
+ b.HasIndex("Email")
+ .IsUnique()
+ .HasDatabaseName("ix_users_email");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("users", "public");
+ });
+
+ modelBuilder.Entity("CardTag", b =>
+ {
+ b.HasOne("Snapflow.Domain.Cards.Card", null)
+ .WithMany()
+ .HasForeignKey("CardsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_card_tag_cards_cards_id");
+
+ b.HasOne("Snapflow.Domain.Tags.Tag", null)
+ .WithMany()
+ .HasForeignKey("TagsId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_card_tag_tags_tags_id");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_role_claims_roles_role_id");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_user_claims_users_user_id");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_user_logins_users_user_id");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_user_roles_roles_role_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_user_roles_users_user_id");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_user_tokens_users_user_id");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Boards.Board", b =>
+ {
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "CreatedBy")
+ .WithMany()
+ .HasForeignKey("CreatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_boards_users_created_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "DeletedBy")
+ .WithMany()
+ .HasForeignKey("DeletedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_boards_users_deleted_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "UpdatedBy")
+ .WithMany()
+ .HasForeignKey("UpdatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_boards_users_updated_by_id");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("UpdatedBy");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Cards.Card", b =>
+ {
+ b.HasOne("Snapflow.Domain.Boards.Board", "Board")
+ .WithMany("Cards")
+ .HasForeignKey("BoardId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_cards_boards_board_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "CreatedBy")
+ .WithMany()
+ .HasForeignKey("CreatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_cards_users_created_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "DeletedBy")
+ .WithMany()
+ .HasForeignKey("DeletedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_cards_users_deleted_by_id");
+
+ b.HasOne("Snapflow.Domain.Lists.List", "List")
+ .WithMany("Cards")
+ .HasForeignKey("ListId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_cards_lists_list_id");
+
+ b.HasOne("Snapflow.Domain.Swimlanes.Swimlane", "Swimlane")
+ .WithMany("Cards")
+ .HasForeignKey("SwimlaneId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_cards_swimlanes_swimlane_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "UpdatedBy")
+ .WithMany()
+ .HasForeignKey("UpdatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_cards_users_updated_by_id");
+
+ b.Navigation("Board");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("List");
+
+ b.Navigation("Swimlane");
+
+ b.Navigation("UpdatedBy");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Lists.List", b =>
+ {
+ b.HasOne("Snapflow.Domain.Boards.Board", "Board")
+ .WithMany("Lists")
+ .HasForeignKey("BoardId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_lists_boards_board_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "CreatedBy")
+ .WithMany()
+ .HasForeignKey("CreatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_lists_users_created_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "DeletedBy")
+ .WithMany()
+ .HasForeignKey("DeletedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_lists_users_deleted_by_id");
+
+ b.HasOne("Snapflow.Domain.Swimlanes.Swimlane", "Swimlane")
+ .WithMany("Lists")
+ .HasForeignKey("SwimlaneId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_lists_swimlanes_swimlane_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "UpdatedBy")
+ .WithMany()
+ .HasForeignKey("UpdatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_lists_users_updated_by_id");
+
+ b.Navigation("Board");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("Swimlane");
+
+ b.Navigation("UpdatedBy");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Members.Member", b =>
+ {
+ b.HasOne("Snapflow.Domain.Boards.Board", "Board")
+ .WithMany("Members")
+ .HasForeignKey("BoardId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_board_members_boards_board_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_board_members_users_user_id");
+
+ b.Navigation("Board");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Swimlanes.Swimlane", b =>
+ {
+ b.HasOne("Snapflow.Domain.Boards.Board", "Board")
+ .WithMany("Swimlanes")
+ .HasForeignKey("BoardId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_swimlanes_boards_board_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "CreatedBy")
+ .WithMany()
+ .HasForeignKey("CreatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_swimlanes_users_created_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "DeletedBy")
+ .WithMany()
+ .HasForeignKey("DeletedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_swimlanes_users_deleted_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "UpdatedBy")
+ .WithMany()
+ .HasForeignKey("UpdatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_swimlanes_users_updated_by_id");
+
+ b.Navigation("Board");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("UpdatedBy");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Tags.Tag", b =>
+ {
+ b.HasOne("Snapflow.Domain.Boards.Board", "Board")
+ .WithMany("Tags")
+ .HasForeignKey("BoardId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_tags_boards_board_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "CreatedBy")
+ .WithMany()
+ .HasForeignKey("CreatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_tags_users_created_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "DeletedBy")
+ .WithMany()
+ .HasForeignKey("DeletedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_tags_users_deleted_by_id");
+
+ b.HasOne("Snapflow.Infrastructure.Auth.Entities.AppUser", "UpdatedBy")
+ .WithMany()
+ .HasForeignKey("UpdatedById")
+ .OnDelete(DeleteBehavior.Restrict)
+ .HasConstraintName("fk_tags_users_updated_by_id");
+
+ b.Navigation("Board");
+
+ b.Navigation("CreatedBy");
+
+ b.Navigation("DeletedBy");
+
+ b.Navigation("UpdatedBy");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Boards.Board", b =>
+ {
+ b.Navigation("Cards");
+
+ b.Navigation("Lists");
+
+ b.Navigation("Members");
+
+ b.Navigation("Swimlanes");
+
+ b.Navigation("Tags");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Lists.List", b =>
+ {
+ b.Navigation("Cards");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Swimlanes.Swimlane", b =>
+ {
+ b.Navigation("Cards");
+
+ b.Navigation("Lists");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.cs b/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.cs
new file mode 100644
index 0000000..79f161c
--- /dev/null
+++ b/server/src/Infrastructure/Persistence/Migrations/20260505113154_AddCardDescription.cs
@@ -0,0 +1,40 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Snapflow.Infrastructure.Persistence.Migrations
+{
+ ///
+ public partial class AddCardDescription : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "description",
+ schema: "public",
+ table: "cards",
+ type: "character varying(2000)",
+ maxLength: 2000,
+ nullable: true,
+ oldClrType: typeof(string),
+ oldType: "text");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn(
+ name: "description",
+ schema: "public",
+ table: "cards",
+ type: "text",
+ nullable: false,
+ defaultValue: "",
+ oldClrType: typeof(string),
+ oldType: "character varying(2000)",
+ oldMaxLength: 2000,
+ oldNullable: true);
+ }
+ }
+}
diff --git a/server/src/Infrastructure/Persistence/Migrations/20260505141557_AddCardComments.Designer.cs b/server/src/Infrastructure/Persistence/Migrations/20260505141557_AddCardComments.Designer.cs
new file mode 100644
index 0000000..cf8aebc
--- /dev/null
+++ b/server/src/Infrastructure/Persistence/Migrations/20260505141557_AddCardComments.Designer.cs
@@ -0,0 +1,1186 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Snapflow.Infrastructure.Persistence;
+
+#nullable disable
+
+namespace Snapflow.Infrastructure.Persistence.Migrations
+{
+ [DbContext(typeof(AppDbContext))]
+ [Migration("20260505141557_AddCardComments")]
+ partial class AddCardComments
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("public")
+ .HasAnnotation("ProductVersion", "10.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("CardTag", b =>
+ {
+ b.Property("CardsId")
+ .HasColumnType("integer")
+ .HasColumnName("cards_id");
+
+ b.Property("TagsId")
+ .HasColumnType("integer")
+ .HasColumnName("tags_id");
+
+ b.HasKey("CardsId", "TagsId")
+ .HasName("pk_card_tag");
+
+ b.HasIndex("TagsId")
+ .HasDatabaseName("ix_card_tag_tags_id");
+
+ b.ToTable("card_tag", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("FriendlyName")
+ .HasColumnType("text")
+ .HasColumnName("friendly_name");
+
+ b.Property("Xml")
+ .HasColumnType("text")
+ .HasColumnName("xml");
+
+ b.HasKey("Id")
+ .HasName("pk_data_protection_keys");
+
+ b.ToTable("data_protection_keys", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text")
+ .HasColumnName("claim_type");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text")
+ .HasColumnName("claim_value");
+
+ b.Property("RoleId")
+ .HasColumnType("integer")
+ .HasColumnName("role_id");
+
+ b.HasKey("Id")
+ .HasName("pk_role_claims");
+
+ b.HasIndex("RoleId")
+ .HasDatabaseName("ix_role_claims_role_id");
+
+ b.ToTable("role_claims", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text")
+ .HasColumnName("claim_type");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text")
+ .HasColumnName("claim_value");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("pk_user_claims");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_user_claims_user_id");
+
+ b.ToTable("user_claims", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("text")
+ .HasColumnName("login_provider");
+
+ b.Property("ProviderKey")
+ .HasColumnType("text")
+ .HasColumnName("provider_key");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("text")
+ .HasColumnName("provider_display_name");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.HasKey("LoginProvider", "ProviderKey")
+ .HasName("pk_user_logins");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_user_logins_user_id");
+
+ b.ToTable("user_logins", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("RoleId")
+ .HasColumnType("integer")
+ .HasColumnName("role_id");
+
+ b.HasKey("UserId", "RoleId")
+ .HasName("pk_user_roles");
+
+ b.HasIndex("RoleId")
+ .HasDatabaseName("ix_user_roles_role_id");
+
+ b.ToTable("user_roles", "public");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("LoginProvider")
+ .HasColumnType("text")
+ .HasColumnName("login_provider");
+
+ b.Property("Name")
+ .HasColumnType("text")
+ .HasColumnName("name");
+
+ b.Property("Value")
+ .HasColumnType("text")
+ .HasColumnName("value");
+
+ b.HasKey("UserId", "LoginProvider", "Name")
+ .HasName("pk_user_tokens");
+
+ b.ToTable("user_tokens", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Boards.Board", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Description")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasDefaultValue("")
+ .HasColumnName("description");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_boards");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_boards_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_boards_deleted_by_id");
+
+ b.HasIndex("Title")
+ .HasDatabaseName("ix_boards_title")
+ .HasAnnotation("Npgsql:TsVectorConfig", "english");
+
+ NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Title"), "GIN");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_boards_updated_by_id");
+
+ b.ToTable("boards", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Cards.Card", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedByCascade")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted_by_cascade");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("Description")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("description");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("ListId")
+ .HasColumnType("integer")
+ .HasColumnName("list_id");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(12)
+ .HasColumnType("character varying(12)")
+ .HasColumnName("rank");
+
+ b.Property("SwimlaneId")
+ .HasColumnType("integer")
+ .HasColumnName("swimlane_id");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.HasKey("Id")
+ .HasName("pk_cards");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_cards_board_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_cards_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_cards_deleted_by_id");
+
+ b.HasIndex("ListId")
+ .HasDatabaseName("ix_cards_list_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("SwimlaneId")
+ .HasDatabaseName("ix_cards_swimlane_id");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_cards_updated_by_id");
+
+ b.HasIndex("ListId", "Rank")
+ .IsUnique()
+ .HasDatabaseName("ix_cards_list_id_rank")
+ .HasFilter("is_deleted = false");
+
+ b.ToTable("cards", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Cards.CardComment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("CardId")
+ .HasColumnType("integer")
+ .HasColumnName("card_id");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("content");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.HasKey("Id")
+ .HasName("pk_card_comments");
+
+ b.HasIndex("CardId")
+ .HasDatabaseName("ix_card_comments_card_id");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_card_comments_user_id");
+
+ b.ToTable("CardComments", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Lists.List", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedById")
+ .HasColumnType("integer")
+ .HasColumnName("created_by_id");
+
+ b.Property("DeletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedByCascade")
+ .HasColumnType("boolean")
+ .HasColumnName("deleted_by_cascade");
+
+ b.Property("DeletedById")
+ .HasColumnType("integer")
+ .HasColumnName("deleted_by_id");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Rank")
+ .IsRequired()
+ .HasMaxLength(12)
+ .HasColumnType("character varying(12)")
+ .HasColumnName("rank");
+
+ b.Property("SwimlaneId")
+ .HasColumnType("integer")
+ .HasColumnName("swimlane_id");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedById")
+ .HasColumnType("integer")
+ .HasColumnName("updated_by_id");
+
+ b.Property("Width")
+ .HasColumnType("integer")
+ .HasColumnName("width");
+
+ b.HasKey("Id")
+ .HasName("pk_lists");
+
+ b.HasIndex("BoardId")
+ .HasDatabaseName("ix_lists_board_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("CreatedById")
+ .HasDatabaseName("ix_lists_created_by_id");
+
+ b.HasIndex("DeletedById")
+ .HasDatabaseName("ix_lists_deleted_by_id");
+
+ b.HasIndex("SwimlaneId")
+ .HasDatabaseName("ix_lists_swimlane_id")
+ .HasFilter("is_deleted = false");
+
+ b.HasIndex("UpdatedById")
+ .HasDatabaseName("ix_lists_updated_by_id");
+
+ b.HasIndex("SwimlaneId", "Rank")
+ .IsUnique()
+ .HasDatabaseName("ix_lists_swimlane_id_rank")
+ .HasFilter("is_deleted = false");
+
+ b.ToTable("lists", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Members.Member", b =>
+ {
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("UserId")
+ .HasColumnType("integer")
+ .HasColumnName("user_id");
+
+ b.Property("Role")
+ .HasColumnType("integer")
+ .HasColumnName("role");
+
+ b.HasKey("BoardId", "UserId")
+ .HasName("pk_board_members");
+
+ b.HasIndex("UserId")
+ .HasDatabaseName("ix_board_members_user_id");
+
+ b.HasIndex("BoardId", "Role")
+ .IsUnique()
+ .HasDatabaseName("ix_board_members_board_id_role")
+ .HasFilter("\"role\" = 0");
+
+ b.ToTable("board_members", "public");
+ });
+
+ modelBuilder.Entity("Snapflow.Domain.Swimlanes.Swimlane", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasColumnName("id");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BoardId")
+ .HasColumnType("integer")
+ .HasColumnName("board_id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property