< Summary - Heimdall API

Line coverage
100%
Covered lines: 978
Uncovered lines: 0
Coverable lines: 978
Total lines: 1093
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 3
Fully covered methods: 3
Total methods: 3
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: Up(...)100%11100%
File 1: Down(...)100%11100%
File 2: BuildTargetModel(...)100%11100%

File(s)

/home/ci/agent/workspace/heimdall-api-docs_main/app/src/Infrastructure/ArturRios.Heimdall.Data/Migrations/20260814160156_AddBruteForceGuardsAndEmailUniqueness.cs

#LineLine coverage
 1using System;
 2using Microsoft.EntityFrameworkCore.Migrations;
 3
 4#nullable disable
 5
 6namespace ArturRios.Heimdall.Data.Migrations
 7{
 8    /// <summary>
 9    ///     Adds the per-account brute-force counters (FR-AU-09, FR-2F-13) and the TOTP replay guard
 10    ///     (FR-2F-09), and turns the two email-uniqueness rules a unique index can express into
 11    ///     actual unique indexes (FR-PE-09, FR-GO-07).
 12    /// </summary>
 13    /// <remarks>
 14    ///     The indexes are raw SQL because EF Core models neither an index over an expression
 15    ///     (LOWER(email)) nor one filtered on a role set, and both properties matter: the application
 16    ///     compares addresses case-insensitively, so an index over the raw column would enforce a
 17    ///     different rule than the handlers apply, and an administrator's address only has to be
 18    ///     unique among live administrators.
 19    /// </remarks>
 20    public partial class AddBruteForceGuardsAndEmailUniqueness : Migration
 21    {
 22        /// <inheritdoc />
 23        protected override void Up(MigrationBuilder migrationBuilder)
 24        {
 1925            migrationBuilder.AddColumn<int>(
 1926                name: "failed_attempts",
 1927                schema: "heimdall",
 1928                table: "two_factor_email_code",
 1929                type: "integer",
 1930                nullable: false,
 1931                defaultValue: 0);
 32
 1933            migrationBuilder.AddColumn<long>(
 1934                name: "last_totp_time_step_used",
 1935                schema: "heimdall",
 1936                table: "two_factor_auth",
 1937                type: "bigint",
 1938                nullable: true);
 39
 1940            migrationBuilder.AddColumn<int>(
 1941                name: "failed_login_attempts",
 1942                schema: "heimdall",
 1943                table: "person",
 1944                type: "integer",
 1945                nullable: false,
 1946                defaultValue: 0);
 47
 1948            migrationBuilder.AddColumn<DateTime>(
 1949                name: "locked_out_until",
 1950                schema: "heimdall",
 1951                table: "person",
 1952                type: "timestamp with time zone",
 1953                nullable: true);
 54
 55            // FR-GO-07, Google User half: the address is unique within the scope, compared the way
 56            // the application compares it. The index this replaces was over the raw column, so
 57            // "[email protected]" and "[email protected]" were two free addresses to the database and one taken
 58            // address to GoogleSignInCommandHandler.
 59            //
 60            // Logically deleted rows are deliberately included, matching the handler: FR-GO-12 keeps
 61            // a deleted Google User addressable rather than erasing it, so the address it holds stays
 62            // taken until UC-29 removes the row for good.
 1963            migrationBuilder.Sql(
 1964                """
 1965                DROP INDEX heimdall.ix_google_user_scope_id_email;
 1966
 1967                CREATE UNIQUE INDEX ix_google_user_scope_id_email
 1968                    ON heimdall.google_user (scope_id, LOWER(email));
 1969                """);
 70
 71            // FR-PE-09, administrator half: unique system-wide across live ScopeAdmins (role 2) and
 72            // SystemAdmins (role 1). This is the enforcement, not a duplicate of the handlers' check
 73            // — a check-then-insert cannot be, since two concurrent creates both read "free" before
 74            // either writes, and the loser of that race becomes a person who can never log in
 75            // (UC-11's admin lookup resolves one row and stops).
 76            //
 77            // If this statement fails on an existing database, the data already violates FR-PE-09 and
 78            // the duplicates have to be resolved before the API can enforce it. Failing the migration
 79            // is the point: creating the index "if possible" would leave the invariant unenforced
 80            // with nothing to say so.
 81            //
 82            // The User half of FR-PE-09 — unique per scope — is not here and cannot be: the scope
 83            // lives in SCOPE_USER, and a PostgreSQL index covers one table. It stays enforced in the
 84            // application layer; see PersonDbMap for what closing its race would require.
 1985            migrationBuilder.Sql(
 1986                """
 1987                CREATE UNIQUE INDEX ux_person_admin_email
 1988                    ON heimdall.person (LOWER(email))
 1989                    WHERE role_id IN (1, 2) AND is_deleted = false;
 1990                """);
 1991        }
 92
 93        /// <inheritdoc />
 94        protected override void Down(MigrationBuilder migrationBuilder)
 95        {
 196            migrationBuilder.Sql(
 197                """
 198                DROP INDEX heimdall.ux_person_admin_email;
 199
 1100                DROP INDEX heimdall.ix_google_user_scope_id_email;
 1101
 1102                CREATE UNIQUE INDEX ix_google_user_scope_id_email
 1103                    ON heimdall.google_user (scope_id, email);
 1104                """);
 105
 1106            migrationBuilder.DropColumn(
 1107                name: "failed_attempts",
 1108                schema: "heimdall",
 1109                table: "two_factor_email_code");
 110
 1111            migrationBuilder.DropColumn(
 1112                name: "last_totp_time_step_used",
 1113                schema: "heimdall",
 1114                table: "two_factor_auth");
 115
 1116            migrationBuilder.DropColumn(
 1117                name: "failed_login_attempts",
 1118                schema: "heimdall",
 1119                table: "person");
 120
 1121            migrationBuilder.DropColumn(
 1122                name: "locked_out_until",
 1123                schema: "heimdall",
 1124                table: "person");
 1125        }
 126    }
 127}

/home/ci/agent/workspace/heimdall-api-docs_main/app/src/Infrastructure/ArturRios.Heimdall.Data/Migrations/20260814160156_AddBruteForceGuardsAndEmailUniqueness.Designer.cs

#LineLine coverage
 1// <auto-generated />
 2using System;
 3using ArturRios.Heimdall.Data.Configuration;
 4using Microsoft.EntityFrameworkCore;
 5using Microsoft.EntityFrameworkCore.Infrastructure;
 6using Microsoft.EntityFrameworkCore.Migrations;
 7using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 8using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
 9
 10#nullable disable
 11
 12namespace ArturRios.Heimdall.Data.Migrations
 13{
 14    [DbContext(typeof(AppDbContext))]
 15    [Migration("20260814160156_AddBruteForceGuardsAndEmailUniqueness")]
 16    partial class AddBruteForceGuardsAndEmailUniqueness
 17    {
 18        /// <inheritdoc />
 19        protected override void BuildTargetModel(ModelBuilder modelBuilder)
 20        {
 21#pragma warning disable 612, 618
 1022            modelBuilder
 1023                .HasDefaultSchema("heimdall")
 1024                .HasAnnotation("ProductVersion", "10.0.11")
 1025                .HasAnnotation("Relational:MaxIdentifierLength", 63);
 26
 1027            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
 28
 1029            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Application", b =>
 1030                {
 1031                    b.Property<long>("Id")
 1032                        .ValueGeneratedOnAdd()
 1033                        .HasColumnType("bigint")
 1034                        .HasColumnName("id")
 1035                        .HasColumnOrder(1);
 1036
 1037                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 1038
 1039                    b.Property<DateTime>("CreatedAt")
 1040                        .ValueGeneratedOnAdd()
 1041                        .HasColumnType("timestamp with time zone")
 1042                        .HasColumnName("created_at")
 1043                        .HasDefaultValueSql("now()");
 1044
 1045                    b.Property<bool>("IsDeleted")
 1046                        .ValueGeneratedOnAdd()
 1047                        .HasColumnType("boolean")
 1048                        .HasDefaultValue(false)
 1049                        .HasColumnName("is_deleted");
 1050
 1051                    b.Property<string>("Name")
 1052                        .IsRequired()
 1053                        .HasMaxLength(200)
 1054                        .HasColumnType("character varying(200)")
 1055                        .HasColumnName("name");
 1056
 1057                    b.Property<long>("OwnerId")
 1058                        .HasColumnType("bigint")
 1059                        .HasColumnName("owner_id");
 1060
 1061                    b.Property<Guid>("PublicId")
 1062                        .HasColumnType("uuid")
 1063                        .HasColumnName("public_id");
 1064
 1065                    b.Property<long>("ScopeId")
 1066                        .HasColumnType("bigint")
 1067                        .HasColumnName("scope_id");
 1068
 1069                    b.Property<DateTime>("UpdatedAt")
 1070                        .ValueGeneratedOnAdd()
 1071                        .HasColumnType("timestamp with time zone")
 1072                        .HasColumnName("updated_at")
 1073                        .HasDefaultValueSql("now()");
 1074
 1075                    b.HasKey("Id")
 1076                        .HasName("pk_application");
 1077
 1078                    b.HasIndex("OwnerId")
 1079                        .HasDatabaseName("ix_application_owner_id");
 1080
 1081                    b.HasIndex("PublicId")
 1082                        .IsUnique()
 1083                        .HasDatabaseName("ix_application_public_id");
 1084
 1085                    b.HasIndex("ScopeId")
 1086                        .HasDatabaseName("ix_application_scope_id");
 1087
 1088                    b.ToTable("application", "heimdall");
 2089                });
 90
 1091            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.AuditLog", b =>
 1092                {
 1093                    b.Property<long>("Id")
 1094                        .ValueGeneratedOnAdd()
 1095                        .HasColumnType("bigint")
 1096                        .HasColumnName("id")
 1097                        .HasColumnOrder(1);
 1098
 1099                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10100
 10101                    b.Property<string>("Action")
 10102                        .IsRequired()
 10103                        .HasMaxLength(200)
 10104                        .HasColumnType("character varying(200)")
 10105                        .HasColumnName("action");
 10106
 10107                    b.Property<Guid?>("ActorPersonId")
 10108                        .HasColumnType("uuid")
 10109                        .HasColumnName("actor_person_id");
 10110
 10111                    b.Property<int?>("ActorRole")
 10112                        .HasColumnType("integer")
 10113                        .HasColumnName("actor_role");
 10114
 10115                    b.Property<DateTime>("CreatedAt")
 10116                        .ValueGeneratedOnAdd()
 10117                        .HasColumnType("timestamp with time zone")
 10118                        .HasColumnName("created_at")
 10119                        .HasDefaultValueSql("now()");
 10120
 10121                    b.Property<Guid>("PublicId")
 10122                        .HasColumnType("uuid")
 10123                        .HasColumnName("public_id");
 10124
 10125                    b.Property<Guid?>("TargetId")
 10126                        .HasColumnType("uuid")
 10127                        .HasColumnName("target_id");
 10128
 10129                    b.HasKey("Id")
 10130                        .HasName("pk_audit_log");
 10131
 10132                    b.HasIndex("ActorPersonId")
 10133                        .HasDatabaseName("ix_audit_log_actor_person_id");
 10134
 10135                    b.HasIndex("CreatedAt")
 10136                        .HasDatabaseName("ix_audit_log_created_at");
 10137
 10138                    b.HasIndex("PublicId")
 10139                        .IsUnique()
 10140                        .HasDatabaseName("ix_audit_log_public_id");
 10141
 10142                    b.ToTable("audit_log", "heimdall");
 20143                });
 144
 10145            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.EmailVerificationToken", b =>
 10146                {
 10147                    b.Property<long>("Id")
 10148                        .ValueGeneratedOnAdd()
 10149                        .HasColumnType("bigint")
 10150                        .HasColumnName("id")
 10151                        .HasColumnOrder(1);
 10152
 10153                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10154
 10155                    b.Property<DateTime>("ExpiresAt")
 10156                        .HasColumnType("timestamp with time zone")
 10157                        .HasColumnName("expires_at");
 10158
 10159                    b.Property<long>("PersonId")
 10160                        .HasColumnType("bigint")
 10161                        .HasColumnName("person_id");
 10162
 10163                    b.Property<string>("Token")
 10164                        .IsRequired()
 10165                        .HasMaxLength(256)
 10166                        .HasColumnType("character varying(256)")
 10167                        .HasColumnName("token");
 10168
 10169                    b.Property<bool>("Used")
 10170                        .ValueGeneratedOnAdd()
 10171                        .HasColumnType("boolean")
 10172                        .HasDefaultValue(false)
 10173                        .HasColumnName("used");
 10174
 10175                    b.HasKey("Id")
 10176                        .HasName("pk_email_verification_token");
 10177
 10178                    b.HasIndex("PersonId")
 10179                        .HasDatabaseName("ix_email_verification_token_person_id");
 10180
 10181                    b.HasIndex("Token")
 10182                        .IsUnique()
 10183                        .HasDatabaseName("ix_email_verification_token_token");
 10184
 10185                    b.ToTable("email_verification_token", "heimdall");
 20186                });
 187
 10188            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.GoogleUser", b =>
 10189                {
 10190                    b.Property<long>("Id")
 10191                        .ValueGeneratedOnAdd()
 10192                        .HasColumnType("bigint")
 10193                        .HasColumnName("id")
 10194                        .HasColumnOrder(1);
 10195
 10196                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10197
 10198                    b.Property<DateTime>("CreatedAt")
 10199                        .ValueGeneratedOnAdd()
 10200                        .HasColumnType("timestamp with time zone")
 10201                        .HasColumnName("created_at")
 10202                        .HasDefaultValueSql("now()");
 10203
 10204                    b.Property<string>("Email")
 10205                        .IsRequired()
 10206                        .HasMaxLength(256)
 10207                        .HasColumnType("character varying(256)")
 10208                        .HasColumnName("email");
 10209
 10210                    b.Property<bool>("EmailVerified")
 10211                        .ValueGeneratedOnAdd()
 10212                        .HasColumnType("boolean")
 10213                        .HasDefaultValue(false)
 10214                        .HasColumnName("email_verified");
 10215
 10216                    b.Property<string>("GoogleId")
 10217                        .IsRequired()
 10218                        .HasMaxLength(255)
 10219                        .HasColumnType("character varying(255)")
 10220                        .HasColumnName("google_id");
 10221
 10222                    b.Property<bool>("IsDeleted")
 10223                        .ValueGeneratedOnAdd()
 10224                        .HasColumnType("boolean")
 10225                        .HasDefaultValue(false)
 10226                        .HasColumnName("is_deleted");
 10227
 10228                    b.Property<string>("Name")
 10229                        .IsRequired()
 10230                        .HasMaxLength(200)
 10231                        .HasColumnType("character varying(200)")
 10232                        .HasColumnName("name");
 10233
 10234                    b.Property<string>("ProfilePictureUrl")
 10235                        .HasMaxLength(2048)
 10236                        .HasColumnType("character varying(2048)")
 10237                        .HasColumnName("profile_picture_url");
 10238
 10239                    b.Property<Guid>("PublicId")
 10240                        .HasColumnType("uuid")
 10241                        .HasColumnName("public_id");
 10242
 10243                    b.Property<long>("ScopeId")
 10244                        .HasColumnType("bigint")
 10245                        .HasColumnName("scope_id");
 10246
 10247                    b.Property<DateTime>("UpdatedAt")
 10248                        .ValueGeneratedOnAdd()
 10249                        .HasColumnType("timestamp with time zone")
 10250                        .HasColumnName("updated_at")
 10251                        .HasDefaultValueSql("now()");
 10252
 10253                    b.HasKey("Id")
 10254                        .HasName("pk_google_user");
 10255
 10256                    b.HasIndex("PublicId")
 10257                        .IsUnique()
 10258                        .HasDatabaseName("ix_google_user_public_id");
 10259
 10260                    b.HasIndex("ScopeId", "Email")
 10261                        .IsUnique()
 10262                        .HasDatabaseName("ix_google_user_scope_id_email");
 10263
 10264                    b.HasIndex("ScopeId", "GoogleId")
 10265                        .IsUnique()
 10266                        .HasDatabaseName("ix_google_user_scope_id_google_id");
 10267
 10268                    b.ToTable("google_user", "heimdall");
 20269                });
 270
 10271            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.PasswordResetToken", b =>
 10272                {
 10273                    b.Property<long>("Id")
 10274                        .ValueGeneratedOnAdd()
 10275                        .HasColumnType("bigint")
 10276                        .HasColumnName("id")
 10277                        .HasColumnOrder(1);
 10278
 10279                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10280
 10281                    b.Property<DateTime>("ExpiresAt")
 10282                        .HasColumnType("timestamp with time zone")
 10283                        .HasColumnName("expires_at");
 10284
 10285                    b.Property<long>("PersonId")
 10286                        .HasColumnType("bigint")
 10287                        .HasColumnName("person_id");
 10288
 10289                    b.Property<string>("Token")
 10290                        .IsRequired()
 10291                        .HasMaxLength(256)
 10292                        .HasColumnType("character varying(256)")
 10293                        .HasColumnName("token");
 10294
 10295                    b.Property<bool>("Used")
 10296                        .ValueGeneratedOnAdd()
 10297                        .HasColumnType("boolean")
 10298                        .HasDefaultValue(false)
 10299                        .HasColumnName("used");
 10300
 10301                    b.HasKey("Id")
 10302                        .HasName("pk_password_reset_token");
 10303
 10304                    b.HasIndex("PersonId")
 10305                        .HasDatabaseName("ix_password_reset_token_person_id");
 10306
 10307                    b.HasIndex("Token")
 10308                        .IsUnique()
 10309                        .HasDatabaseName("ix_password_reset_token_token");
 10310
 10311                    b.ToTable("password_reset_token", "heimdall");
 20312                });
 313
 10314            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 10315                {
 10316                    b.Property<long>("Id")
 10317                        .ValueGeneratedOnAdd()
 10318                        .HasColumnType("bigint")
 10319                        .HasColumnName("id")
 10320                        .HasColumnOrder(1);
 10321
 10322                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10323
 10324                    b.Property<DateTime>("CreatedAt")
 10325                        .ValueGeneratedOnAdd()
 10326                        .HasColumnType("timestamp with time zone")
 10327                        .HasColumnName("created_at")
 10328                        .HasDefaultValueSql("now()");
 10329
 10330                    b.Property<string>("Email")
 10331                        .IsRequired()
 10332                        .HasMaxLength(256)
 10333                        .HasColumnType("character varying(256)")
 10334                        .HasColumnName("email");
 10335
 10336                    b.Property<bool>("EmailVerified")
 10337                        .ValueGeneratedOnAdd()
 10338                        .HasColumnType("boolean")
 10339                        .HasDefaultValue(false)
 10340                        .HasColumnName("email_verified");
 10341
 10342                    b.Property<int>("FailedLoginAttempts")
 10343                        .HasColumnType("integer")
 10344                        .HasColumnName("failed_login_attempts");
 10345
 10346                    b.Property<bool>("IsDeleted")
 10347                        .ValueGeneratedOnAdd()
 10348                        .HasColumnType("boolean")
 10349                        .HasDefaultValue(false)
 10350                        .HasColumnName("is_deleted");
 10351
 10352                    b.Property<DateTime?>("LockedOutUntil")
 10353                        .HasColumnType("timestamp with time zone")
 10354                        .HasColumnName("locked_out_until");
 10355
 10356                    b.Property<string>("Name")
 10357                        .IsRequired()
 10358                        .HasMaxLength(200)
 10359                        .HasColumnType("character varying(200)")
 10360                        .HasColumnName("name");
 10361
 10362                    b.Property<byte[]>("PasswordHash")
 10363                        .IsRequired()
 10364                        .HasColumnType("bytea")
 10365                        .HasColumnName("password_hash");
 10366
 10367                    b.Property<Guid>("PublicId")
 10368                        .HasColumnType("uuid")
 10369                        .HasColumnName("public_id");
 10370
 10371                    b.Property<long>("RoleId")
 10372                        .HasColumnType("bigint")
 10373                        .HasColumnName("role_id");
 10374
 10375                    b.Property<byte[]>("Salt")
 10376                        .IsRequired()
 10377                        .HasColumnType("bytea")
 10378                        .HasColumnName("salt");
 10379
 10380                    b.Property<DateTime>("UpdatedAt")
 10381                        .ValueGeneratedOnAdd()
 10382                        .HasColumnType("timestamp with time zone")
 10383                        .HasColumnName("updated_at")
 10384                        .HasDefaultValueSql("now()");
 10385
 10386                    b.HasKey("Id")
 10387                        .HasName("pk_person");
 10388
 10389                    b.HasIndex("Email")
 10390                        .HasDatabaseName("ix_person_email");
 10391
 10392                    b.HasIndex("PublicId")
 10393                        .IsUnique()
 10394                        .HasDatabaseName("ix_person_public_id");
 10395
 10396                    b.HasIndex("RoleId")
 10397                        .HasDatabaseName("ix_person_role_id");
 10398
 10399                    b.ToTable("person", "heimdall");
 20400                });
 401
 10402            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Role", b =>
 10403                {
 10404                    b.Property<long>("Id")
 10405                        .HasColumnType("bigint")
 10406                        .HasColumnName("id")
 10407                        .HasColumnOrder(1);
 10408
 10409                    b.Property<string>("Description")
 10410                        .HasMaxLength(500)
 10411                        .HasColumnType("character varying(500)")
 10412                        .HasColumnName("description");
 10413
 10414                    b.Property<string>("Name")
 10415                        .IsRequired()
 10416                        .HasMaxLength(200)
 10417                        .HasColumnType("character varying(200)")
 10418                        .HasColumnName("name");
 10419
 10420                    b.Property<Guid>("PublicId")
 10421                        .HasColumnType("uuid")
 10422                        .HasColumnName("public_id");
 10423
 10424                    b.HasKey("Id")
 10425                        .HasName("pk_role");
 10426
 10427                    b.HasIndex("Name")
 10428                        .IsUnique()
 10429                        .HasDatabaseName("ix_role_name");
 10430
 10431                    b.HasIndex("PublicId")
 10432                        .IsUnique()
 10433                        .HasDatabaseName("ix_role_public_id");
 10434
 10435                    b.ToTable("role", "heimdall");
 20436                });
 437
 10438            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Scope", b =>
 10439                {
 10440                    b.Property<long>("Id")
 10441                        .ValueGeneratedOnAdd()
 10442                        .HasColumnType("bigint")
 10443                        .HasColumnName("id")
 10444                        .HasColumnOrder(1);
 10445
 10446                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10447
 10448                    b.Property<DateTime>("CreatedAt")
 10449                        .ValueGeneratedOnAdd()
 10450                        .HasColumnType("timestamp with time zone")
 10451                        .HasColumnName("created_at")
 10452                        .HasDefaultValueSql("now()");
 10453
 10454                    b.Property<string>("Description")
 10455                        .HasMaxLength(500)
 10456                        .HasColumnType("character varying(500)")
 10457                        .HasColumnName("description");
 10458
 10459                    b.Property<bool>("GoogleSignInEnabled")
 10460                        .ValueGeneratedOnAdd()
 10461                        .HasColumnType("boolean")
 10462                        .HasDefaultValue(false)
 10463                        .HasColumnName("google_sign_in_enabled");
 10464
 10465                    b.Property<bool>("IsDeleted")
 10466                        .ValueGeneratedOnAdd()
 10467                        .HasColumnType("boolean")
 10468                        .HasDefaultValue(false)
 10469                        .HasColumnName("is_deleted");
 10470
 10471                    b.Property<string>("Name")
 10472                        .IsRequired()
 10473                        .HasMaxLength(200)
 10474                        .HasColumnType("character varying(200)")
 10475                        .HasColumnName("name");
 10476
 10477                    b.Property<Guid>("PublicId")
 10478                        .HasColumnType("uuid")
 10479                        .HasColumnName("public_id");
 10480
 10481                    b.Property<DateTime>("UpdatedAt")
 10482                        .ValueGeneratedOnAdd()
 10483                        .HasColumnType("timestamp with time zone")
 10484                        .HasColumnName("updated_at")
 10485                        .HasDefaultValueSql("now()");
 10486
 10487                    b.HasKey("Id")
 10488                        .HasName("pk_scope");
 10489
 10490                    b.HasIndex("Name")
 10491                        .IsUnique()
 10492                        .HasDatabaseName("ix_scope_name");
 10493
 10494                    b.HasIndex("PublicId")
 10495                        .IsUnique()
 10496                        .HasDatabaseName("ix_scope_public_id");
 10497
 10498                    b.ToTable("scope", "heimdall");
 20499                });
 500
 10501            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeOwner", b =>
 10502                {
 10503                    b.Property<long>("ScopeId")
 10504                        .HasColumnType("bigint")
 10505                        .HasColumnName("scope_id");
 10506
 10507                    b.Property<long>("PersonId")
 10508                        .HasColumnType("bigint")
 10509                        .HasColumnName("person_id");
 10510
 10511                    b.HasKey("ScopeId", "PersonId")
 10512                        .HasName("pk_scope_owner");
 10513
 10514                    b.HasIndex("PersonId")
 10515                        .HasDatabaseName("ix_scope_owner_person_id");
 10516
 10517                    b.ToTable("scope_owner", "heimdall");
 20518                });
 519
 10520            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopePermission", b =>
 10521                {
 10522                    b.Property<long>("Id")
 10523                        .ValueGeneratedOnAdd()
 10524                        .HasColumnType("bigint")
 10525                        .HasColumnName("id")
 10526                        .HasColumnOrder(1);
 10527
 10528                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10529
 10530                    b.Property<DateTime>("CreatedAt")
 10531                        .ValueGeneratedOnAdd()
 10532                        .HasColumnType("timestamp with time zone")
 10533                        .HasColumnName("created_at")
 10534                        .HasDefaultValueSql("now()");
 10535
 10536                    b.Property<string>("Description")
 10537                        .HasMaxLength(500)
 10538                        .HasColumnType("character varying(500)")
 10539                        .HasColumnName("description");
 10540
 10541                    b.Property<bool>("IncludeAsJwtClaim")
 10542                        .ValueGeneratedOnAdd()
 10543                        .HasColumnType("boolean")
 10544                        .HasDefaultValue(false)
 10545                        .HasColumnName("include_as_jwt_claim");
 10546
 10547                    b.Property<bool>("IsDeleted")
 10548                        .ValueGeneratedOnAdd()
 10549                        .HasColumnType("boolean")
 10550                        .HasDefaultValue(false)
 10551                        .HasColumnName("is_deleted");
 10552
 10553                    b.Property<string>("Name")
 10554                        .IsRequired()
 10555                        .HasMaxLength(200)
 10556                        .HasColumnType("character varying(200)")
 10557                        .HasColumnName("name");
 10558
 10559                    b.Property<Guid>("PublicId")
 10560                        .HasColumnType("uuid")
 10561                        .HasColumnName("public_id");
 10562
 10563                    b.Property<long>("ScopeId")
 10564                        .HasColumnType("bigint")
 10565                        .HasColumnName("scope_id");
 10566
 10567                    b.Property<DateTime>("UpdatedAt")
 10568                        .ValueGeneratedOnAdd()
 10569                        .HasColumnType("timestamp with time zone")
 10570                        .HasColumnName("updated_at")
 10571                        .HasDefaultValueSql("now()");
 10572
 10573                    b.HasKey("Id")
 10574                        .HasName("pk_scope_permission");
 10575
 10576                    b.HasIndex("PublicId")
 10577                        .IsUnique()
 10578                        .HasDatabaseName("ix_scope_permission_public_id");
 10579
 10580                    b.HasIndex("ScopeId")
 10581                        .HasDatabaseName("ix_scope_permission_scope_id");
 10582
 10583                    b.ToTable("scope_permission", "heimdall");
 20584                });
 585
 10586            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeUser", b =>
 10587                {
 10588                    b.Property<long>("ScopeId")
 10589                        .HasColumnType("bigint")
 10590                        .HasColumnName("scope_id");
 10591
 10592                    b.Property<long>("PersonId")
 10593                        .HasColumnType("bigint")
 10594                        .HasColumnName("person_id");
 10595
 10596                    b.HasKey("ScopeId", "PersonId")
 10597                        .HasName("pk_scope_user");
 10598
 10599                    b.HasIndex("PersonId")
 10600                        .IsUnique()
 10601                        .HasDatabaseName("ix_scope_user_person_id");
 10602
 10603                    b.ToTable("scope_user", "heimdall");
 20604                });
 605
 10606            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 10607                {
 10608                    b.Property<long>("Id")
 10609                        .ValueGeneratedOnAdd()
 10610                        .HasColumnType("bigint")
 10611                        .HasColumnName("id")
 10612                        .HasColumnOrder(1);
 10613
 10614                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10615
 10616                    b.Property<bool>("AppEnabled")
 10617                        .ValueGeneratedOnAdd()
 10618                        .HasColumnType("boolean")
 10619                        .HasDefaultValue(false)
 10620                        .HasColumnName("app_enabled");
 10621
 10622                    b.Property<DateTime>("CreatedAt")
 10623                        .ValueGeneratedOnAdd()
 10624                        .HasColumnType("timestamp with time zone")
 10625                        .HasColumnName("created_at")
 10626                        .HasDefaultValueSql("now()");
 10627
 10628                    b.Property<bool>("EmailEnabled")
 10629                        .ValueGeneratedOnAdd()
 10630                        .HasColumnType("boolean")
 10631                        .HasDefaultValue(false)
 10632                        .HasColumnName("email_enabled");
 10633
 10634                    b.Property<bool>("IsActive")
 10635                        .ValueGeneratedOnAdd()
 10636                        .HasColumnType("boolean")
 10637                        .HasDefaultValue(false)
 10638                        .HasColumnName("is_active");
 10639
 10640                    b.Property<long?>("LastTotpTimeStepUsed")
 10641                        .HasColumnType("bigint")
 10642                        .HasColumnName("last_totp_time_step_used");
 10643
 10644                    b.Property<long>("PersonId")
 10645                        .HasColumnType("bigint")
 10646                        .HasColumnName("person_id");
 10647
 10648                    b.Property<byte[]>("TotpSecretEncrypted")
 10649                        .HasColumnType("bytea")
 10650                        .HasColumnName("totp_secret_encrypted");
 10651
 10652                    b.Property<DateTime>("UpdatedAt")
 10653                        .ValueGeneratedOnAdd()
 10654                        .HasColumnType("timestamp with time zone")
 10655                        .HasColumnName("updated_at")
 10656                        .HasDefaultValueSql("now()");
 10657
 10658                    b.HasKey("Id")
 10659                        .HasName("pk_two_factor_auth");
 10660
 10661                    b.HasIndex("PersonId")
 10662                        .IsUnique()
 10663                        .HasDatabaseName("ix_two_factor_auth_person_id");
 10664
 10665                    b.ToTable("two_factor_auth", "heimdall");
 20666                });
 667
 10668            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorEmailCode", b =>
 10669                {
 10670                    b.Property<long>("Id")
 10671                        .ValueGeneratedOnAdd()
 10672                        .HasColumnType("bigint")
 10673                        .HasColumnName("id")
 10674                        .HasColumnOrder(1);
 10675
 10676                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10677
 10678                    b.Property<byte[]>("CodeHash")
 10679                        .IsRequired()
 10680                        .HasColumnType("bytea")
 10681                        .HasColumnName("code_hash");
 10682
 10683                    b.Property<DateTime>("CreatedAt")
 10684                        .ValueGeneratedOnAdd()
 10685                        .HasColumnType("timestamp with time zone")
 10686                        .HasColumnName("created_at")
 10687                        .HasDefaultValueSql("now()");
 10688
 10689                    b.Property<DateTime>("ExpiresAt")
 10690                        .HasColumnType("timestamp with time zone")
 10691                        .HasColumnName("expires_at");
 10692
 10693                    b.Property<int>("FailedAttempts")
 10694                        .HasColumnType("integer")
 10695                        .HasColumnName("failed_attempts");
 10696
 10697                    b.Property<byte[]>("Salt")
 10698                        .IsRequired()
 10699                        .HasColumnType("bytea")
 10700                        .HasColumnName("salt");
 10701
 10702                    b.Property<long>("TwoFactorAuthId")
 10703                        .HasColumnType("bigint")
 10704                        .HasColumnName("two_factor_auth_id");
 10705
 10706                    b.Property<bool>("Used")
 10707                        .ValueGeneratedOnAdd()
 10708                        .HasColumnType("boolean")
 10709                        .HasDefaultValue(false)
 10710                        .HasColumnName("used");
 10711
 10712                    b.HasKey("Id")
 10713                        .HasName("pk_two_factor_email_code");
 10714
 10715                    b.HasIndex("TwoFactorAuthId")
 10716                        .HasDatabaseName("ix_two_factor_email_code_two_factor_auth_id");
 10717
 10718                    b.ToTable("two_factor_email_code", "heimdall");
 20719                });
 720
 10721            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorRecoveryCode", b =>
 10722                {
 10723                    b.Property<long>("Id")
 10724                        .ValueGeneratedOnAdd()
 10725                        .HasColumnType("bigint")
 10726                        .HasColumnName("id")
 10727                        .HasColumnOrder(1);
 10728
 10729                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 10730
 10731                    b.Property<byte[]>("CodeHash")
 10732                        .IsRequired()
 10733                        .HasColumnType("bytea")
 10734                        .HasColumnName("code_hash");
 10735
 10736                    b.Property<DateTime>("CreatedAt")
 10737                        .ValueGeneratedOnAdd()
 10738                        .HasColumnType("timestamp with time zone")
 10739                        .HasColumnName("created_at")
 10740                        .HasDefaultValueSql("now()");
 10741
 10742                    b.Property<long>("TwoFactorAuthId")
 10743                        .HasColumnType("bigint")
 10744                        .HasColumnName("two_factor_auth_id");
 10745
 10746                    b.Property<bool>("Used")
 10747                        .ValueGeneratedOnAdd()
 10748                        .HasColumnType("boolean")
 10749                        .HasDefaultValue(false)
 10750                        .HasColumnName("used");
 10751
 10752                    b.Property<DateTime?>("UsedAt")
 10753                        .HasColumnType("timestamp with time zone")
 10754                        .HasColumnName("used_at");
 10755
 10756                    b.HasKey("Id")
 10757                        .HasName("pk_two_factor_recovery_code");
 10758
 10759                    b.HasIndex("TwoFactorAuthId")
 10760                        .HasDatabaseName("ix_two_factor_recovery_code_two_factor_auth_id");
 10761
 10762                    b.ToTable("two_factor_recovery_code", "heimdall");
 20763                });
 764
 10765            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Application", b =>
 10766                {
 10767                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Owner")
 10768                        .WithMany("OwnedApplications")
 10769                        .HasForeignKey("OwnerId")
 10770                        .OnDelete(DeleteBehavior.Cascade)
 10771                        .IsRequired()
 10772                        .HasConstraintName("fk_application_person_owner_id");
 10773
 10774                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 10775                        .WithMany("Applications")
 10776                        .HasForeignKey("ScopeId")
 10777                        .OnDelete(DeleteBehavior.Cascade)
 10778                        .IsRequired()
 10779                        .HasConstraintName("fk_application_scope_scope_id");
 10780
 10781                    b.Navigation("Owner");
 10782
 10783                    b.Navigation("Scope");
 20784                });
 785
 10786            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.EmailVerificationToken", b =>
 10787                {
 10788                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 10789                        .WithMany("EmailVerificationTokens")
 10790                        .HasForeignKey("PersonId")
 10791                        .OnDelete(DeleteBehavior.Cascade)
 10792                        .IsRequired()
 10793                        .HasConstraintName("fk_email_verification_token_person_person_id");
 10794
 10795                    b.Navigation("Person");
 20796                });
 797
 10798            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.GoogleUser", b =>
 10799                {
 10800                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 10801                        .WithMany("GoogleUsers")
 10802                        .HasForeignKey("ScopeId")
 10803                        .OnDelete(DeleteBehavior.Cascade)
 10804                        .IsRequired()
 10805                        .HasConstraintName("fk_google_user_scope_scope_id");
 10806
 10807                    b.Navigation("Scope");
 20808                });
 809
 10810            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.PasswordResetToken", b =>
 10811                {
 10812                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 10813                        .WithMany("PasswordResetTokens")
 10814                        .HasForeignKey("PersonId")
 10815                        .OnDelete(DeleteBehavior.Cascade)
 10816                        .IsRequired()
 10817                        .HasConstraintName("fk_password_reset_token_person_person_id");
 10818
 10819                    b.Navigation("Person");
 20820                });
 821
 10822            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 10823                {
 10824                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Role", "Role")
 10825                        .WithMany("Persons")
 10826                        .HasForeignKey("RoleId")
 10827                        .OnDelete(DeleteBehavior.Restrict)
 10828                        .IsRequired()
 10829                        .HasConstraintName("fk_person_roles_role_id");
 10830
 10831                    b.Navigation("Role");
 20832                });
 833
 10834            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeOwner", b =>
 10835                {
 10836                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 10837                        .WithMany("ScopeOwnerships")
 10838                        .HasForeignKey("PersonId")
 10839                        .OnDelete(DeleteBehavior.Cascade)
 10840                        .IsRequired()
 10841                        .HasConstraintName("fk_scope_owner_person_person_id");
 10842
 10843                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 10844                        .WithMany("Owners")
 10845                        .HasForeignKey("ScopeId")
 10846                        .OnDelete(DeleteBehavior.Cascade)
 10847                        .IsRequired()
 10848                        .HasConstraintName("fk_scope_owner_scope_scope_id");
 10849
 10850                    b.Navigation("Person");
 10851
 10852                    b.Navigation("Scope");
 20853                });
 854
 10855            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopePermission", b =>
 10856                {
 10857                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 10858                        .WithMany("ScopePermissions")
 10859                        .HasForeignKey("ScopeId")
 10860                        .OnDelete(DeleteBehavior.Cascade)
 10861                        .IsRequired()
 10862                        .HasConstraintName("fk_scope_permission_scope_scope_id");
 10863
 10864                    b.Navigation("Scope");
 20865                });
 866
 10867            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeUser", b =>
 10868                {
 10869                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 10870                        .WithOne("ScopeMembership")
 10871                        .HasForeignKey("ArturRios.Heimdall.Domain.Entities.ScopeUser", "PersonId")
 10872                        .OnDelete(DeleteBehavior.Cascade)
 10873                        .IsRequired()
 10874                        .HasConstraintName("fk_scope_user_person_person_id");
 10875
 10876                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 10877                        .WithMany("Users")
 10878                        .HasForeignKey("ScopeId")
 10879                        .OnDelete(DeleteBehavior.Cascade)
 10880                        .IsRequired()
 10881                        .HasConstraintName("fk_scope_user_scope_scope_id");
 10882
 10883                    b.Navigation("Person");
 10884
 10885                    b.Navigation("Scope");
 20886                });
 887
 10888            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 10889                {
 10890                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 10891                        .WithOne("TwoFactorAuth")
 10892                        .HasForeignKey("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "PersonId")
 10893                        .OnDelete(DeleteBehavior.Cascade)
 10894                        .IsRequired()
 10895                        .HasConstraintName("fk_two_factor_auth_person_person_id");
 10896
 10897                    b.Navigation("Person");
 20898                });
 899
 10900            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorEmailCode", b =>
 10901                {
 10902                    b.HasOne("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "TwoFactorAuth")
 10903                        .WithMany("EmailCodes")
 10904                        .HasForeignKey("TwoFactorAuthId")
 10905                        .OnDelete(DeleteBehavior.Cascade)
 10906                        .IsRequired()
 10907                        .HasConstraintName("fk_two_factor_email_code_two_factor_auth_two_factor_auth_id");
 10908
 10909                    b.Navigation("TwoFactorAuth");
 20910                });
 911
 10912            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorRecoveryCode", b =>
 10913                {
 10914                    b.HasOne("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "TwoFactorAuth")
 10915                        .WithMany("RecoveryCodes")
 10916                        .HasForeignKey("TwoFactorAuthId")
 10917                        .OnDelete(DeleteBehavior.Cascade)
 10918                        .IsRequired()
 10919                        .HasConstraintName("fk_two_factor_recovery_code_two_factor_auth_two_factor_auth_id");
 10920
 10921                    b.Navigation("TwoFactorAuth");
 20922                });
 923
 10924            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 10925                {
 10926                    b.Navigation("EmailVerificationTokens");
 10927
 10928                    b.Navigation("OwnedApplications");
 10929
 10930                    b.Navigation("PasswordResetTokens");
 10931
 10932                    b.Navigation("ScopeMembership");
 10933
 10934                    b.Navigation("ScopeOwnerships");
 10935
 10936                    b.Navigation("TwoFactorAuth");
 20937                });
 938
 10939            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Role", b =>
 10940                {
 10941                    b.Navigation("Persons");
 20942                });
 943
 10944            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Scope", b =>
 10945                {
 10946                    b.Navigation("Applications");
 10947
 10948                    b.Navigation("GoogleUsers");
 10949
 10950                    b.Navigation("Owners");
 10951
 10952                    b.Navigation("ScopePermissions");
 10953
 10954                    b.Navigation("Users");
 20955                });
 956
 10957            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 10958                {
 10959                    b.Navigation("EmailCodes");
 10960
 10961                    b.Navigation("RecoveryCodes");
 20962                });
 963#pragma warning restore 612, 618
 10964        }
 965    }
 966}