diff --git a/src/.dockerignore b/src/.dockerignore
new file mode 100644
index 000000000..cd967fc3a
--- /dev/null
+++ b/src/.dockerignore
@@ -0,0 +1,25 @@
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.idea
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/src/.idea/.idea.FluentCMS/.idea/dataSources.xml b/src/.idea/.idea.FluentCMS/.idea/dataSources.xml
new file mode 100644
index 000000000..945f32669
--- /dev/null
+++ b/src/.idea/.idea.FluentCMS/.idea/dataSources.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ postgresql
+ true
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/fluentcms_db?password=fluentcms_password&user=fluentcms_user
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/src/Backend/FluentCMS.Entities/GlobalSettings.cs b/src/Backend/FluentCMS.Entities/GlobalSettings.cs
index 548480bd7..db1f94997 100644
--- a/src/Backend/FluentCMS.Entities/GlobalSettings.cs
+++ b/src/Backend/FluentCMS.Entities/GlobalSettings.cs
@@ -2,8 +2,8 @@
public class GlobalSettings : AuditableEntity
{
- public FileUploadConfig FileUpload { get; set; } = default!;
- public IEnumerable SuperAdmins { get; set; } = [];
+ public FileUploadConfig? FileUpload { get; set; } = default!;
+ public List SuperAdmins { get; set; } = [];
public bool Initialized { get; set; } = false;
}
diff --git a/src/Backend/FluentCMS.Entities/PluginDefinition.cs b/src/Backend/FluentCMS.Entities/PluginDefinition.cs
index e9de37a19..3f5a473af 100644
--- a/src/Backend/FluentCMS.Entities/PluginDefinition.cs
+++ b/src/Backend/FluentCMS.Entities/PluginDefinition.cs
@@ -3,7 +3,7 @@
public class PluginDefinition : AuditableEntity
{
public string Name { get; set; } = default!;
- public string Category { get; set; } = default!;
+ public string? Category { get; set; } = default!;
public string Assembly { get; set; } = default!;
public string? Description { get; set; }
public IEnumerable Types { get; set; } = [];
diff --git a/src/Backend/FluentCMS.Services/SetupService.cs b/src/Backend/FluentCMS.Services/SetupService.cs
index 511cb33fd..2b39bd0fa 100644
--- a/src/Backend/FluentCMS.Services/SetupService.cs
+++ b/src/Backend/FluentCMS.Services/SetupService.cs
@@ -70,5 +70,8 @@ private static void SetIds(SetupTemplate setupTemplate)
foreach (var contentType in setupTemplate.ContentTypes)
contentType.Id = Guid.NewGuid();
+
+ foreach (var layout in setupTemplate.Site.Layouts)
+ layout.Id = Guid.NewGuid();
}
}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ApiTokenConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ApiTokenConfiguration.cs
new file mode 100644
index 000000000..23c2c15fc
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ApiTokenConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class ApiTokenConfiguration : AuditableEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/AuditableEntityConfigurationBase.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/AuditableEntityConfigurationBase.cs
new file mode 100644
index 000000000..002bb552d
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/AuditableEntityConfigurationBase.cs
@@ -0,0 +1,12 @@
+namespace FluentCMS.Repositories.Postgres.Configurations.Base;
+
+public class AuditableEntityConfigurationBase : EntityConfigurationBase where T : AuditableEntity
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.Property(x => x.CreatedAt).HasColumnType("timestamp with time zone");
+ entity.Property(x => x.ModifiedAt).HasColumnType("timestamp with time zone");
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/EntityConfigurationBase.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/EntityConfigurationBase.cs
new file mode 100644
index 000000000..4ed331673
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/EntityConfigurationBase.cs
@@ -0,0 +1,12 @@
+namespace FluentCMS.Repositories.Postgres.Configurations.Base;
+
+public class EntityConfigurationBase : IEntityTypeConfiguration where T : Entity
+{
+ public virtual void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(x => x.Id);
+ }
+
+
+}
+
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/ShadowKeyEntityBaseConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/ShadowKeyEntityBaseConfiguration.cs
new file mode 100644
index 000000000..8b87978a8
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/ShadowKeyEntityBaseConfiguration.cs
@@ -0,0 +1,11 @@
+namespace FluentCMS.Repositories.Postgres.Configurations.Base;
+
+public class ShadowKeyEntityBaseConfiguration : IEntityTypeConfiguration where T : class
+{
+ public virtual void Configure(EntityTypeBuilder builder)
+ {
+ builder.Property("Id").ValueGeneratedOnAdd();
+
+ builder.HasKey("Id");
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/SiteAssociatedEntityConfigurationBase.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/SiteAssociatedEntityConfigurationBase.cs
new file mode 100644
index 000000000..61ee45081
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/Base/SiteAssociatedEntityConfigurationBase.cs
@@ -0,0 +1,13 @@
+namespace FluentCMS.Repositories.Postgres.Configurations.Base;
+
+public class SiteAssociatedEntityConfigurationBase : AuditableEntityConfigurationBase where T : SiteAssociatedEntity
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.SiteId);
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentConfiguration.cs
new file mode 100644
index 000000000..7b5a32ed2
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentConfiguration.cs
@@ -0,0 +1,13 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class ContentConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.OwnsOne(x => x.Data, builder => {builder.ToJson(); });
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeConfiguration.cs
new file mode 100644
index 000000000..e6baef53e
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeConfiguration.cs
@@ -0,0 +1,12 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class ContentTypeConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeFieldConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeFieldConfiguration.cs
new file mode 100644
index 000000000..5cff8aaa0
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/ContentTypeFieldConfiguration.cs
@@ -0,0 +1,18 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class ContentTypeFieldConfiguration : ShadowKeyEntityBaseConfiguration
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.Property(x => x.Settings).HasColumnType("jsonb");
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey("TypeId");
+
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FileConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FileConfiguration.cs
new file mode 100644
index 000000000..8a0c378b7
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FileConfiguration.cs
@@ -0,0 +1,15 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class FileConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.FolderId);
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FolderConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FolderConfiguration.cs
new file mode 100644
index 000000000..801485b2c
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/FolderConfiguration.cs
@@ -0,0 +1,16 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class FolderConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.FolderId);
+
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/GlobalSettingsConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/GlobalSettingsConfiguration.cs
new file mode 100644
index 000000000..cdb63a175
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/GlobalSettingsConfiguration.cs
@@ -0,0 +1,14 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class GlobalSettingsConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.OwnsOne(x => x.FileUpload, builder => { builder.ToJson(); });
+
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionConfiguration.cs
new file mode 100644
index 000000000..3e19e516e
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class PluginDefinitionConfiguration : AuditableEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionTypeConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionTypeConfiguration.cs
new file mode 100644
index 000000000..aea38ab8a
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PluginDefinitionTypeConfiguration.cs
@@ -0,0 +1,13 @@
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class PluginDefinitionTypeConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(x => new{x.Type, x.Name});
+
+ builder.HasOne()
+ .WithMany()
+ .HasForeignKey("DefinitionId");
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PolicyConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PolicyConfiguration.cs
new file mode 100644
index 000000000..e9c61bb44
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/PolicyConfiguration.cs
@@ -0,0 +1,13 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class PolicyConfiguration : ShadowKeyEntityBaseConfiguration
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.OwnsOne(x => x.Actions, builder => { builder.ToJson(); });
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SettingsConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SettingsConfiguration.cs
new file mode 100644
index 000000000..dd1bb191a
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SettingsConfiguration.cs
@@ -0,0 +1,13 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations;
+
+public class SettingsConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.OwnsOne(x => x.Values, builder => { builder.ToJson(); });
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/BlockConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/BlockConfiguration.cs
new file mode 100644
index 000000000..53243b520
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/BlockConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class BlockConfiguration : SiteAssociatedEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/LayoutConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/LayoutConfiguration.cs
new file mode 100644
index 000000000..545b19222
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/LayoutConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class LayoutConfiguration : SiteAssociatedEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PageConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PageConfiguration.cs
new file mode 100644
index 000000000..750c1aee3
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PageConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class PageConfiguration : SiteAssociatedEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PermissionConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PermissionConfiguration.cs
new file mode 100644
index 000000000..eb7614aa5
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PermissionConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class PermissionConfiguration : SiteAssociatedEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginConfiguration.cs
new file mode 100644
index 000000000..13772e511
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class PluginConfiguration : SiteAssociatedEntityConfigurationBase
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginContentConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginContentConfiguration.cs
new file mode 100644
index 000000000..4af8a58cf
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/PluginContentConfiguration.cs
@@ -0,0 +1,17 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class PluginContentConfiguration : SiteAssociatedEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.PluginId);
+
+ entity.OwnsOne(x => x.Data, builder => builder.ToJson());
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/RoleConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/RoleConfiguration.cs
new file mode 100644
index 000000000..10946abed
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/RoleConfiguration.cs
@@ -0,0 +1,13 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class RoleConfiguration : SiteAssociatedEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.Property(x => x.Type).HasConversion();
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/SiteConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/SiteConfiguration.cs
new file mode 100644
index 000000000..97432a38f
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/SiteConfiguration.cs
@@ -0,0 +1,25 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class SiteConfiguration : AuditableEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.OwnsOne(x => x.Urls, builder => builder.ToJson());
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.LayoutId);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.DetailLayoutId);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.EditLayoutId);
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/UserRoleConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/UserRoleConfiguration.cs
new file mode 100644
index 000000000..521a587a6
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/SiteAssociatedEntities/UserRoleConfiguration.cs
@@ -0,0 +1,19 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.SiteAssociatedEntities;
+
+public class UserRoleConfiguration : SiteAssociatedEntityConfigurationBase
+{
+ public override void Configure(EntityTypeBuilder entity)
+ {
+ base.Configure(entity);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.UserId);
+
+ entity.HasOne()
+ .WithMany()
+ .HasForeignKey(x => x.RoleId);
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserConfiguration.cs
new file mode 100644
index 000000000..79960b501
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserConfiguration.cs
@@ -0,0 +1,9 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+using Microsoft.AspNetCore.Identity;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class IdentityUserConfiguration : ShadowKeyEntityBaseConfiguration>
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserLoginConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserLoginConfiguration.cs
new file mode 100644
index 000000000..13869d81a
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserLoginConfiguration.cs
@@ -0,0 +1,9 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+using Microsoft.AspNetCore.Identity;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class IdentityUserLoginConfiguration : ShadowKeyEntityBaseConfiguration>
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserRoleConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserRoleConfiguration.cs
new file mode 100644
index 000000000..f6d5447c6
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserRoleConfiguration.cs
@@ -0,0 +1,9 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+using Microsoft.AspNetCore.Identity;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class IdentityUserRoleConfiguration : ShadowKeyEntityBaseConfiguration>
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserTokenConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserTokenConfiguration.cs
new file mode 100644
index 000000000..d41689883
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/IdentityUserTokenConfiguration.cs
@@ -0,0 +1,9 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+using Microsoft.AspNetCore.Identity;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class IdentityUserTokenConfiguration : ShadowKeyEntityBaseConfiguration>
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserConfiguration.cs
new file mode 100644
index 000000000..dc0b33d76
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserConfiguration.cs
@@ -0,0 +1,11 @@
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class UserConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+
+ builder.HasMany(x => x.RecoveryCodes)
+ .WithOne();
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserTwoFactorRecoveryCodeConfiguration.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserTwoFactorRecoveryCodeConfiguration.cs
new file mode 100644
index 000000000..bc6313889
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Configurations/UserAssociatedEntities/UserTwoFactorRecoveryCodeConfiguration.cs
@@ -0,0 +1,8 @@
+using FluentCMS.Repositories.Postgres.Configurations.Base;
+
+namespace FluentCMS.Repositories.Postgres.Configurations.UserAssociatedEntities;
+
+public class UserTwoFactorRecoveryCodeConfiguration : ShadowKeyEntityBaseConfiguration
+{
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/MainContextDesignTimeFactory.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/MainContextDesignTimeFactory.cs
new file mode 100644
index 000000000..b1de09e7d
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/MainContextDesignTimeFactory.cs
@@ -0,0 +1,17 @@
+using FluentCMS.Web.Api;
+using Microsoft.AspNetCore.Http;
+using Microsoft.EntityFrameworkCore.Design;
+
+namespace FluentCMS.Repositories.Postgres.Extensions;
+
+public class MainContextDesignTimeFactory : IDesignTimeDbContextFactory
+{
+ public PostgresDbContext CreateDbContext(string[] args)
+ {
+
+ var optionsBuilder = new DbContextOptionsBuilder();
+ optionsBuilder.UseNpgsql("Host=localhost;Database=fluentcms;Username=postgres;Password=postgres");
+
+ return new(optionsBuilder.Options, new ApiExecutionContext(new HttpContextAccessor()));
+ }
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/PostgresServiceExtensions.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/PostgresServiceExtensions.cs
new file mode 100644
index 000000000..4beba0121
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Extensions/PostgresServiceExtensions.cs
@@ -0,0 +1,40 @@
+using FluentCMS.Repositories.Postgres.Repositories;
+using FluentCMS.Repositories.Postgres.Workers;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Npgsql;
+
+namespace FluentCMS.Repositories.Postgres.Extensions;
+
+public static class PostgresServiceExtensions
+{
+ public static IServiceCollection AddPostgresDbRepositories(this IServiceCollection services, string connectionStringName)
+ {
+ services.AddDbContext((provider, optionsBuilder) =>
+ {
+ var configuration = provider.GetService() ?? throw new InvalidOperationException("IConfiguration is not registered.");
+ var connectionString = configuration.GetConnectionString(connectionStringName);
+
+ var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
+ dataSourceBuilder.EnableDynamicJson();
+
+
+ optionsBuilder.UseNpgsql(dataSourceBuilder.Build());
+ });
+
+
+
+ // Register repositories
+ services.Scan(scan => scan
+ .FromAssembliesOf(typeof(PostgresDbContext))
+ .AddClasses(classes => classes.AssignableTo(typeof(IService)))
+ .AsImplementedInterfaces()
+ .WithTransientLifetime());
+
+ services.AddHostedService();
+
+ return services;
+ }
+
+
+}
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/FluentCMS.Repositories.Postgres.csproj b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/FluentCMS.Repositories.Postgres.csproj
new file mode 100644
index 000000000..88e37058b
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/FluentCMS.Repositories.Postgres.csproj
@@ -0,0 +1,52 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.10\Microsoft.Extensions.Configuration.dll
+
+
+
+
+
+
+
+
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/GlobalUsings.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/GlobalUsings.cs
new file mode 100644
index 000000000..6df8eadcb
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/GlobalUsings.cs
@@ -0,0 +1,11 @@
+global using Microsoft.EntityFrameworkCore;
+global using FluentCMS.Entities;
+global using FluentCMS.Repositories.Abstractions;
+global using System;
+global using System.Collections.Generic;
+global using System.Linq;
+global using System.Threading;
+global using System.Threading.Tasks;
+global using FluentCMS.Repositories.Postgres.Repositories.Base;
+global using Microsoft.EntityFrameworkCore.Metadata.Builders;
+global using File = FluentCMS.Entities.File;
diff --git a/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Migrations/20241014214640_Init.Designer.cs b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Migrations/20241014214640_Init.Designer.cs
new file mode 100644
index 000000000..05918cb66
--- /dev/null
+++ b/src/Backend/Repositories/FluentCMS.Repositories.Postgres/Migrations/20241014214640_Init.Designer.cs
@@ -0,0 +1,1415 @@
+//
+using System;
+using System.Collections.Generic;
+using FluentCMS.Repositories.Postgres;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace FluentCMS.Repositories.Postgres.Migrations
+{
+ [DbContext(typeof(PostgresDbContext))]
+ [Migration("20241014214640_Init")]
+ partial class Init
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("FluentCMS.Entities.ApiToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Enabled")
+ .HasColumnType("boolean");
+
+ b.Property("ExpireAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Secret")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("ApiTokens");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Block", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Category")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Blocks");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Content", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("TypeId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.ToTable("Contents");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.ContentType", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Slug")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("ContentTypes");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.ContentTypeField", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ContentTypeId")
+ .HasColumnType("uuid");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Label")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Required")
+ .HasColumnType("boolean");
+
+ b.Property>("Settings")
+ .HasColumnType("jsonb");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TypeId")
+ .HasColumnType("uuid");
+
+ b.Property("Unique")
+ .HasColumnType("boolean");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ContentTypeId");
+
+ b.HasIndex("TypeId");
+
+ b.ToTable("ContentTypeFields");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.File", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ContentType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Extension")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("FolderId")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Size")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("FolderId");
+
+ b.ToTable("Files");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Folder", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("FolderId")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("FolderId");
+
+ b.ToTable("Folders");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.GlobalSettings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Initialized")
+ .HasColumnType("boolean");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property>("SuperAdmins")
+ .IsRequired()
+ .HasColumnType("text[]");
+
+ b.HasKey("Id");
+
+ b.ToTable("GlobalSettings");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Layout", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Body")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Head")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Layouts");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Page", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DetailLayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("EditLayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("LayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("Locked")
+ .HasColumnType("boolean");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Order")
+ .HasColumnType("integer");
+
+ b.Property("ParentId")
+ .HasColumnType("uuid");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Pages");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Permission", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Action")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("EntityId")
+ .HasColumnType("uuid");
+
+ b.Property("EntityType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("RoleId")
+ .HasColumnType("uuid");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Permissions");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Plugin", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Cols")
+ .HasColumnType("integer");
+
+ b.Property("ColsLg")
+ .HasColumnType("integer");
+
+ b.Property("ColsMd")
+ .HasColumnType("integer");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DefinitionId")
+ .HasColumnType("uuid");
+
+ b.Property("Locked")
+ .HasColumnType("boolean");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Order")
+ .HasColumnType("integer");
+
+ b.Property("PageId")
+ .HasColumnType("uuid");
+
+ b.Property("Section")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Plugin");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.PluginContent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("PluginId")
+ .HasColumnType("uuid");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PluginId");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("PluginContents");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.PluginDefinition", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Assembly")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Category")
+ .HasColumnType("text");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Locked")
+ .HasColumnType("boolean");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("PluginDefinitions");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.PluginDefinitionType", b =>
+ {
+ b.Property("Type")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("DefinitionId")
+ .HasColumnType("uuid");
+
+ b.Property("IsDefault")
+ .HasColumnType("boolean");
+
+ b.Property("PluginDefinitionId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Type", "Name");
+
+ b.HasIndex("DefinitionId");
+
+ b.HasIndex("PluginDefinitionId");
+
+ b.ToTable("PluginDefinitionType");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Policy", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ApiTokenId")
+ .HasColumnType("uuid");
+
+ b.Property("Area")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ApiTokenId");
+
+ b.ToTable("Policy");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Role", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SiteId");
+
+ b.ToTable("Role");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Settings", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Settings");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.Site", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("DetailLayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("EditLayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("LayoutId")
+ .HasColumnType("uuid");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DetailLayoutId");
+
+ b.HasIndex("EditLayoutId");
+
+ b.HasIndex("LayoutId");
+
+ b.ToTable("Sites");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.UserRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("CreatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ModifiedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ModifiedBy")
+ .HasColumnType("text");
+
+ b.Property("RoleId")
+ .HasColumnType("uuid");
+
+ b.Property("SiteId")
+ .HasColumnType("uuid");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.HasIndex("SiteId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserRole");
+ });
+
+ modelBuilder.Entity("FluentCMS.Entities.UserTwoFactorRecoveryCode", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Redeemed")
+ .HasColumnType("boolean");
+
+ b.Property("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserTwoFactorRecoveryCode");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property("ConcurrencyStamp")
+ .HasColumnType("text");
+
+ b.Property