diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87747a7a4..2c89a87c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: # context since the per-section split (nobodies-collective/Humans#858). run: | dotnet tool install --global dotnet-ef --version 10.0.* - for ctx in HumansDbContext SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext; do + for ctx in HumansDbContext SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext FinanceDbContext; do dotnet ef migrations has-pending-model-changes \ --context "$ctx" \ --project src/Humans.Infrastructure \ @@ -174,7 +174,7 @@ jobs: - name: Apply per-section baselines from scratch run: | set -euo pipefail - for ctx in SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext; do + for ctx in SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext FinanceDbContext; do db="humans_$(echo "$ctx" | tr '[:upper:]' '[:lower:]')" docker exec "${{ steps.pg.outputs.container }}" \ psql -U humans -d postgres -c "CREATE DATABASE $db" @@ -193,7 +193,7 @@ jobs: # Belt-and-suspenders: Layer 1 already runs this in the build job, # but re-checking after a real apply guards against any state the # apply step might have observed differently from a static check. - for ctx in HumansDbContext SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext; do + for ctx in HumansDbContext SystemSettingsDbContext ContainersDbContext AgentDbContext ExpensesDbContext FinanceDbContext; do dotnet ef migrations has-pending-model-changes \ --context "$ctx" \ --project src/Humans.Infrastructure \ diff --git a/src/Humans.Infrastructure/Data/FinanceDbContext.cs b/src/Humans.Infrastructure/Data/FinanceDbContext.cs new file mode 100644 index 000000000..b13ea5380 --- /dev/null +++ b/src/Humans.Infrastructure/Data/FinanceDbContext.cs @@ -0,0 +1,40 @@ +using Humans.Domain.Entities; +using Humans.Infrastructure.Data.Configurations.Finance; +using Microsoft.EntityFrameworkCore; + +namespace Humans.Infrastructure.Data; + +/// +/// Per-section database context for the Finance section +/// (nobodies-collective/Humans#858): maps only holded_expense_docs, +/// holded_category_map, holded_ledger_lines, +/// holded_creditor_contacts and holded_sync_states, with its own +/// __EFMigrationsHistory_Finance table and migrations under +/// Migrations/Finance/. Same database, same connection — the split +/// is a code-side partition of the EF model. +/// +/// +/// Internal-sealed like (issue #750): repositories +/// are the only consumers. Configurations are applied explicitly (not by +/// assembly scanning) so this model can never accrete another section's tables. +/// +internal sealed class FinanceDbContext(DbContextOptions options) + : DbContext(options) +{ + public DbSet HoldedExpenseDocs => Set(); + public DbSet HoldedCategoryMap => Set(); + public DbSet HoldedLedgerLines => Set(); + public DbSet HoldedCreditorContacts => Set(); + public DbSet HoldedSyncStates => Set(); + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.ApplyConfiguration(new HoldedExpenseDocConfiguration()); + builder.ApplyConfiguration(new HoldedCategoryMapConfiguration()); + builder.ApplyConfiguration(new HoldedLedgerLineConfiguration()); + builder.ApplyConfiguration(new HoldedCreditorContactConfiguration()); + builder.ApplyConfiguration(new HoldedSyncStateConfiguration()); + } +} diff --git a/src/Humans.Infrastructure/Data/FinanceDbContextFactory.cs b/src/Humans.Infrastructure/Data/FinanceDbContextFactory.cs new file mode 100644 index 000000000..b9330967e --- /dev/null +++ b/src/Humans.Infrastructure/Data/FinanceDbContextFactory.cs @@ -0,0 +1,33 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; + +namespace Humans.Infrastructure.Data; + +/// +/// Design-time factory used by dotnet ef … --context FinanceDbContext. +/// Mirrors ; the migrations-history table must +/// match the runtime registration so CI's from-scratch apply records baselines in +/// __EFMigrationsHistory_Finance. +/// +internal sealed class FinanceDbContextFactory : IDesignTimeDbContextFactory +{ + public FinanceDbContext CreateDbContext(string[] args) + { + var connectionString = + Environment.GetEnvironmentVariable("ConnectionStrings__DefaultConnection") + ?? "Host=localhost;Database=humans_design_time;Username=humans;Password=humans"; + + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseNpgsql( + connectionString, + npgsqlOptions => + { + npgsqlOptions.UseNodaTime(); + npgsqlOptions.MigrationsAssembly("Humans.Infrastructure"); + npgsqlOptions.MigrationsHistoryTable("__EFMigrationsHistory_Finance"); + npgsqlOptions.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); + }); + + return new FinanceDbContext(optionsBuilder.Options); + } +} diff --git a/src/Humans.Infrastructure/Data/HumansDbContext.cs b/src/Humans.Infrastructure/Data/HumansDbContext.cs index a9c9f7d17..44fd4000b 100644 --- a/src/Humans.Infrastructure/Data/HumansDbContext.cs +++ b/src/Humans.Infrastructure/Data/HumansDbContext.cs @@ -106,11 +106,6 @@ internal sealed class HumansDbContext(DbContextOptions options) public DbSet StorePayments => Set(); public DbSet StoreInvoices => Set(); public DbSet StoreTreasurySyncStates => Set(); - public DbSet HoldedExpenseDocs => Set(); - public DbSet HoldedCategoryMap => Set(); - public DbSet HoldedSyncStates => Set(); - public DbSet HoldedLedgerLines => Set(); - public DbSet HoldedCreditorContacts => Set(); // Survey section public DbSet Surveys => Set(); @@ -133,6 +128,7 @@ internal sealed class HumansDbContext(DbContextOptions options) typeof(Configurations.Containers.ContainerConfiguration).Namespace!, typeof(Configurations.Agent.AgentConversationConfiguration).Namespace!, typeof(Configurations.Expenses.ExpenseReportConfiguration).Namespace!, + typeof(Configurations.Finance.HoldedExpenseDocConfiguration).Namespace!, ]; protected override void OnModelCreating(ModelBuilder builder) diff --git a/src/Humans.Infrastructure/Hosting/InfrastructureServiceCollectionExtensions.cs b/src/Humans.Infrastructure/Hosting/InfrastructureServiceCollectionExtensions.cs index 3aba870dc..64eff01d8 100644 --- a/src/Humans.Infrastructure/Hosting/InfrastructureServiceCollectionExtensions.cs +++ b/src/Humans.Infrastructure/Hosting/InfrastructureServiceCollectionExtensions.cs @@ -50,6 +50,7 @@ public static IServiceCollection AddHumansPersistence( services.AddSectionDbContext(sentinelTable: "containers"); services.AddSectionDbContext(sentinelTable: "agent_conversations"); services.AddSectionDbContext(sentinelTable: "expense_reports"); + services.AddSectionDbContext(sentinelTable: "holded_expense_docs"); services.AddHostedService(); diff --git a/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.Designer.cs b/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.Designer.cs new file mode 100644 index 000000000..21492221e --- /dev/null +++ b/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.Designer.cs @@ -0,0 +1,6540 @@ +// +using System; +using Humans.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Humans.Infrastructure.Migrations +{ + [DbContext(typeof(HumansDbContext))] + [Migration("20260715103734_PeelFinance")] + partial class PeelFinance + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Humans.Domain.Entities.AccountMergeRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNotes") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PendingEmailId") + .HasColumnType("uuid"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedByUserId") + .HasColumnType("uuid"); + + b.Property("SourceUserId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TargetUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResolvedByUserId"); + + b.HasIndex("SourceUserId"); + + b.HasIndex("Status"); + + b.HasIndex("TargetUserId"); + + b.ToTable("account_merge_requests", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Application", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalInfo") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("BoardMeetingDate") + .HasColumnType("date"); + + b.Property("DecisionNote") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Language") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("MembershipTier") + .IsRequired() + .HasColumnType("text"); + + b.Property("Motivation") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("RenewalReminderSentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReviewNotes") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ReviewStartedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReviewedByUserId") + .HasColumnType("uuid"); + + b.Property("RoleUnderstanding") + .HasColumnType("text"); + + b.Property("SignificantContribution") + .HasColumnType("text"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("SubmittedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TermExpiresAt") + .HasColumnType("date"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MembershipTier"); + + b.HasIndex("ReviewedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("SubmittedAt"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "Status"); + + b.ToTable("applications", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ApplicationStateHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ChangedByUserId") + .HasColumnType("uuid"); + + b.Property("Notes") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("ChangedAt"); + + b.HasIndex("ChangedByUserId"); + + b.ToTable("application_state_history", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ActorUserId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ErrorMessage") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RelatedEntityId") + .HasColumnType("uuid"); + + b.Property("RelatedEntityType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ResourceId") + .HasColumnType("uuid"); + + b.Property("Role") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Success") + .HasColumnType("boolean"); + + b.Property("SyncSource") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UserEmail") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("Action"); + + b.HasIndex("ActorUserId"); + + b.HasIndex("OccurredAt"); + + b.HasIndex("ResourceId"); + + b.HasIndex("EntityType", "EntityId"); + + b.HasIndex("RelatedEntityType", "RelatedEntityId"); + + b.ToTable("audit_log", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BoardVote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationId") + .HasColumnType("uuid"); + + b.Property("BoardMemberUserId") + .HasColumnType("uuid"); + + b.Property("Note") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Vote") + .IsRequired() + .HasColumnType("text"); + + b.Property("VotedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId"); + + b.HasIndex("BoardMemberUserId"); + + b.HasIndex("ApplicationId", "BoardMemberUserId") + .IsUnique(); + + b.ToTable("board_votes", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetAuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActorUserId") + .HasColumnType("uuid"); + + b.Property("BudgetYearId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FieldName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NewValue") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OldValue") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("ActorUserId"); + + b.HasIndex("BudgetYearId"); + + b.HasIndex("OccurredAt"); + + b.HasIndex("EntityType", "EntityId"); + + b.ToTable("budget_audit_logs", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllocatedAmount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("BudgetGroupId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpenditureType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("TeamId") + .HasFilter("\"TeamId\" IS NOT NULL"); + + b.HasIndex("BudgetGroupId", "SortOrder"); + + b.ToTable("budget_categories", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BudgetYearId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDepartmentGroup") + .HasColumnType("boolean"); + + b.Property("IsRestricted") + .HasColumnType("boolean"); + + b.Property("IsTicketingGroup") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("BudgetYearId", "SortOrder"); + + b.ToTable("budget_groups", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetLineItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("BudgetCategoryId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ExpectedDate") + .HasColumnType("date"); + + b.Property("IsAutoGenerated") + .HasColumnType("boolean"); + + b.Property("IsCashflowOnly") + .HasColumnType("boolean"); + + b.Property("Notes") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ResponsibleTeamId") + .HasColumnType("uuid"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("VatRate") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ResponsibleTeamId") + .HasFilter("\"ResponsibleTeamId\" IS NOT NULL"); + + b.HasIndex("BudgetCategoryId", "SortOrder"); + + b.ToTable("budget_line_items", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetYear", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Year") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Status"); + + b.HasIndex("Year") + .IsUnique(); + + b.ToTable("budget_years", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CalendarEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("EndUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("IsAllDay") + .HasColumnType("boolean"); + + b.Property("Location") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("LocationUrl") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("OwningTeamId") + .HasColumnType("uuid"); + + b.Property("RecurrenceRule") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("RecurrenceTimezone") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("RecurrenceUntilUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("StartUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OwningTeamId", "StartUtc"); + + b.HasIndex("StartUtc", "RecurrenceUntilUtc"); + + b.ToTable("calendar_events", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CalendarEventException", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("EventId") + .HasColumnType("uuid"); + + b.Property("IsCancelled") + .HasColumnType("boolean"); + + b.Property("OriginalOccurrenceStartUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("OverrideDescription") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("OverrideEndUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("OverrideLocation") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("OverrideLocationUrl") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("OverrideStartUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("OverrideTitle") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EventId", "OriginalOccurrenceStartUtc") + .IsUnique(); + + b.ToTable("calendar_event_exceptions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Camp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ContactEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ContactPhone") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("HideHistoricalNames") + .HasColumnType("boolean"); + + b.Property("IsSwissCamp") + .HasColumnType("boolean"); + + b.Property("Links") + .HasColumnType("jsonb"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TimesAtNowhere") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WebOrSocialUrl") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("Slug") + .IsUnique(); + + b.ToTable("camps", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampHistoricalName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CampId"); + + b.ToTable("camp_historical_names", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampId") + .HasColumnType("uuid"); + + b.Property("ContentType") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("StoragePath") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("UploadedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CampId"); + + b.ToTable("camp_images", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampLead", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampId") + .HasColumnType("uuid"); + + b.Property("JoinedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LeftAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Role") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("CampId", "UserId") + .IsUnique() + .HasDatabaseName("IX_camp_leads_active_unique") + .HasFilter("\"LeftAt\" IS NULL"); + + b.ToTable("camp_leads", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampSeasonId") + .HasColumnType("uuid"); + + b.Property("ConfirmedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ConfirmedByUserId") + .HasColumnType("uuid"); + + b.Property("HasEarlyEntry") + .HasColumnType("boolean"); + + b.Property("RemovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RemovedByUserId") + .HasColumnType("uuid"); + + b.Property("RequestedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("CampSeasonId", "UserId") + .IsUnique() + .HasDatabaseName("IX_camp_members_active_unique") + .HasFilter("\"Status\" <> 'Removed'"); + + b.ToTable("camp_members", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampPolygon", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSqm") + .HasColumnType("double precision"); + + b.Property("CampSeasonId") + .HasColumnType("uuid"); + + b.Property("GeoJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedByUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CampSeasonId") + .IsUnique(); + + b.HasIndex("LastModifiedByUserId"); + + b.ToTable("camp_polygons", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampPolygonHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSqm") + .HasColumnType("double precision"); + + b.Property("CampSeasonId") + .HasColumnType("uuid"); + + b.Property("GeoJson") + .IsRequired() + .HasColumnType("text"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedByUserId") + .HasColumnType("uuid"); + + b.Property("Note") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.HasKey("Id"); + + b.HasIndex("ModifiedByUserId"); + + b.HasIndex("CampSeasonId", "ModifiedAt"); + + b.ToTable("camp_polygon_histories", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampRoleAssignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AssignedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AssignedByUserId") + .HasColumnType("uuid"); + + b.Property("CampMemberId") + .HasColumnType("uuid"); + + b.Property("CampRoleDefinitionId") + .HasColumnType("uuid"); + + b.Property("CampSeasonId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CampMemberId"); + + b.HasIndex("CampRoleDefinitionId"); + + b.HasIndex("CampSeasonId", "CampRoleDefinitionId", "CampMemberId") + .IsUnique() + .HasDatabaseName("IX_camp_role_assignments_unique"); + + b.ToTable("camp_role_assignments", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampRoleDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeactivatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("MinimumRequired") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SlotCount") + .HasColumnType("integer"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("character varying(60)"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("SpecialRole") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasDefaultValueSql("'None'"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("IX_camp_role_definitions_name_unique"); + + b.HasIndex("SortOrder"); + + b.ToTable("camp_role_definitions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AcceptingMembers") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("AdultPlayspace") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BlurbLong") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("BlurbShort") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CampId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EeSlotCount") + .HasColumnType("integer"); + + b.Property("ElectricalGrid") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("HasPerformanceSpace") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("KidsAreaDescription") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("KidsVisiting") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("KidsWelcome") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Languages") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("MemberCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NameLockDate") + .HasColumnType("date"); + + b.Property("NameLockedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PerformanceTypes") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReviewNotes") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ReviewedByUserId") + .HasColumnType("uuid"); + + b.Property("SoundZone") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("SpaceRequirement") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Vibes") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ReviewedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("CampId", "Year") + .IsUnique(); + + b.ToTable("camp_seasons", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EeStartDate") + .HasColumnType("date"); + + b.Property("OpenSeasons") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("PublicYear") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("camp_settings", (string)null); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0010-000000000001"), + OpenSeasons = "[2026]", + PublicYear = 2026 + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Campaign", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("EmailBodyTemplate") + .IsRequired() + .HasColumnType("text"); + + b.Property("EmailSubject") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("ReplyToAddress") + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.ToTable("campaigns", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampaignId") + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ImportOrder") + .HasColumnType("integer"); + + b.Property("ImportedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CampaignId", "Code") + .IsUnique(); + + b.ToTable("campaign_codes", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AssignedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CampaignCodeId") + .HasColumnType("uuid"); + + b.Property("CampaignId") + .HasColumnType("uuid"); + + b.Property("LatestEmailAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LatestEmailStatus") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("RedeemedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CampaignCodeId") + .IsUnique(); + + b.HasIndex("UserId"); + + b.HasIndex("CampaignId", "UserId") + .IsUnique(); + + b.ToTable("campaign_grants", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CityPlanningSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClosedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ContainerPlacementClosedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ContainerPlacementOpenedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsContainerPlacementOpen") + .HasColumnType("boolean"); + + b.Property("IsPlacementOpen") + .HasColumnType("boolean"); + + b.Property("LimitZoneGeoJson") + .HasColumnType("text"); + + b.Property("OfficialZonesGeoJson") + .HasColumnType("text"); + + b.Property("OpenedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PlacementClosesAt") + .HasColumnType("timestamp without time zone"); + + b.Property("PlacementOpensAt") + .HasColumnType("timestamp without time zone"); + + b.Property("RegistrationInfo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Year") + .IsUnique(); + + b.ToTable("city_planning_settings", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CommunicationPreference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("InboxEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("OptedOut") + .HasColumnType("boolean"); + + b.Property("SubscribedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("SubscribedAt"); + + b.Property("UpdateSource") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "Category") + .IsUnique(); + + b.ToTable("communication_preferences", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ConsentRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConsentedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ContentHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("DocumentVersionId") + .HasColumnType("uuid"); + + b.Property("ExplicitConsent") + .HasColumnType("boolean"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("character varying(45)"); + + b.Property("UserAgent") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ConsentedAt"); + + b.HasIndex("DocumentVersionId"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "DocumentVersionId") + .IsUnique(); + + b.HasIndex("UserId", "ExplicitConsent", "ConsentedAt"); + + b.ToTable("consent_records", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ContactField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomLabel") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("FieldType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ProfileId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Visibility") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId"); + + b.HasIndex("ProfileId", "Visibility"); + + b.ToTable("contact_fields", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.DocumentVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangesSummary") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("CommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Content") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EffectiveFrom") + .HasColumnType("timestamp with time zone"); + + b.Property("LegalDocumentId") + .HasColumnType("uuid"); + + b.Property("RequiresReConsent") + .HasColumnType("boolean"); + + b.Property("VersionNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("CommitSha"); + + b.HasIndex("EffectiveFrom"); + + b.HasIndex("LegalDocumentId"); + + b.ToTable("document_versions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EmailOutboxMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampaignGrantId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExtraHeaders") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("HtmlBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastError") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("NextRetryAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PickedUpAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PlainTextBody") + .HasColumnType("text"); + + b.Property("RecipientEmail") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("RecipientName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ReplyTo") + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ShiftSignupId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Subject") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TemplateName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CampaignGrantId"); + + b.HasIndex("UserId"); + + b.HasIndex("ShiftSignupId", "TemplateName") + .HasFilter("\"ShiftSignupId\" IS NOT NULL"); + + b.HasIndex("SentAt", "RetryCount", "NextRetryAt", "PickedUpAt"); + + b.ToTable("email_outbox_messages", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Event", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNotes") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CampId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("DurationMinutes") + .HasColumnType("integer"); + + b.Property("GuideSharedVenueId") + .HasColumnType("uuid"); + + b.Property("Host") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("IsRecurring") + .HasColumnType("boolean"); + + b.Property("LastUpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LocationNote") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("PriorityRank") + .HasColumnType("integer"); + + b.Property("RecurrenceDays") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("StartAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("SubmittedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SubmitterUserId") + .HasColumnType("uuid"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.HasKey("Id"); + + b.HasIndex("CampId"); + + b.HasIndex("CategoryId"); + + b.HasIndex("GuideSharedVenueId"); + + b.HasIndex("Status"); + + b.HasIndex("SubmitterUserId"); + + b.ToTable("events", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsSensitive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("character varying(60)"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(60) + .HasColumnType("character varying(60)"); + + b.HasKey("Id"); + + b.HasIndex("IsActive"); + + b.HasIndex("Slug") + .IsUnique(); + + b.ToTable("event_categories", (string)null); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0026-000000000001"), + DisplayOrder = 1, + IsActive = true, + IsSensitive = false, + Name = "Workshop", + Slug = "workshop" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000002"), + DisplayOrder = 2, + IsActive = true, + IsSensitive = false, + Name = "Party", + Slug = "party" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000003"), + DisplayOrder = 3, + IsActive = true, + IsSensitive = false, + Name = "Food and drink", + Slug = "food-and-drink" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000004"), + DisplayOrder = 4, + IsActive = true, + IsSensitive = false, + Name = "Chillout", + Slug = "chillout" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000005"), + DisplayOrder = 5, + IsActive = true, + IsSensitive = true, + Name = "Spiritual / Healing", + Slug = "spiritual-healing" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000007"), + DisplayOrder = 6, + IsActive = true, + IsSensitive = true, + Name = "Adults", + Slug = "adults" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000008"), + DisplayOrder = 7, + IsActive = true, + IsSensitive = false, + Name = "Kids", + Slug = "kids" + }, + new + { + Id = new Guid("00000000-0000-0000-0026-000000000006"), + DisplayOrder = 8, + IsActive = true, + IsSensitive = false, + Name = "Other", + Slug = "other" + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventFavourite", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOffset") + .HasColumnType("integer"); + + b.Property("GuideEventId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GuideEventId"); + + b.HasIndex("UserId", "GuideEventId", "DayOffset") + .IsUnique(); + + NpgsqlIndexBuilderExtensions.AreNullsDistinct(b.HasIndex("UserId", "GuideEventId", "DayOffset"), false); + + b.ToTable("event_favourites", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventGuideSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EventSettingsId") + .HasColumnType("uuid"); + + b.Property("GuidePublishAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MaxPrintSlots") + .HasColumnType("integer"); + + b.Property("SubmissionCloseAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SubmissionOpenAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EventSettingsId") + .IsUnique(); + + b.ToTable("event_guide_settings", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventModerationAction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("ActorUserId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("GuideEventId") + .HasColumnType("uuid"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.HasKey("Id"); + + b.HasIndex("GuideEventId"); + + b.ToTable("event_moderation_actions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventParticipation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CheckedInAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeclaredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Year") + .IsUnique(); + + b.ToTable("event_participations", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventPreference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ExcludedCategorySlugs") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("event_preferences", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BarriosEarlyEntryAllocation") + .HasColumnType("jsonb"); + + b.Property("BuildStartOffset") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EarlyEntryCapacity") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EarlyEntryClose") + .HasColumnType("timestamp with time zone"); + + b.Property("EventEndOffset") + .HasColumnType("integer"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("FinishingWeekendStartOffset") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(-4); + + b.Property("FirstCrewStartOffset") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(-25); + + b.Property("GateOpeningDate") + .HasColumnType("date"); + + b.Property("GlobalVolunteerCap") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsShiftBrowsingOpen") + .HasColumnType("boolean"); + + b.Property("PreEventWeekStartOffset") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(-9); + + b.Property("ReminderLeadTimeHours") + .HasColumnType("integer"); + + b.Property("SetupWeekStartOffset") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(-16); + + b.Property("StrikeEndOffset") + .HasColumnType("integer"); + + b.Property("TimeZoneId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IsActive"); + + b.ToTable("event_settings", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventVenue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("DisplayOrder") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LocationDescription") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.HasKey("Id"); + + b.HasIndex("IsActive"); + + b.ToTable("event_venues", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.FeedbackMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(5000) + .HasColumnType("character varying(5000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FeedbackReportId") + .HasColumnType("uuid"); + + b.Property("SenderUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("FeedbackReportId"); + + b.HasIndex("SenderUserId"); + + b.ToTable("feedback_messages", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.FeedbackReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalContext") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("AgentConversationId") + .HasColumnType("uuid"); + + b.Property("AssignedToTeamId") + .HasColumnType("uuid"); + + b.Property("AssignedToUserId") + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(5000) + .HasColumnType("character varying(5000)"); + + b.Property("GitHubIssueNumber") + .HasColumnType("integer"); + + b.Property("LastAdminMessageAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastReporterMessageAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PageUrl") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedByUserId") + .HasColumnType("uuid"); + + b.Property("ScreenshotContentType") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ScreenshotFileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ScreenshotStoragePath") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Source") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasDefaultValueSql("'UserReport'"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserAgent") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AgentConversationId"); + + b.HasIndex("AssignedToTeamId"); + + b.HasIndex("AssignedToUserId"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("ResolvedByUserId"); + + b.HasIndex("Source"); + + b.HasIndex("Status"); + + b.HasIndex("UserId"); + + b.ToTable("feedback_reports", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GateScanEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdmitDedupeKey") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("Barcode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ClientScanAt") + .HasColumnType("timestamp with time zone"); + + b.Property("GuestUserId") + .HasColumnType("uuid"); + + b.Property("LaneId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Note") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("OverrideByUserId") + .HasColumnType("uuid"); + + b.Property("ScannedByUserId") + .HasColumnType("uuid"); + + b.Property("TicketAttendeeId") + .HasColumnType("uuid"); + + b.Property("Verdict") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.HasKey("Id"); + + b.HasIndex("AdmitDedupeKey") + .IsUnique() + .HasDatabaseName("ix_gate_scan_events_admit_dedupe_key"); + + b.HasIndex("OccurredAt"); + + b.HasIndex("ScannedByUserId"); + + b.ToTable("gate_scan_events", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GateSettings", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("GeneralEntryOpensAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MinorAgeThresholdYears") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("gate_settings", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GateStaffPin", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("AdminEnrolled") + .HasColumnType("boolean"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PinHash") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("UserId"); + + b.ToTable("gate_staff_pins", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GeneralAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.PrimitiveCollection("AvailableDayOffsets") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EventSettingsId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EventSettingsId"); + + b.HasIndex("UserId", "EventSettingsId") + .IsUnique(); + + b.ToTable("general_availability", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GoogleResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DrivePermissionLevel") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ErrorMessage") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("GoogleId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ProvisionedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResourceType") + .IsRequired() + .HasColumnType("text"); + + b.Property("RestrictInheritedAccess") + .HasColumnType("boolean"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("Url") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.HasKey("Id"); + + b.HasIndex("GoogleId"); + + b.HasIndex("IsActive"); + + b.HasIndex("TeamId"); + + b.HasIndex("TeamId", "GoogleId") + .IsUnique() + .HasFilter("\"IsActive\" = true"); + + b.ToTable("google_resources", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GoogleSyncOutboxEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DeduplicationKey") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EventType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FailedPermanently") + .HasColumnType("boolean"); + + b.Property("LastError") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("OccurredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DeduplicationKey") + .IsUnique(); + + b.HasIndex("UserId"); + + b.HasIndex("ProcessedAt", "OccurredAt"); + + b.HasIndex("TeamId", "UserId", "ProcessedAt"); + + b.ToTable("google_sync_outbox", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Issue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalContext") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("AssigneeUserId") + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(5000) + .HasColumnType("character varying(5000)"); + + b.Property("DueDate") + .HasColumnType("date"); + + b.Property("GitHubIssueNumber") + .HasColumnType("integer"); + + b.Property("PageUrl") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ReporterUserId") + .HasColumnType("uuid"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedByUserId") + .HasColumnType("uuid"); + + b.Property("ScreenshotContentType") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ScreenshotFileName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ScreenshotStoragePath") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("Section") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserAgent") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.HasKey("Id"); + + b.HasIndex("AssigneeUserId"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("ReporterUserId"); + + b.HasIndex("ResolvedByUserId"); + + b.HasIndex("Section"); + + b.HasIndex("Status"); + + b.HasIndex("Section", "Status"); + + b.ToTable("issues", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.IssueComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(5000) + .HasColumnType("character varying(5000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IssueId") + .HasColumnType("uuid"); + + b.Property("SenderUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("IssueId"); + + b.HasIndex("SenderUserId"); + + b.ToTable("issue_comments", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.LegalDocument", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentCommitSha") + .IsRequired() + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("GitHubFolderPath") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("GracePeriodDays") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(7); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsRequired") + .HasColumnType("boolean"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("IsActive"); + + b.HasIndex("TeamId", "IsActive"); + + b.ToTable("legal_documents", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActionLabel") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ActionUrl") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Body") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Class") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedByUserId") + .HasColumnType("uuid"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("SourceKey") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("TargetGroupName") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("CreatedAt"); + + b.HasIndex("ResolvedByUserId"); + + b.ToTable("notifications", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.NotificationRecipient", b => + { + b.Property("NotificationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ReadAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("NotificationId", "UserId"); + + b.HasIndex("UserId") + .HasDatabaseName("IX_NotificationRecipient_UserId"); + + b.ToTable("notification_recipients", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Profile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNotes") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Allergies") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("AllergyOtherText") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Bio") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("BoardNotes") + .HasColumnType("text"); + + b.Property("BurnerName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("City") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ConsentCheckAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ConsentCheckNotes") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ConsentCheckStatus") + .HasColumnType("text"); + + b.Property("ConsentCheckedByUserId") + .HasColumnType("uuid"); + + b.Property("ContributionInterests") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DateOfBirth") + .HasColumnType("date"); + + b.Property("DietaryPreference") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EmergencyContactName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmergencyContactPhone") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("EmergencyContactRelationship") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Iban") + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("IntoleranceOtherText") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Intolerances") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("IsApproved") + .HasColumnType("boolean"); + + b.Property("IsSuspended") + .HasColumnType("boolean"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Latitude") + .HasColumnType("double precision"); + + b.Property("Longitude") + .HasColumnType("double precision"); + + b.Property("MedicalConditions") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("MembershipTier") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("Volunteer"); + + b.Property("NoPriorBurnExperience") + .HasColumnType("boolean"); + + b.Property("PlaceId") + .HasMaxLength(512) + .HasColumnType("character varying(512)"); + + b.Property("ProfilePictureContentType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ProfilePictureData") + .HasColumnType("bytea"); + + b.Property("Pronouns") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("RejectedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RejectedByUserId") + .HasColumnType("uuid"); + + b.Property("RejectionReason") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("State") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ConsentCheckStatus"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("profiles", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ProfileLanguage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("LanguageCode") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Proficiency") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ProfileId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId"); + + b.ToTable("profile_languages", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.RoleAssignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("Notes") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("ValidFrom") + .HasColumnType("timestamp with time zone"); + + b.Property("ValidTo") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("RoleName"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "RoleName") + .HasFilter("\"ValidTo\" IS NULL"); + + b.HasIndex("UserId", "RoleName", "ValidFrom"); + + b.ToTable("role_assignments", null, t => + { + t.HasCheckConstraint("CK_role_assignments_valid_window", "\"ValidTo\" IS NULL OR \"ValidTo\" > \"ValidFrom\""); + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Rota", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("EventSettingsId") + .HasColumnType("uuid"); + + b.Property("IsVisibleToVolunteers") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Period") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Policy") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PracticalInfo") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.HasIndex("EventSettingsId", "TeamId"); + + b.ToTable("rotas", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Shift", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminOnly") + .HasColumnType("boolean"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOffset") + .HasColumnType("integer"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Duration") + .HasColumnType("bigint"); + + b.Property("IsAllDay") + .HasColumnType("boolean"); + + b.Property("MaxVolunteers") + .HasColumnType("integer"); + + b.Property("MinVolunteers") + .HasColumnType("integer"); + + b.Property("RotaId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("time"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("RotaId"); + + b.ToTable("shifts", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ShiftSignup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Enrolled") + .HasColumnType("boolean"); + + b.Property("EnrolledByUserId") + .HasColumnType("uuid"); + + b.Property("ReviewedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReviewedByUserId") + .HasColumnType("uuid"); + + b.Property("ShiftId") + .HasColumnType("uuid"); + + b.Property("SignupBlockId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("StatusReason") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EnrolledByUserId"); + + b.HasIndex("ReviewedByUserId"); + + b.HasIndex("ShiftId"); + + b.HasIndex("SignupBlockId"); + + b.HasIndex("UserId"); + + b.HasIndex("ShiftId", "Status"); + + b.ToTable("shift_signups", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ShiftTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("IX_shift_tags_name_unique"); + + b.ToTable("shift_tags", (string)null); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0003-000000000001"), + Name = "Heavy lifting" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000002"), + Name = "Working in the sun" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000003"), + Name = "Working in the shade" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000004"), + Name = "Organisational task" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000005"), + Name = "Meeting new people" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000006"), + Name = "Looking after folks" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000007"), + Name = "Exploring the site" + }, + new + { + Id = new Guid("00000000-0000-0000-0003-000000000008"), + Name = "Feeding and hydrating folks" + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreInvoice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("HoldedDocId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("HoldedDocNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IssuedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IssuedByUserId") + .HasColumnType("uuid"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("RequestPayload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("ResponsePayload") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("Id"); + + b.HasIndex("HoldedDocId") + .IsUnique(); + + b.HasIndex("OrderId") + .IsUnique(); + + b.ToTable("store_invoices", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CampSeasonId") + .HasColumnType("uuid"); + + b.Property("CounterpartyAddress") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CounterpartyCountryCode") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("CounterpartyEmail") + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("CounterpartyName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("CounterpartyVatId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IssuedInvoiceId") + .HasColumnType("uuid"); + + b.Property("Label") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CampSeasonId"); + + b.HasIndex("State"); + + b.HasIndex("TeamId"); + + b.ToTable("store_orders", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreOrderLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AddedByUserId") + .HasColumnType("uuid"); + + b.Property("DepositAmountSnapshot") + .HasColumnType("numeric(12,2)"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("ProductId") + .HasColumnType("uuid"); + + b.Property("Qty") + .HasColumnType("integer"); + + b.Property("UnitPriceSnapshot") + .HasColumnType("numeric(12,2)"); + + b.Property("VatRateSnapshot") + .HasColumnType("numeric(5,2)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("ProductId"); + + b.ToTable("store_order_lines", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StorePayment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AmountEur") + .HasColumnType("numeric(12,2)"); + + b.Property("ExternalRef") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Method") + .HasColumnType("integer"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("ReceivedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordedByUserId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("StripePaymentIntentId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("OrderId"); + + b.HasIndex("StripePaymentIntentId") + .IsUnique() + .HasFilter("\"StripePaymentIntentId\" IS NOT NULL"); + + b.ToTable("store_payments", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreProduct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DepositAmountEur") + .HasColumnType("numeric(12,2)"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("OrderableUntil") + .HasColumnType("date"); + + b.Property("UnitPriceEur") + .HasColumnType("numeric(12,2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("VatRatePercent") + .HasColumnType("numeric(5,2)"); + + b.Property("Year") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Year", "IsActive"); + + b.ToTable("store_products", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreTreasurySyncState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastError") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("LastSyncAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SyncStatus") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("store_treasury_sync_state", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Survey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowAnonymous") + .HasColumnType("boolean"); + + b.Property("AudienceLoggedInSince") + .HasColumnType("timestamp with time zone"); + + b.Property("AudienceTeamId") + .HasColumnType("uuid"); + + b.Property("AudienceType") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ClosesAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("DefaultCulture") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Intro") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("OpensAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PublicSlug") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PublicStartedCount") + .HasColumnType("integer"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ThankYou") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("Title") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("PublicSlug") + .IsUnique() + .HasFilter("\"PublicSlug\" IS NOT NULL"); + + b.HasIndex("Status"); + + b.ToTable("surveys", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("RatingValue") + .HasColumnType("integer"); + + b.Property("ResponseId") + .HasColumnType("uuid"); + + b.Property("SelectedOptionValues") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TextValue") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.HasIndex("ResponseId"); + + b.ToTable("survey_answers", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyInvitation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Completed") + .HasColumnType("boolean"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LatestEmailStatus") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ReminderSentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Started") + .HasColumnType("boolean"); + + b.Property("SurveyId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId", "UserId") + .IsUnique(); + + b.HasIndex("SurveyId", "Completed", "SentAt"); + + b.ToTable("survey_invitations", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("HelpText") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("IsRequired") + .HasColumnType("boolean"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("PageNumber") + .HasColumnType("integer"); + + b.Property("Prompt") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("RatingMax") + .HasColumnType("integer"); + + b.Property("RatingMaxLabel") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("RatingMin") + .HasColumnType("integer"); + + b.Property("RatingMinLabel") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("ShowIf") + .HasColumnType("jsonb"); + + b.Property("SurveyId") + .HasColumnType("uuid"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId", "PageNumber", "Order"); + + b.ToTable("survey_questions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyQuestionOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Label") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'{}'::jsonb"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("QuestionId") + .HasColumnType("uuid"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId", "Order"); + + b.ToTable("survey_question_options", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Anonymity") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Culture") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("InputMethod") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("InvitationId") + .HasColumnType("uuid"); + + b.Property("SubmittedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SurveyId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("InvitationId"); + + b.HasIndex("SurveyId"); + + b.HasIndex("SurveyId", "UserId"); + + b.ToTable("survey_responses", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SyncServiceSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ServiceType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("SyncMode") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedByUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ServiceType") + .IsUnique(); + + b.HasIndex("UpdatedByUserId"); + + b.ToTable("sync_service_settings", (string)null); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0002-000000000001"), + ServiceType = "GoogleDrive", + SyncMode = "None", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17730144000000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0002-000000000002"), + ServiceType = "GoogleGroups", + SyncMode = "None", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17730144000000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0002-000000000003"), + ServiceType = "Discord", + SyncMode = "None", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17730144000000000L) + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Team", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CallsToAction") + .HasColumnType("jsonb"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CustomSlug") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("EarlyEntryEnabled") + .HasColumnType("boolean"); + + b.Property("GoogleGroupPrefix") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("HasBudget") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsHidden") + .HasColumnType("boolean"); + + b.Property("IsPromotedToDirectory") + .HasColumnType("boolean"); + + b.Property("IsPublicPage") + .HasColumnType("boolean"); + + b.Property("IsSensitive") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PageContent") + .HasMaxLength(50000) + .HasColumnType("character varying(50000)"); + + b.Property("PageContentUpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("PageContentUpdatedByUserId") + .HasColumnType("uuid"); + + b.Property("ParentTeamId") + .HasColumnType("uuid"); + + b.Property("RequiresApproval") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("ShowCoordinatorsOnPublicPage") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("SystemTeamType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CustomSlug") + .IsUnique() + .HasFilter("\"CustomSlug\" IS NOT NULL"); + + b.HasIndex("GoogleGroupPrefix") + .IsUnique() + .HasFilter("\"GoogleGroupPrefix\" IS NOT NULL"); + + b.HasIndex("IsActive"); + + b.HasIndex("ParentTeamId"); + + b.HasIndex("Slug") + .IsUnique(); + + b.HasIndex("SystemTeamType"); + + b.ToTable("teams", (string)null); + + b.HasData( + new + { + Id = new Guid("00000000-0000-0000-0001-000000000001"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "All active volunteers with signed required documents", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Volunteers", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "volunteers", + SystemTeamType = "Volunteers", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0001-000000000002"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "All team coordinators", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Coordinators", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "coordinators", + SystemTeamType = "Coordinators", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0001-000000000003"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "Board members with active role assignments", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Board", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "board", + SystemTeamType = "Board", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0001-000000000004"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "Voting members with approved asociado applications", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Asociados", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "asociados", + SystemTeamType = "Asociados", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0001-000000000005"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "Active contributors with approved colaborador applications", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Colaboradors", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "colaboradors", + SystemTeamType = "Colaboradors", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }, + new + { + Id = new Guid("00000000-0000-0000-0001-000000000006"), + CreatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L), + Description = "All active camp leads across all camps", + EarlyEntryEnabled = false, + HasBudget = false, + IsActive = true, + IsHidden = false, + IsPromotedToDirectory = false, + IsPublicPage = false, + IsSensitive = false, + Name = "Barrio Leads", + RequiresApproval = false, + ShowCoordinatorsOnPublicPage = true, + Slug = "barrio-leads", + SystemTeamType = "BarrioLeads", + UpdatedAt = NodaTime.Instant.FromUnixTimeTicks(17702491570000000L) + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamEarlyEntryGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByUserId") + .HasColumnType("uuid"); + + b.Property("EntryDate") + .HasColumnType("date"); + + b.Property("ProjectName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.HasIndex("UserId"); + + b.ToTable("team_early_entry_grants", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamJoinRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Message") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("RequestedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResolvedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReviewNotes") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("ReviewedByUserId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ReviewedByUserId"); + + b.HasIndex("Status"); + + b.HasIndex("TeamId"); + + b.HasIndex("UserId"); + + b.HasIndex("TeamId", "UserId", "Status"); + + b.ToTable("team_join_requests", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamJoinRequestStateHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ChangedByUserId") + .HasColumnType("uuid"); + + b.Property("Notes") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("TeamJoinRequestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ChangedAt"); + + b.HasIndex("ChangedByUserId"); + + b.HasIndex("TeamJoinRequestId"); + + b.ToTable("team_join_request_state_history", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("JoinedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LeftAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Role") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Role"); + + b.HasIndex("UserId"); + + b.HasIndex("TeamId", "UserId") + .IsUnique() + .HasDatabaseName("IX_team_members_active_unique") + .HasFilter("\"LeftAt\" IS NULL"); + + b.ToTable("team_members", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamRoleAssignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AssignedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AssignedByUserId") + .HasColumnType("uuid"); + + b.Property("SlotIndex") + .HasColumnType("integer"); + + b.Property("TeamMemberId") + .HasColumnType("uuid"); + + b.Property("TeamRoleDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AssignedByUserId"); + + b.HasIndex("TeamMemberId"); + + b.HasIndex("TeamRoleDefinitionId", "SlotIndex") + .IsUnique() + .HasDatabaseName("IX_team_role_assignments_definition_slot_unique"); + + b.HasIndex("TeamRoleDefinitionId", "TeamMemberId") + .IsUnique() + .HasDatabaseName("IX_team_role_assignments_definition_member_unique"); + + b.ToTable("team_role_assignments", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamRoleDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("EstimatedHours") + .HasColumnType("integer"); + + b.Property("IsManagement") + .HasColumnType("boolean"); + + b.Property("IsPublic") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Period") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Priorities") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(500) + .HasColumnType("character varying(500)") + .HasDefaultValueSql("''"); + + b.Property("SlotCount") + .HasColumnType("integer"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("TeamId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("TeamId"); + + b.HasIndex("TeamId", "Name") + .IsUnique() + .HasDatabaseName("IX_team_role_definitions_team_name_unique"); + + b.ToTable("team_role_definitions", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketAttendee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttendeeEmail") + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("AttendeeName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Barcode") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CheckedInAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MatchedUserId") + .HasColumnType("uuid"); + + b.Property("Price") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("SyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TicketOrderId") + .HasColumnType("uuid"); + + b.Property("TicketTypeName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("VendorEventId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("VendorTicketId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("AttendeeEmail"); + + b.HasIndex("Barcode"); + + b.HasIndex("MatchedUserId"); + + b.HasIndex("TicketOrderId"); + + b.HasIndex("VendorTicketId") + .IsUnique(); + + b.ToTable("ticket_attendees", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketOrder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApplicationFee") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("BuyerEmail") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("BuyerName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("DiscountAmount") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("DiscountCode") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("DonationAmount") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("MatchedUserId") + .HasColumnType("uuid"); + + b.Property("PaymentMethod") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PaymentMethodDetail") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PaymentStatus") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("PurchasedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("StripeFee") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("StripePaymentIntentId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TotalAmount") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("VatAmount") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("VendorDashboardUrl") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("VendorEventId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("VendorOrderId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("BuyerEmail"); + + b.HasIndex("MatchedUserId"); + + b.HasIndex("PaymentMethod"); + + b.HasIndex("PurchasedAt"); + + b.HasIndex("VendorOrderId") + .IsUnique(); + + b.ToTable("ticket_orders", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketSyncState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastError") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("LastSyncAt") + .HasColumnType("timestamp with time zone"); + + b.Property("StatusChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SyncStatus") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("VendorEventId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("ticket_sync_state", (string)null); + + b.HasData( + new + { + Id = 1, + SyncStatus = "Idle", + VendorEventId = "" + }); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketTransferRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNotes") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("DecidedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DecidedByUserId") + .HasColumnType("uuid"); + + b.Property("NewVendorTicketId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("OriginalTicketAttendeeId") + .HasColumnType("uuid"); + + b.Property("ReceiverEmail") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("ReceiverLegalName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ReceiverUserId") + .HasColumnType("uuid"); + + b.Property("RequestedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SenderReason") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("SenderUserId") + .HasColumnType("uuid"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("VendorHoldId") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("VendorMessage") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("VendorResult") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("VendorStepsJson") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("text") + .HasDefaultValue("[]"); + + b.HasKey("Id"); + + b.HasIndex("OriginalTicketAttendeeId"); + + b.HasIndex("Status"); + + b.HasIndex("SenderUserId", "Status"); + + b.ToTable("ticket_transfer_requests", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketingProjection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AverageTicketPrice") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("BudgetGroupId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DailySalesRate") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("EventDate") + .HasColumnType("date"); + + b.Property("InitialSalesCount") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("StripeFeeFixed") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("StripeFeePercent") + .HasPrecision(18, 4) + .HasColumnType("numeric(18,4)"); + + b.Property("TicketTailorFeePercent") + .HasPrecision(18, 4) + .HasColumnType("numeric(18,4)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("VatRate") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BudgetGroupId") + .IsUnique(); + + b.ToTable("ticketing_projections", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("ContactSource") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletionEligibleAfter") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletionRequestedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletionScheduledFor") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("ExternalSourceId") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GoogleEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("GoogleEmail"); + + b.Property("GoogleEmailStatus") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasDefaultValue("Unknown"); + + b.Property("ICalToken") + .HasColumnType("uuid"); + + b.Property("LastConsentReminderSentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("MagicLinkSentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MergedToUserId") + .HasColumnType("uuid"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("PreferredLanguage") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasDefaultValue("en"); + + b.Property("ProfilePictureUrl") + .HasMaxLength(2048) + .HasColumnType("character varying(2048)"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("State") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("SuppressScheduleChangeEmails") + .HasColumnType("boolean"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UnsubscribedFromCampaigns") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("MergedToUserId") + .HasFilter("\"MergedToUserId\" IS NOT NULL"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("ContactSource", "ExternalSourceId") + .HasFilter("\"ExternalSourceId\" IS NOT NULL"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.UserEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayOrder") + .HasColumnType("integer") + .HasColumnName("DisplayOrder"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GoogleEmailStatus") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasDefaultValue("Unknown"); + + b.Property("IsGoogle") + .HasColumnType("boolean"); + + b.Property("IsOAuth") + .HasColumnType("boolean") + .HasColumnName("IsOAuth"); + + b.Property("IsPrimary") + .HasColumnType("boolean") + .HasColumnName("IsNotificationTarget"); + + b.Property("IsVerified") + .HasColumnType("boolean"); + + b.Property("Provider") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("ProviderKey") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("VerificationSentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Visibility") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique() + .HasFilter("\"IsVerified\" = true"); + + b.HasIndex("UserId"); + + b.ToTable("user_emails", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerBuildStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BarrioSetupStartDate") + .HasColumnType("date"); + + b.Property("DayOffs") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValueSql("'[]'::jsonb"); + + b.Property("EventSettingsId") + .HasColumnType("uuid"); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("SetAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SetByUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EventSettingsId"); + + b.HasIndex("UserId", "EventSettingsId") + .IsUnique(); + + b.ToTable("volunteer_build_statuses", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerEventProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Allergies") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("AllergyOtherText") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DietaryPreference") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IntoleranceOtherText") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Intolerances") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Languages") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("MedicalConditions") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("Quirks") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Skills") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("volunteer_event_profiles", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerHistoryEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Date") + .HasColumnType("date"); + + b.Property("Description") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ProfileId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ProfileId"); + + b.ToTable("volunteer_history_entries", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerTagPreference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ShiftTagId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ShiftTagId"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "ShiftTagId") + .IsUnique() + .HasDatabaseName("IX_volunteer_tag_preferences_user_tag_unique"); + + b.ToTable("volunteer_tag_preferences", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("text"); + + b.Property("Xml") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("roles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("role_claims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("user_claims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("user_logins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("user_roles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("user_tokens", (string)null); + }); + + modelBuilder.Entity("RotaShiftTag", b => + { + b.Property("RotaId") + .HasColumnType("uuid"); + + b.Property("ShiftTagId") + .HasColumnType("uuid"); + + b.HasKey("RotaId", "ShiftTagId"); + + b.HasIndex("ShiftTagId"); + + b.ToTable("rota_shift_tags", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.AccountMergeRequest", b => + { + b.HasOne("Humans.Domain.Entities.User", "ResolvedByUser") + .WithMany() + .HasForeignKey("ResolvedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", "SourceUser") + .WithMany() + .HasForeignKey("SourceUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "TargetUser") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResolvedByUser"); + + b.Navigation("SourceUser"); + + b.Navigation("TargetUser"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Application", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ReviewedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ApplicationStateHistory", b => + { + b.HasOne("Humans.Domain.Entities.Application", "Application") + .WithMany("StateHistory") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.AuditLogEntry", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ActorUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.GoogleResource", "Resource") + .WithMany() + .HasForeignKey("ResourceId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Resource"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BoardVote", b => + { + b.HasOne("Humans.Domain.Entities.Application", "Application") + .WithMany("BoardVotes") + .HasForeignKey("ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("BoardMemberUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetAuditLog", b => + { + b.HasOne("Humans.Domain.Entities.User", "ActorUser") + .WithMany() + .HasForeignKey("ActorUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.BudgetYear", "BudgetYear") + .WithMany("AuditLogs") + .HasForeignKey("BudgetYearId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ActorUser"); + + b.Navigation("BudgetYear"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetCategory", b => + { + b.HasOne("Humans.Domain.Entities.BudgetGroup", "BudgetGroup") + .WithMany("Categories") + .HasForeignKey("BudgetGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.Team", "Team") + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("BudgetGroup"); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetGroup", b => + { + b.HasOne("Humans.Domain.Entities.BudgetYear", "BudgetYear") + .WithMany("Groups") + .HasForeignKey("BudgetYearId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BudgetYear"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetLineItem", b => + { + b.HasOne("Humans.Domain.Entities.BudgetCategory", "BudgetCategory") + .WithMany("LineItems") + .HasForeignKey("BudgetCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.Team", null) + .WithMany() + .HasForeignKey("ResponsibleTeamId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("BudgetCategory"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CalendarEvent", b => + { + b.HasOne("Humans.Domain.Entities.Team", "OwningTeam") + .WithMany() + .HasForeignKey("OwningTeamId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("OwningTeam"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CalendarEventException", b => + { + b.HasOne("Humans.Domain.Entities.CalendarEvent", "Event") + .WithMany("Exceptions") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Camp", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampHistoricalName", b => + { + b.HasOne("Humans.Domain.Entities.Camp", "Camp") + .WithMany("HistoricalNames") + .HasForeignKey("CampId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Camp"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampImage", b => + { + b.HasOne("Humans.Domain.Entities.Camp", "Camp") + .WithMany("Images") + .HasForeignKey("CampId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Camp"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampLead", b => + { + b.HasOne("Humans.Domain.Entities.Camp", "Camp") + .WithMany("Leads") + .HasForeignKey("CampId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Camp"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampMember", b => + { + b.HasOne("Humans.Domain.Entities.CampSeason", "CampSeason") + .WithMany("Members") + .HasForeignKey("CampSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CampSeason"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampPolygon", b => + { + b.HasOne("Humans.Domain.Entities.CampSeason", "CampSeason") + .WithMany() + .HasForeignKey("CampSeasonId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("LastModifiedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CampSeason"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampPolygonHistory", b => + { + b.HasOne("Humans.Domain.Entities.CampSeason", "CampSeason") + .WithMany() + .HasForeignKey("CampSeasonId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ModifiedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CampSeason"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampRoleAssignment", b => + { + b.HasOne("Humans.Domain.Entities.CampMember", "CampMember") + .WithMany() + .HasForeignKey("CampMemberId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.CampRoleDefinition", "Definition") + .WithMany("Assignments") + .HasForeignKey("CampRoleDefinitionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.CampSeason", "CampSeason") + .WithMany() + .HasForeignKey("CampSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CampMember"); + + b.Navigation("CampSeason"); + + b.Navigation("Definition"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampSeason", b => + { + b.HasOne("Humans.Domain.Entities.Camp", "Camp") + .WithMany("Seasons") + .HasForeignKey("CampId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ReviewedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Camp"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Campaign", b => + { + b.HasOne("Humans.Domain.Entities.User", "CreatedByUser") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("CreatedByUser"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignCode", b => + { + b.HasOne("Humans.Domain.Entities.Campaign", "Campaign") + .WithMany("Codes") + .HasForeignKey("CampaignId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Campaign"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignGrant", b => + { + b.HasOne("Humans.Domain.Entities.CampaignCode", "Code") + .WithOne("Grant") + .HasForeignKey("Humans.Domain.Entities.CampaignGrant", "CampaignCodeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.Campaign", "Campaign") + .WithMany("Grants") + .HasForeignKey("CampaignId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Campaign"); + + b.Navigation("Code"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CommunicationPreference", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ConsentRecord", b => + { + b.HasOne("Humans.Domain.Entities.DocumentVersion", "DocumentVersion") + .WithMany("ConsentRecords") + .HasForeignKey("DocumentVersionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("DocumentVersion"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ContactField", b => + { + b.HasOne("Humans.Domain.Entities.Profile", "Profile") + .WithMany("ContactFields") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.DocumentVersion", b => + { + b.HasOne("Humans.Domain.Entities.LegalDocument", "LegalDocument") + .WithMany("Versions") + .HasForeignKey("LegalDocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LegalDocument"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EmailOutboxMessage", b => + { + b.HasOne("Humans.Domain.Entities.CampaignGrant", "CampaignGrant") + .WithMany("OutboxMessages") + .HasForeignKey("CampaignGrantId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.ShiftSignup", "ShiftSignup") + .WithMany() + .HasForeignKey("ShiftSignupId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("CampaignGrant"); + + b.Navigation("ShiftSignup"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Event", b => + { + b.HasOne("Humans.Domain.Entities.EventCategory", "Category") + .WithMany("Events") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.EventVenue", "EventVenue") + .WithMany("Events") + .HasForeignKey("GuideSharedVenueId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Category"); + + b.Navigation("EventVenue"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventFavourite", b => + { + b.HasOne("Humans.Domain.Entities.Event", "Event") + .WithMany("EventFavourites") + .HasForeignKey("GuideEventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventModerationAction", b => + { + b.HasOne("Humans.Domain.Entities.Event", "Event") + .WithMany("EventModerationActions") + .HasForeignKey("GuideEventId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventParticipation", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany("EventParticipations") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.FeedbackMessage", b => + { + b.HasOne("Humans.Domain.Entities.FeedbackReport", "FeedbackReport") + .WithMany("Messages") + .HasForeignKey("FeedbackReportId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "SenderUser") + .WithMany() + .HasForeignKey("SenderUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("FeedbackReport"); + + b.Navigation("SenderUser"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.FeedbackReport", b => + { + b.HasOne("Humans.Domain.Entities.Team", "AssignedToTeam") + .WithMany() + .HasForeignKey("AssignedToTeamId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", "AssignedToUser") + .WithMany() + .HasForeignKey("AssignedToUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", "ResolvedByUser") + .WithMany() + .HasForeignKey("ResolvedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AssignedToTeam"); + + b.Navigation("AssignedToUser"); + + b.Navigation("ResolvedByUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GeneralAvailability", b => + { + b.HasOne("Humans.Domain.Entities.EventSettings", "EventSettings") + .WithMany() + .HasForeignKey("EventSettingsId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("EventSettings"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GoogleResource", b => + { + b.HasOne("Humans.Domain.Entities.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.GoogleSyncOutboxEvent", b => + { + b.HasOne("Humans.Domain.Entities.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Issue", b => + { + b.HasOne("Humans.Domain.Entities.User", "Assignee") + .WithMany() + .HasForeignKey("AssigneeUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", "Reporter") + .WithMany() + .HasForeignKey("ReporterUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "ResolvedByUser") + .WithMany() + .HasForeignKey("ResolvedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Assignee"); + + b.Navigation("Reporter"); + + b.Navigation("ResolvedByUser"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.IssueComment", b => + { + b.HasOne("Humans.Domain.Entities.Issue", "Issue") + .WithMany("Comments") + .HasForeignKey("IssueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "SenderUser") + .WithMany() + .HasForeignKey("SenderUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Issue"); + + b.Navigation("SenderUser"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.LegalDocument", b => + { + b.HasOne("Humans.Domain.Entities.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Notification", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ResolvedByUserId") + .OnDelete(DeleteBehavior.SetNull); + }); + + modelBuilder.Entity("Humans.Domain.Entities.NotificationRecipient", b => + { + b.HasOne("Humans.Domain.Entities.Notification", "Notification") + .WithMany("Recipients") + .HasForeignKey("NotificationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Notification"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Profile", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithOne() + .HasForeignKey("Humans.Domain.Entities.Profile", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ProfileLanguage", b => + { + b.HasOne("Humans.Domain.Entities.Profile", "Profile") + .WithMany("Languages") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.RoleAssignment", b => + { + b.HasOne("Humans.Domain.Entities.User", "CreatedByUser") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CreatedByUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Rota", b => + { + b.HasOne("Humans.Domain.Entities.EventSettings", "EventSettings") + .WithMany("Rotas") + .HasForeignKey("EventSettingsId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.Team", null) + .WithMany() + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("EventSettings"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Shift", b => + { + b.HasOne("Humans.Domain.Entities.Rota", "Rota") + .WithMany("Shifts") + .HasForeignKey("RotaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Rota"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ShiftSignup", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("EnrolledByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("ReviewedByUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.Shift", "Shift") + .WithMany("ShiftSignups") + .HasForeignKey("ShiftId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Shift"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreInvoice", b => + { + b.HasOne("Humans.Domain.Entities.StoreOrder", null) + .WithOne() + .HasForeignKey("Humans.Domain.Entities.StoreInvoice", "OrderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreOrderLine", b => + { + b.HasOne("Humans.Domain.Entities.StoreOrder", "Order") + .WithMany("Lines") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.StoreProduct", null) + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StorePayment", b => + { + b.HasOne("Humans.Domain.Entities.StoreOrder", "Order") + .WithMany("Payments") + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Order"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyAnswer", b => + { + b.HasOne("Humans.Domain.Entities.SurveyQuestion", null) + .WithMany() + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.SurveyResponse", "Response") + .WithMany("Answers") + .HasForeignKey("ResponseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Response"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyQuestion", b => + { + b.HasOne("Humans.Domain.Entities.Survey", "Survey") + .WithMany("Questions") + .HasForeignKey("SurveyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Survey"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyQuestionOption", b => + { + b.HasOne("Humans.Domain.Entities.SurveyQuestion", "Question") + .WithMany("Options") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyResponse", b => + { + b.HasOne("Humans.Domain.Entities.SurveyInvitation", null) + .WithMany() + .HasForeignKey("InvitationId") + .OnDelete(DeleteBehavior.SetNull); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SyncServiceSettings", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UpdatedByUserId") + .OnDelete(DeleteBehavior.SetNull); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Team", b => + { + b.HasOne("Humans.Domain.Entities.Team", "ParentTeam") + .WithMany("ChildTeams") + .HasForeignKey("ParentTeamId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("ParentTeam"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamEarlyEntryGrant", b => + { + b.HasOne("Humans.Domain.Entities.Team", "Team") + .WithMany("EarlyEntryGrants") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamJoinRequest", b => + { + b.HasOne("Humans.Domain.Entities.User", "ReviewedByUser") + .WithMany() + .HasForeignKey("ReviewedByUserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("Humans.Domain.Entities.Team", "Team") + .WithMany("JoinRequests") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReviewedByUser"); + + b.Navigation("Team"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamJoinRequestStateHistory", b => + { + b.HasOne("Humans.Domain.Entities.User", "ChangedByUser") + .WithMany() + .HasForeignKey("ChangedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.TeamJoinRequest", "TeamJoinRequest") + .WithMany("StateHistory") + .HasForeignKey("TeamJoinRequestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChangedByUser"); + + b.Navigation("TeamJoinRequest"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamMember", b => + { + b.HasOne("Humans.Domain.Entities.Team", "Team") + .WithMany("Members") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamRoleAssignment", b => + { + b.HasOne("Humans.Domain.Entities.User", "AssignedByUser") + .WithMany() + .HasForeignKey("AssignedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.TeamMember", "TeamMember") + .WithMany("RoleAssignments") + .HasForeignKey("TeamMemberId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.TeamRoleDefinition", "TeamRoleDefinition") + .WithMany("Assignments") + .HasForeignKey("TeamRoleDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AssignedByUser"); + + b.Navigation("TeamMember"); + + b.Navigation("TeamRoleDefinition"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamRoleDefinition", b => + { + b.HasOne("Humans.Domain.Entities.Team", "Team") + .WithMany("RoleDefinitions") + .HasForeignKey("TeamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Team"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketAttendee", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("MatchedUserId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("Humans.Domain.Entities.TicketOrder", "TicketOrder") + .WithMany("Attendees") + .HasForeignKey("TicketOrderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TicketOrder"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketOrder", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("MatchedUserId") + .OnDelete(DeleteBehavior.SetNull); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketTransferRequest", b => + { + b.HasOne("Humans.Domain.Entities.TicketAttendee", "OriginalTicketAttendee") + .WithMany() + .HasForeignKey("OriginalTicketAttendeeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("OriginalTicketAttendee"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketingProjection", b => + { + b.HasOne("Humans.Domain.Entities.BudgetGroup", "BudgetGroup") + .WithOne("TicketingProjection") + .HasForeignKey("Humans.Domain.Entities.TicketingProjection", "BudgetGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BudgetGroup"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.User", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("MergedToUserId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("Humans.Domain.Entities.UserEmail", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany("UserEmails") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerBuildStatus", b => + { + b.HasOne("Humans.Domain.Entities.EventSettings", null) + .WithMany() + .HasForeignKey("EventSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerEventProfile", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerHistoryEntry", b => + { + b.HasOne("Humans.Domain.Entities.Profile", "Profile") + .WithMany("VolunteerHistory") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.VolunteerTagPreference", b => + { + b.HasOne("Humans.Domain.Entities.ShiftTag", "ShiftTag") + .WithMany("VolunteerPreferences") + .HasForeignKey("ShiftTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ShiftTag"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Humans.Domain.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RotaShiftTag", b => + { + b.HasOne("Humans.Domain.Entities.Rota", null) + .WithMany() + .HasForeignKey("RotaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Humans.Domain.Entities.ShiftTag", null) + .WithMany() + .HasForeignKey("ShiftTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Application", b => + { + b.Navigation("BoardVotes"); + + b.Navigation("StateHistory"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetCategory", b => + { + b.Navigation("LineItems"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetGroup", b => + { + b.Navigation("Categories"); + + b.Navigation("TicketingProjection"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.BudgetYear", b => + { + b.Navigation("AuditLogs"); + + b.Navigation("Groups"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CalendarEvent", b => + { + b.Navigation("Exceptions"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Camp", b => + { + b.Navigation("HistoricalNames"); + + b.Navigation("Images"); + + b.Navigation("Leads"); + + b.Navigation("Seasons"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampRoleDefinition", b => + { + b.Navigation("Assignments"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampSeason", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Campaign", b => + { + b.Navigation("Codes"); + + b.Navigation("Grants"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignCode", b => + { + b.Navigation("Grant"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.CampaignGrant", b => + { + b.Navigation("OutboxMessages"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.DocumentVersion", b => + { + b.Navigation("ConsentRecords"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Event", b => + { + b.Navigation("EventFavourites"); + + b.Navigation("EventModerationActions"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventCategory", b => + { + b.Navigation("Events"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventSettings", b => + { + b.Navigation("Rotas"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.EventVenue", b => + { + b.Navigation("Events"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.FeedbackReport", b => + { + b.Navigation("Messages"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Issue", b => + { + b.Navigation("Comments"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.LegalDocument", b => + { + b.Navigation("Versions"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Notification", b => + { + b.Navigation("Recipients"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Profile", b => + { + b.Navigation("ContactFields"); + + b.Navigation("Languages"); + + b.Navigation("VolunteerHistory"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Rota", b => + { + b.Navigation("Shifts"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Shift", b => + { + b.Navigation("ShiftSignups"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.ShiftTag", b => + { + b.Navigation("VolunteerPreferences"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.StoreOrder", b => + { + b.Navigation("Lines"); + + b.Navigation("Payments"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Survey", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyQuestion", b => + { + b.Navigation("Options"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.SurveyResponse", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.Team", b => + { + b.Navigation("ChildTeams"); + + b.Navigation("EarlyEntryGrants"); + + b.Navigation("JoinRequests"); + + b.Navigation("Members"); + + b.Navigation("RoleDefinitions"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamJoinRequest", b => + { + b.Navigation("StateHistory"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamMember", b => + { + b.Navigation("RoleAssignments"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TeamRoleDefinition", b => + { + b.Navigation("Assignments"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.TicketOrder", b => + { + b.Navigation("Attendees"); + }); + + modelBuilder.Entity("Humans.Domain.Entities.User", b => + { + b.Navigation("EventParticipations"); + + b.Navigation("UserEmails"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.cs b/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.cs new file mode 100644 index 000000000..9dc9f1294 --- /dev/null +++ b/src/Humans.Infrastructure/Migrations/20260715103734_PeelFinance.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; + +#nullable disable + +namespace Humans.Infrastructure.Migrations +{ + /// + /// Snapshot-only migration for the Finance peel + /// (nobodies-collective/Humans#858): holded_expense_docs, + /// holded_category_map, holded_ledger_lines, + /// holded_creditor_contacts and holded_sync_states moved to + /// FinanceDbContext, which owns the physical tables from here on. The + /// scaffolded DropTable/CreateTable bodies were deliberately + /// emptied — Peter-authorized per-instance exception to + /// memory/architecture/no-hand-edited-migrations.md in the #858 + /// execution brief — so applying this migration changes no physical schema. + /// + public partial class PeelFinance : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + } + } +} diff --git a/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.Designer.cs b/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.Designer.cs new file mode 100644 index 000000000..0c3e001b0 --- /dev/null +++ b/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.Designer.cs @@ -0,0 +1,286 @@ +// +using System; +using Humans.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Humans.Infrastructure.Migrations.Finance +{ + [DbContext(typeof(FinanceDbContext))] + [Migration("20260715103643_BaselineFinance")] + partial class BaselineFinance + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedCategoryMap", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ArchivedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("BudgetCategoryId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HoldedAccountId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("HoldedAccountNumber") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Tag") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("BudgetCategoryId") + .IsUnique(); + + b.HasIndex("HoldedAccountNumber") + .IsUnique(); + + b.ToTable("holded_category_map", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedCreditorContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HoldedContactId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("SupplierAccountNum") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SupplierAccountNum"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("holded_creditor_contacts", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedExpenseDoc", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("BookedAccountId") + .HasColumnType("text"); + + b.Property("BudgetCategoryId") + .HasColumnType("uuid"); + + b.Property("ContactName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("Date") + .HasColumnType("date"); + + b.Property("DocNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("HoldedDocId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MatchSource") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("MatchStatus") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("RawPayload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Subtotal") + .HasColumnType("numeric"); + + b.Property("TagsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Tax") + .HasColumnType("numeric"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("BudgetCategoryId"); + + b.HasIndex("Date"); + + b.HasIndex("HoldedDocId") + .IsUnique(); + + b.HasIndex("MatchStatus"); + + b.ToTable("holded_expense_docs", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedLedgerLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountNum") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Credit") + .HasColumnType("decimal(12,2)"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Debit") + .HasColumnType("decimal(12,2)"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EntryNumber") + .HasColumnType("integer"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Line") + .HasColumnType("integer"); + + b.Property("Type") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("AccountNum"); + + b.HasIndex("EntryNumber", "Line") + .IsUnique(); + + b.ToTable("holded_ledger_lines", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedSyncState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastError") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("LastSyncAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSyncedDocCount") + .HasColumnType("integer"); + + b.Property("StatusChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SyncStatus") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.HasKey("Id"); + + b.ToTable("holded_sync_states", (string)null); + + b.HasData( + new + { + Id = 1, + LastSyncedDocCount = 0, + SyncStatus = "Idle" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.cs b/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.cs new file mode 100644 index 000000000..df1c013f0 --- /dev/null +++ b/src/Humans.Infrastructure/Migrations/Finance/20260715103643_BaselineFinance.cs @@ -0,0 +1,199 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Humans.Infrastructure.Migrations.Finance +{ + /// + public partial class BaselineFinance : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "holded_category_map", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + BudgetCategoryId = table.Column(type: "uuid", nullable: false), + HoldedAccountNumber = table.Column(type: "integer", nullable: false), + HoldedAccountId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + Tag = table.Column(type: "character varying(128)", maxLength: 128, nullable: false), + IsActive = table.Column(type: "boolean", nullable: false), + ArchivedAt = table.Column(type: "timestamp with time zone", 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_holded_category_map", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "holded_creditor_contacts", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + HoldedContactId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + SupplierAccountNum = table.Column(type: "integer", nullable: true), + Source = table.Column(type: "character varying(16)", maxLength: 16, nullable: false), + 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_holded_creditor_contacts", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "holded_expense_docs", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + HoldedDocId = table.Column(type: "character varying(64)", maxLength: 64, nullable: false), + DocNumber = table.Column(type: "text", nullable: false), + ContactName = table.Column(type: "text", nullable: false), + Date = table.Column(type: "date", nullable: false), + Subtotal = table.Column(type: "numeric", nullable: false), + Tax = table.Column(type: "numeric", nullable: false), + Total = table.Column(type: "numeric", nullable: false), + Currency = table.Column(type: "character varying(3)", maxLength: 3, nullable: false), + ApprovedAt = table.Column(type: "timestamp with time zone", nullable: true), + TagsJson = table.Column(type: "jsonb", nullable: false), + BookedAccountId = table.Column(type: "text", nullable: true), + BudgetCategoryId = table.Column(type: "uuid", nullable: true), + MatchStatus = table.Column(type: "character varying(16)", maxLength: 16, nullable: false), + MatchSource = table.Column(type: "character varying(16)", maxLength: 16, nullable: false), + RawPayload = table.Column(type: "jsonb", nullable: false), + LastSyncedAt = table.Column(type: "timestamp with time zone", nullable: false), + 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_holded_expense_docs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "holded_ledger_lines", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + EntryNumber = table.Column(type: "integer", nullable: false), + Line = table.Column(type: "integer", nullable: false), + AccountNum = table.Column(type: "integer", nullable: false), + Date = table.Column(type: "timestamp with time zone", nullable: false), + Type = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + Description = table.Column(type: "text", nullable: true), + Debit = table.Column(type: "numeric(12,2)", nullable: false), + Credit = table.Column(type: "numeric(12,2)", nullable: false), + LastSyncedAt = table.Column(type: "timestamp with time zone", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_holded_ledger_lines", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "holded_sync_states", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + LastSyncAt = table.Column(type: "timestamp with time zone", nullable: true), + SyncStatus = table.Column(type: "character varying(16)", maxLength: 16, nullable: false), + LastError = table.Column(type: "character varying(2000)", maxLength: 2000, nullable: true), + StatusChangedAt = table.Column(type: "timestamp with time zone", nullable: true), + LastSyncedDocCount = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_holded_sync_states", x => x.Id); + }); + + migrationBuilder.InsertData( + table: "holded_sync_states", + columns: new[] { "Id", "LastError", "LastSyncAt", "LastSyncedDocCount", "StatusChangedAt", "SyncStatus" }, + values: new object[] { 1, null, null, 0, null, "Idle" }); + + migrationBuilder.CreateIndex( + name: "IX_holded_category_map_BudgetCategoryId", + table: "holded_category_map", + column: "BudgetCategoryId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_holded_category_map_HoldedAccountNumber", + table: "holded_category_map", + column: "HoldedAccountNumber", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_holded_creditor_contacts_SupplierAccountNum", + table: "holded_creditor_contacts", + column: "SupplierAccountNum"); + + migrationBuilder.CreateIndex( + name: "IX_holded_creditor_contacts_UserId", + table: "holded_creditor_contacts", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_holded_expense_docs_BudgetCategoryId", + table: "holded_expense_docs", + column: "BudgetCategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_holded_expense_docs_Date", + table: "holded_expense_docs", + column: "Date"); + + migrationBuilder.CreateIndex( + name: "IX_holded_expense_docs_HoldedDocId", + table: "holded_expense_docs", + column: "HoldedDocId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_holded_expense_docs_MatchStatus", + table: "holded_expense_docs", + column: "MatchStatus"); + + migrationBuilder.CreateIndex( + name: "IX_holded_ledger_lines_AccountNum", + table: "holded_ledger_lines", + column: "AccountNum"); + + migrationBuilder.CreateIndex( + name: "IX_holded_ledger_lines_EntryNumber_Line", + table: "holded_ledger_lines", + columns: new[] { "EntryNumber", "Line" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "holded_category_map"); + + migrationBuilder.DropTable( + name: "holded_creditor_contacts"); + + migrationBuilder.DropTable( + name: "holded_expense_docs"); + + migrationBuilder.DropTable( + name: "holded_ledger_lines"); + + migrationBuilder.DropTable( + name: "holded_sync_states"); + } + } +} diff --git a/src/Humans.Infrastructure/Migrations/Finance/FinanceDbContextModelSnapshot.cs b/src/Humans.Infrastructure/Migrations/Finance/FinanceDbContextModelSnapshot.cs new file mode 100644 index 000000000..50d84929f --- /dev/null +++ b/src/Humans.Infrastructure/Migrations/Finance/FinanceDbContextModelSnapshot.cs @@ -0,0 +1,283 @@ +// +using System; +using Humans.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Humans.Infrastructure.Migrations.Finance +{ + [DbContext(typeof(FinanceDbContext))] + partial class FinanceDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedCategoryMap", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ArchivedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("BudgetCategoryId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HoldedAccountId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("HoldedAccountNumber") + .HasColumnType("integer"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("Tag") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("BudgetCategoryId") + .IsUnique(); + + b.HasIndex("HoldedAccountNumber") + .IsUnique(); + + b.ToTable("holded_category_map", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedCreditorContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("HoldedContactId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("SupplierAccountNum") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SupplierAccountNum"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("holded_creditor_contacts", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedExpenseDoc", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ApprovedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("BookedAccountId") + .HasColumnType("text"); + + b.Property("BudgetCategoryId") + .HasColumnType("uuid"); + + b.Property("ContactName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Currency") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.Property("Date") + .HasColumnType("date"); + + b.Property("DocNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("HoldedDocId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MatchSource") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("MatchStatus") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("RawPayload") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Subtotal") + .HasColumnType("numeric"); + + b.Property("TagsJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Tax") + .HasColumnType("numeric"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("BudgetCategoryId"); + + b.HasIndex("Date"); + + b.HasIndex("HoldedDocId") + .IsUnique(); + + b.HasIndex("MatchStatus"); + + b.ToTable("holded_expense_docs", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedLedgerLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountNum") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Credit") + .HasColumnType("decimal(12,2)"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Debit") + .HasColumnType("decimal(12,2)"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EntryNumber") + .HasColumnType("integer"); + + b.Property("LastSyncedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Line") + .HasColumnType("integer"); + + b.Property("Type") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.HasKey("Id"); + + b.HasIndex("AccountNum"); + + b.HasIndex("EntryNumber", "Line") + .IsUnique(); + + b.ToTable("holded_ledger_lines", (string)null); + }); + + modelBuilder.Entity("Humans.Domain.Entities.HoldedSyncState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("LastError") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("LastSyncAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSyncedDocCount") + .HasColumnType("integer"); + + b.Property("StatusChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SyncStatus") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.HasKey("Id"); + + b.ToTable("holded_sync_states", (string)null); + + b.HasData( + new + { + Id = 1, + LastSyncedDocCount = 0, + SyncStatus = "Idle" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Humans.Infrastructure/Migrations/HumansDbContextModelSnapshot.cs b/src/Humans.Infrastructure/Migrations/HumansDbContextModelSnapshot.cs index 1ea3e6439..c2f1a07f2 100644 --- a/src/Humans.Infrastructure/Migrations/HumansDbContextModelSnapshot.cs +++ b/src/Humans.Infrastructure/Migrations/HumansDbContextModelSnapshot.cs @@ -2477,261 +2477,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("google_sync_outbox", (string)null); }); - modelBuilder.Entity("Humans.Domain.Entities.HoldedCategoryMap", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ArchivedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("BudgetCategoryId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HoldedAccountId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("HoldedAccountNumber") - .HasColumnType("integer"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Tag") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("BudgetCategoryId") - .IsUnique(); - - b.HasIndex("HoldedAccountNumber") - .IsUnique(); - - b.ToTable("holded_category_map", (string)null); - }); - - modelBuilder.Entity("Humans.Domain.Entities.HoldedCreditorContact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("HoldedContactId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("Source") - .IsRequired() - .HasMaxLength(16) - .HasColumnType("character varying(16)"); - - b.Property("SupplierAccountNum") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("SupplierAccountNum"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("holded_creditor_contacts", (string)null); - }); - - modelBuilder.Entity("Humans.Domain.Entities.HoldedExpenseDoc", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("ApprovedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("BookedAccountId") - .HasColumnType("text"); - - b.Property("BudgetCategoryId") - .HasColumnType("uuid"); - - b.Property("ContactName") - .IsRequired() - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Currency") - .IsRequired() - .HasMaxLength(3) - .HasColumnType("character varying(3)"); - - b.Property("Date") - .HasColumnType("date"); - - b.Property("DocNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("HoldedDocId") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("character varying(64)"); - - b.Property("LastSyncedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MatchSource") - .IsRequired() - .HasMaxLength(16) - .HasColumnType("character varying(16)"); - - b.Property("MatchStatus") - .IsRequired() - .HasMaxLength(16) - .HasColumnType("character varying(16)"); - - b.Property("RawPayload") - .IsRequired() - .HasColumnType("jsonb"); - - b.Property("Subtotal") - .HasColumnType("numeric"); - - b.Property("TagsJson") - .IsRequired() - .HasColumnType("jsonb"); - - b.Property("Tax") - .HasColumnType("numeric"); - - b.Property("Total") - .HasColumnType("numeric"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("BudgetCategoryId"); - - b.HasIndex("Date"); - - b.HasIndex("HoldedDocId") - .IsUnique(); - - b.HasIndex("MatchStatus"); - - b.ToTable("holded_expense_docs", (string)null); - }); - - modelBuilder.Entity("Humans.Domain.Entities.HoldedLedgerLine", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountNum") - .HasColumnType("integer"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Credit") - .HasColumnType("decimal(12,2)"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("Debit") - .HasColumnType("decimal(12,2)"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("EntryNumber") - .HasColumnType("integer"); - - b.Property("LastSyncedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Line") - .HasColumnType("integer"); - - b.Property("Type") - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.HasKey("Id"); - - b.HasIndex("AccountNum"); - - b.HasIndex("EntryNumber", "Line") - .IsUnique(); - - b.ToTable("holded_ledger_lines", (string)null); - }); - - modelBuilder.Entity("Humans.Domain.Entities.HoldedSyncState", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("LastError") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("LastSyncAt") - .HasColumnType("timestamp with time zone"); - - b.Property("LastSyncedDocCount") - .HasColumnType("integer"); - - b.Property("StatusChangedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("SyncStatus") - .IsRequired() - .HasMaxLength(16) - .HasColumnType("character varying(16)"); - - b.HasKey("Id"); - - b.ToTable("holded_sync_states", (string)null); - - b.HasData( - new - { - Id = 1, - LastSyncedDocCount = 0, - SyncStatus = "Idle" - }); - }); - modelBuilder.Entity("Humans.Domain.Entities.Issue", b => { b.Property("Id") diff --git a/src/Humans.Infrastructure/Repositories/Finance/HoldedRepository.cs b/src/Humans.Infrastructure/Repositories/Finance/HoldedRepository.cs index 7c7cbcbf8..7b0480958 100644 --- a/src/Humans.Infrastructure/Repositories/Finance/HoldedRepository.cs +++ b/src/Humans.Infrastructure/Repositories/Finance/HoldedRepository.cs @@ -7,7 +7,7 @@ namespace Humans.Infrastructure.Repositories.Finance; -internal sealed class HoldedRepository(IDbContextFactory factory) +internal sealed class HoldedRepository(IDbContextFactory factory) : IHoldedRepository { // ── Category map ───────────────────────────────────────────────────────── diff --git a/tests/Humans.Integration.Tests/Infrastructure/SectionMigrationRunnerTests.cs b/tests/Humans.Integration.Tests/Infrastructure/SectionMigrationRunnerTests.cs index f979d5bf4..f0ff80003 100644 --- a/tests/Humans.Integration.Tests/Infrastructure/SectionMigrationRunnerTests.cs +++ b/tests/Humans.Integration.Tests/Infrastructure/SectionMigrationRunnerTests.cs @@ -63,6 +63,12 @@ private sealed record SectionCase( ["expense_reports", "expense_lines", "expense_attachments", "holded_expense_outbox_events"], cs => CreateSectionContext(cs, "__EFMigrationsHistory_Expenses"), null), + new( + "Finance", + "holded_expense_docs", + ["holded_expense_docs", "holded_category_map", "holded_ledger_lines", "holded_creditor_contacts", "holded_sync_states"], + cs => CreateSectionContext(cs, "__EFMigrationsHistory_Finance"), + "SELECT count(*) FROM holded_sync_states"), ]; private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder("postgres:16-alpine")