< Summary - Heimdall API

Line coverage
98%
Covered lines: 1065
Uncovered lines: 11
Coverable lines: 1076
Total lines: 1182
Line coverage: 98.9%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
66%
Covered methods: 2
Fully covered methods: 2
Total methods: 3
Method coverage: 66.6%
Full method coverage: 66.6%

Metrics

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

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Infrastructure/ArturRios.Heimdall.Data/Migrations/20260909182313_AllowClearingAuditActor.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore.Migrations;
 2
 3#nullable disable
 4
 5namespace ArturRios.Heimdall.Data.Migrations
 6{
 7    /// <summary>
 8    ///     Narrows the audit log's append-only rule by exactly one permitted change: the actor
 9    ///     attribution may be cleared once it is due (NFR-21).
 10    /// </summary>
 11    /// <remarks>
 12    ///     <para>
 13    ///         `MakeAuditLogAppendOnly` refused every UPDATE, DELETE and TRUNCATE, which closed
 14    ///         Threat Model TH-18 and also made erasure impossible: `actor_person_id` holds a
 15    ///         person's `PublicId`, so an indefinitely retained, unalterable row naming an erased
 16    ///         person is personal data processed with no remaining basis.
 17    ///     </para>
 18    ///     <para>
 19    ///         Rather than dropping the guarantee, this narrows it. DELETE and TRUNCATE stay refused
 20    ///         outright. UPDATE becomes row-level and is permitted only when every column except
 21    ///         `actor_person_id` and `actor_role` is unchanged, the attribution is being set to
 22    ///         NULL rather than to somebody else, and the clearing is due. The resulting rule is
 23    ///         precise: <b>an action can never be denied, and who took it can never be reassigned —
 24    ///         only forgotten, on schedule or on erasure.</b>
 25    ///     </para>
 26    ///     <para>
 27    ///         "Due" means the entry is older than a thirty-day floor, or the identity it names has
 28    ///         been anonymised. The floor is an anti-tamper backstop rather than a retention policy:
 29    ///         the retention period is configuration and is far longer, and the floor exists so that
 30    ///         somebody who has just acted cannot immediately erase their own attribution. The
 31    ///         erasure branch carries no age condition, because a subject-requested erasure completes
 32    ///         thirty days after the request and their most recent entries must go with them.
 33    ///     </para>
 34    /// </remarks>
 35    public partial class AllowClearingAuditActor : Migration
 36    {
 37        /// <inheritdoc />
 38        protected override void Up(MigrationBuilder migrationBuilder)
 39        {
 440            migrationBuilder.Sql(
 441                """
 442                CREATE OR REPLACE FUNCTION heimdall.audit_log_actor_clear_only()
 443                RETURNS TRIGGER AS $$
 444                DECLARE
 445                    actor_erased boolean;
 446                BEGIN
 447                    -- Everything but the attribution is immutable. Checked first, so an attempt to
 448                    -- rewrite what happened is refused with that reason rather than a later one.
 449                    IF NEW.public_id IS DISTINCT FROM OLD.public_id
 450                       OR NEW.action IS DISTINCT FROM OLD.action
 451                       OR NEW.target_id IS DISTINCT FROM OLD.target_id
 452                       OR NEW.succeeded IS DISTINCT FROM OLD.succeeded
 453                       OR NEW.failure_reason IS DISTINCT FROM OLD.failure_reason
 454                       OR NEW.created_at IS DISTINCT FROM OLD.created_at
 455                    THEN
 456                        RAISE EXCEPTION
 457                            'heimdall.audit_log is append-only: only the actor attribution may be cleared'
 458                            USING ERRCODE = 'restrict_violation';
 459                    END IF;
 460
 461                    -- Cleared, never reassigned. Without this the trail could be made to say that
 462                    -- somebody else took the action, which is worse than it not saying who did.
 463                    IF NEW.actor_person_id IS NOT NULL OR NEW.actor_role IS NOT NULL THEN
 464                        RAISE EXCEPTION
 465                            'heimdall.audit_log actor attribution may be cleared but not reassigned'
 466                            USING ERRCODE = 'restrict_violation';
 467                    END IF;
 468
 469                    -- Already clear: a no-op write, permitted so a re-run is not an error.
 470                    IF OLD.actor_person_id IS NULL AND OLD.actor_role IS NULL THEN
 471                        RETURN NEW;
 472                    END IF;
 473
 474                    SELECT EXISTS (
 475                        SELECT 1 FROM heimdall.person p
 476                        WHERE p.public_id = OLD.actor_person_id AND p.anonymised_at IS NOT NULL
 477                        UNION ALL
 478                        SELECT 1 FROM heimdall.google_user g
 479                        WHERE g.public_id = OLD.actor_person_id AND g.anonymised_at IS NOT NULL
 480                    ) INTO actor_erased;
 481
 482                    IF actor_erased OR OLD.created_at <= now() - interval '30 days' THEN
 483                        RETURN NEW;
 484                    END IF;
 485
 486                    RAISE EXCEPTION
 487                        'heimdall.audit_log actor attribution is not yet due to be cleared'
 488                        USING ERRCODE = 'restrict_violation';
 489                END;
 490                $$ LANGUAGE plpgsql;
 491                """);
 92
 93            // The statement-level UPDATE trigger goes: the rule is now about which row-level change
 94            // is being made, which a statement-level trigger cannot see.
 495            migrationBuilder.Sql("DROP TRIGGER IF EXISTS audit_log_no_update ON heimdall.audit_log;");
 96
 497            migrationBuilder.Sql(
 498                """
 499                CREATE TRIGGER audit_log_actor_clear_only
 4100                BEFORE UPDATE ON heimdall.audit_log
 4101                FOR EACH ROW EXECUTE FUNCTION heimdall.audit_log_actor_clear_only();
 4102                """);
 4103        }
 104
 105        /// <inheritdoc />
 106        protected override void Down(MigrationBuilder migrationBuilder)
 107        {
 0108            migrationBuilder.Sql(
 0109                "DROP TRIGGER IF EXISTS audit_log_actor_clear_only ON heimdall.audit_log;");
 0110            migrationBuilder.Sql(
 0111                "DROP FUNCTION IF EXISTS heimdall.audit_log_actor_clear_only();");
 112
 113            // Back to refusing every UPDATE.
 0114            migrationBuilder.Sql(
 0115                """
 0116                CREATE TRIGGER audit_log_no_update
 0117                BEFORE UPDATE ON heimdall.audit_log
 0118                FOR EACH STATEMENT EXECUTE FUNCTION heimdall.audit_log_is_append_only();
 0119                """);
 0120        }
 121    }
 122}

/home/runner/work/heimdall-api/heimdall-api/src/Infrastructure/ArturRios.Heimdall.Data/Migrations/20260909182313_AllowClearingAuditActor.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("20260909182313_AllowClearingAuditActor")]
 16    partial class AllowClearingAuditActor
 17    {
 18        /// <inheritdoc />
 19        protected override void BuildTargetModel(ModelBuilder modelBuilder)
 20        {
 21#pragma warning disable 612, 618
 222            modelBuilder
 223                .HasDefaultSchema("heimdall")
 224                .HasAnnotation("ProductVersion", "10.0.11")
 225                .HasAnnotation("Relational:MaxIdentifierLength", 63);
 26
 227            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
 28
 229            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Application", b =>
 230                {
 231                    b.Property<long>("Id")
 232                        .ValueGeneratedOnAdd()
 233                        .HasColumnType("bigint")
 234                        .HasColumnName("id")
 235                        .HasColumnOrder(1);
 236
 237                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 238
 239                    b.Property<DateTime>("CreatedAt")
 240                        .ValueGeneratedOnAdd()
 241                        .HasColumnType("timestamp with time zone")
 242                        .HasColumnName("created_at")
 243                        .HasDefaultValueSql("now()");
 244
 245                    b.Property<bool>("IsDeleted")
 246                        .ValueGeneratedOnAdd()
 247                        .HasColumnType("boolean")
 248                        .HasDefaultValue(false)
 249                        .HasColumnName("is_deleted");
 250
 251                    b.Property<string>("Name")
 252                        .IsRequired()
 253                        .HasMaxLength(200)
 254                        .HasColumnType("character varying(200)")
 255                        .HasColumnName("name");
 256
 257                    b.Property<long>("OwnerId")
 258                        .HasColumnType("bigint")
 259                        .HasColumnName("owner_id");
 260
 261                    b.Property<Guid>("PublicId")
 262                        .HasColumnType("uuid")
 263                        .HasColumnName("public_id");
 264
 265                    b.Property<long>("ScopeId")
 266                        .HasColumnType("bigint")
 267                        .HasColumnName("scope_id");
 268
 269                    b.Property<DateTime>("UpdatedAt")
 270                        .ValueGeneratedOnAdd()
 271                        .HasColumnType("timestamp with time zone")
 272                        .HasColumnName("updated_at")
 273                        .HasDefaultValueSql("now()");
 274
 275                    b.HasKey("Id")
 276                        .HasName("pk_application");
 277
 278                    b.HasIndex("OwnerId")
 279                        .HasDatabaseName("ix_application_owner_id");
 280
 281                    b.HasIndex("PublicId")
 282                        .IsUnique()
 283                        .HasDatabaseName("ix_application_public_id");
 284
 285                    b.HasIndex("ScopeId")
 286                        .HasDatabaseName("ix_application_scope_id");
 287
 288                    b.ToTable("application", "heimdall");
 489                });
 90
 291            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.AuditLog", b =>
 292                {
 293                    b.Property<long>("Id")
 294                        .ValueGeneratedOnAdd()
 295                        .HasColumnType("bigint")
 296                        .HasColumnName("id")
 297                        .HasColumnOrder(1);
 298
 299                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2100
 2101                    b.Property<string>("Action")
 2102                        .IsRequired()
 2103                        .HasMaxLength(200)
 2104                        .HasColumnType("character varying(200)")
 2105                        .HasColumnName("action");
 2106
 2107                    b.Property<Guid?>("ActorPersonId")
 2108                        .HasColumnType("uuid")
 2109                        .HasColumnName("actor_person_id");
 2110
 2111                    b.Property<int?>("ActorRole")
 2112                        .HasColumnType("integer")
 2113                        .HasColumnName("actor_role");
 2114
 2115                    b.Property<DateTime>("CreatedAt")
 2116                        .ValueGeneratedOnAdd()
 2117                        .HasColumnType("timestamp with time zone")
 2118                        .HasColumnName("created_at")
 2119                        .HasDefaultValueSql("now()");
 2120
 2121                    b.Property<string>("FailureReason")
 2122                        .HasMaxLength(500)
 2123                        .HasColumnType("character varying(500)")
 2124                        .HasColumnName("failure_reason");
 2125
 2126                    b.Property<Guid>("PublicId")
 2127                        .HasColumnType("uuid")
 2128                        .HasColumnName("public_id");
 2129
 2130                    b.Property<bool>("Succeeded")
 2131                        .HasColumnType("boolean")
 2132                        .HasColumnName("succeeded");
 2133
 2134                    b.Property<Guid?>("TargetId")
 2135                        .HasColumnType("uuid")
 2136                        .HasColumnName("target_id");
 2137
 2138                    b.HasKey("Id")
 2139                        .HasName("pk_audit_log");
 2140
 2141                    b.HasIndex("ActorPersonId")
 2142                        .HasDatabaseName("ix_audit_log_actor_person_id");
 2143
 2144                    b.HasIndex("CreatedAt")
 2145                        .HasDatabaseName("ix_audit_log_created_at");
 2146
 2147                    b.HasIndex("PublicId")
 2148                        .IsUnique()
 2149                        .HasDatabaseName("ix_audit_log_public_id");
 2150
 2151                    b.ToTable("audit_log", "heimdall");
 4152                });
 153
 2154            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.EmailVerificationToken", b =>
 2155                {
 2156                    b.Property<long>("Id")
 2157                        .ValueGeneratedOnAdd()
 2158                        .HasColumnType("bigint")
 2159                        .HasColumnName("id")
 2160                        .HasColumnOrder(1);
 2161
 2162                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2163
 2164                    b.Property<DateTime>("ExpiresAt")
 2165                        .HasColumnType("timestamp with time zone")
 2166                        .HasColumnName("expires_at");
 2167
 2168                    b.Property<long>("PersonId")
 2169                        .HasColumnType("bigint")
 2170                        .HasColumnName("person_id");
 2171
 2172                    b.Property<string>("TokenHash")
 2173                        .IsRequired()
 2174                        .HasMaxLength(64)
 2175                        .HasColumnType("character varying(64)")
 2176                        .HasColumnName("token_hash");
 2177
 2178                    b.Property<bool>("Used")
 2179                        .ValueGeneratedOnAdd()
 2180                        .HasColumnType("boolean")
 2181                        .HasDefaultValue(false)
 2182                        .HasColumnName("used");
 2183
 2184                    b.HasKey("Id")
 2185                        .HasName("pk_email_verification_token");
 2186
 2187                    b.HasIndex("PersonId")
 2188                        .HasDatabaseName("ix_email_verification_token_person_id");
 2189
 2190                    b.HasIndex("TokenHash")
 2191                        .IsUnique()
 2192                        .HasDatabaseName("ix_email_verification_token_token_hash");
 2193
 2194                    b.ToTable("email_verification_token", "heimdall");
 4195                });
 196
 2197            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.GoogleUser", b =>
 2198                {
 2199                    b.Property<long>("Id")
 2200                        .ValueGeneratedOnAdd()
 2201                        .HasColumnType("bigint")
 2202                        .HasColumnName("id")
 2203                        .HasColumnOrder(1);
 2204
 2205                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2206
 2207                    b.Property<DateTime?>("AnonymisedAt")
 2208                        .HasColumnType("timestamp with time zone")
 2209                        .HasColumnName("anonymised_at");
 2210
 2211                    b.Property<DateTime>("CreatedAt")
 2212                        .ValueGeneratedOnAdd()
 2213                        .HasColumnType("timestamp with time zone")
 2214                        .HasColumnName("created_at")
 2215                        .HasDefaultValueSql("now()");
 2216
 2217                    b.Property<DateTime?>("DeletedAt")
 2218                        .HasColumnType("timestamp with time zone")
 2219                        .HasColumnName("deleted_at");
 2220
 2221                    b.Property<int?>("DeletionKind")
 2222                        .HasColumnType("integer")
 2223                        .HasColumnName("deletion_kind");
 2224
 2225                    b.Property<string>("Email")
 2226                        .IsRequired()
 2227                        .HasMaxLength(256)
 2228                        .HasColumnType("character varying(256)")
 2229                        .HasColumnName("email");
 2230
 2231                    b.Property<bool>("EmailVerified")
 2232                        .ValueGeneratedOnAdd()
 2233                        .HasColumnType("boolean")
 2234                        .HasDefaultValue(false)
 2235                        .HasColumnName("email_verified");
 2236
 2237                    b.Property<string>("ErasureBlockedReason")
 2238                        .HasMaxLength(500)
 2239                        .HasColumnType("character varying(500)")
 2240                        .HasColumnName("erasure_blocked_reason");
 2241
 2242                    b.Property<DateTime?>("ErasureDueAt")
 2243                        .HasColumnType("timestamp with time zone")
 2244                        .HasColumnName("erasure_due_at");
 2245
 2246                    b.Property<DateTime?>("ErasureRequestedAt")
 2247                        .HasColumnType("timestamp with time zone")
 2248                        .HasColumnName("erasure_requested_at");
 2249
 2250                    b.Property<string>("GoogleId")
 2251                        .IsRequired()
 2252                        .HasMaxLength(255)
 2253                        .HasColumnType("character varying(255)")
 2254                        .HasColumnName("google_id");
 2255
 2256                    b.Property<bool>("IsDeleted")
 2257                        .ValueGeneratedOnAdd()
 2258                        .HasColumnType("boolean")
 2259                        .HasDefaultValue(false)
 2260                        .HasColumnName("is_deleted");
 2261
 2262                    b.Property<string>("Name")
 2263                        .IsRequired()
 2264                        .HasMaxLength(200)
 2265                        .HasColumnType("character varying(200)")
 2266                        .HasColumnName("name");
 2267
 2268                    b.Property<string>("ProfilePictureUrl")
 2269                        .HasMaxLength(2048)
 2270                        .HasColumnType("character varying(2048)")
 2271                        .HasColumnName("profile_picture_url");
 2272
 2273                    b.Property<Guid>("PublicId")
 2274                        .HasColumnType("uuid")
 2275                        .HasColumnName("public_id");
 2276
 2277                    b.Property<long>("ScopeId")
 2278                        .HasColumnType("bigint")
 2279                        .HasColumnName("scope_id");
 2280
 2281                    b.Property<DateTime>("UpdatedAt")
 2282                        .ValueGeneratedOnAdd()
 2283                        .HasColumnType("timestamp with time zone")
 2284                        .HasColumnName("updated_at")
 2285                        .HasDefaultValueSql("now()");
 2286
 2287                    b.HasKey("Id")
 2288                        .HasName("pk_google_user");
 2289
 2290                    b.HasIndex("DeletedAt")
 2291                        .HasDatabaseName("ix_google_user_deleted_at")
 2292                        .HasFilter("is_deleted = true AND anonymised_at IS NULL");
 2293
 2294                    b.HasIndex("PublicId")
 2295                        .IsUnique()
 2296                        .HasDatabaseName("ix_google_user_public_id");
 2297
 2298                    b.HasIndex("ScopeId", "Email")
 2299                        .IsUnique()
 2300                        .HasDatabaseName("ix_google_user_scope_id_email");
 2301
 2302                    b.HasIndex("ScopeId", "GoogleId")
 2303                        .IsUnique()
 2304                        .HasDatabaseName("ix_google_user_scope_id_google_id");
 2305
 2306                    b.ToTable("google_user", "heimdall");
 4307                });
 308
 2309            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.PasswordResetToken", b =>
 2310                {
 2311                    b.Property<long>("Id")
 2312                        .ValueGeneratedOnAdd()
 2313                        .HasColumnType("bigint")
 2314                        .HasColumnName("id")
 2315                        .HasColumnOrder(1);
 2316
 2317                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2318
 2319                    b.Property<DateTime>("ExpiresAt")
 2320                        .HasColumnType("timestamp with time zone")
 2321                        .HasColumnName("expires_at");
 2322
 2323                    b.Property<long>("PersonId")
 2324                        .HasColumnType("bigint")
 2325                        .HasColumnName("person_id");
 2326
 2327                    b.Property<string>("TokenHash")
 2328                        .IsRequired()
 2329                        .HasMaxLength(64)
 2330                        .HasColumnType("character varying(64)")
 2331                        .HasColumnName("token_hash");
 2332
 2333                    b.Property<bool>("Used")
 2334                        .ValueGeneratedOnAdd()
 2335                        .HasColumnType("boolean")
 2336                        .HasDefaultValue(false)
 2337                        .HasColumnName("used");
 2338
 2339                    b.HasKey("Id")
 2340                        .HasName("pk_password_reset_token");
 2341
 2342                    b.HasIndex("PersonId")
 2343                        .HasDatabaseName("ix_password_reset_token_person_id");
 2344
 2345                    b.HasIndex("TokenHash")
 2346                        .IsUnique()
 2347                        .HasDatabaseName("ix_password_reset_token_token_hash");
 2348
 2349                    b.ToTable("password_reset_token", "heimdall");
 4350                });
 351
 2352            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 2353                {
 2354                    b.Property<long>("Id")
 2355                        .ValueGeneratedOnAdd()
 2356                        .HasColumnType("bigint")
 2357                        .HasColumnName("id")
 2358                        .HasColumnOrder(1);
 2359
 2360                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2361
 2362                    b.Property<DateTime?>("AnonymisedAt")
 2363                        .HasColumnType("timestamp with time zone")
 2364                        .HasColumnName("anonymised_at");
 2365
 2366                    b.Property<DateTime>("CreatedAt")
 2367                        .ValueGeneratedOnAdd()
 2368                        .HasColumnType("timestamp with time zone")
 2369                        .HasColumnName("created_at")
 2370                        .HasDefaultValueSql("now()");
 2371
 2372                    b.Property<DateTime?>("DeletedAt")
 2373                        .HasColumnType("timestamp with time zone")
 2374                        .HasColumnName("deleted_at");
 2375
 2376                    b.Property<int?>("DeletionKind")
 2377                        .HasColumnType("integer")
 2378                        .HasColumnName("deletion_kind");
 2379
 2380                    b.Property<string>("Email")
 2381                        .IsRequired()
 2382                        .HasMaxLength(256)
 2383                        .HasColumnType("character varying(256)")
 2384                        .HasColumnName("email");
 2385
 2386                    b.Property<bool>("EmailVerified")
 2387                        .ValueGeneratedOnAdd()
 2388                        .HasColumnType("boolean")
 2389                        .HasDefaultValue(false)
 2390                        .HasColumnName("email_verified");
 2391
 2392                    b.Property<string>("ErasureBlockedReason")
 2393                        .HasMaxLength(500)
 2394                        .HasColumnType("character varying(500)")
 2395                        .HasColumnName("erasure_blocked_reason");
 2396
 2397                    b.Property<DateTime?>("ErasureDueAt")
 2398                        .HasColumnType("timestamp with time zone")
 2399                        .HasColumnName("erasure_due_at");
 2400
 2401                    b.Property<DateTime?>("ErasureRequestedAt")
 2402                        .HasColumnType("timestamp with time zone")
 2403                        .HasColumnName("erasure_requested_at");
 2404
 2405                    b.Property<int>("FailedLoginAttempts")
 2406                        .HasColumnType("integer")
 2407                        .HasColumnName("failed_login_attempts");
 2408
 2409                    b.Property<bool>("IsDeleted")
 2410                        .ValueGeneratedOnAdd()
 2411                        .HasColumnType("boolean")
 2412                        .HasDefaultValue(false)
 2413                        .HasColumnName("is_deleted");
 2414
 2415                    b.Property<DateTime?>("LockedOutUntil")
 2416                        .HasColumnType("timestamp with time zone")
 2417                        .HasColumnName("locked_out_until");
 2418
 2419                    b.Property<string>("Name")
 2420                        .IsRequired()
 2421                        .HasMaxLength(200)
 2422                        .HasColumnType("character varying(200)")
 2423                        .HasColumnName("name");
 2424
 2425                    b.Property<byte[]>("PasswordHash")
 2426                        .IsRequired()
 2427                        .HasColumnType("bytea")
 2428                        .HasColumnName("password_hash");
 2429
 2430                    b.Property<Guid>("PublicId")
 2431                        .HasColumnType("uuid")
 2432                        .HasColumnName("public_id");
 2433
 2434                    b.Property<long>("RoleId")
 2435                        .HasColumnType("bigint")
 2436                        .HasColumnName("role_id");
 2437
 2438                    b.Property<byte[]>("Salt")
 2439                        .IsRequired()
 2440                        .HasColumnType("bytea")
 2441                        .HasColumnName("salt");
 2442
 2443                    b.Property<long?>("ScopeId")
 2444                        .HasColumnType("bigint")
 2445                        .HasColumnName("scope_id");
 2446
 2447                    b.Property<DateTime>("UpdatedAt")
 2448                        .ValueGeneratedOnAdd()
 2449                        .HasColumnType("timestamp with time zone")
 2450                        .HasColumnName("updated_at")
 2451                        .HasDefaultValueSql("now()");
 2452
 2453                    b.HasKey("Id")
 2454                        .HasName("pk_person");
 2455
 2456                    b.HasIndex("DeletedAt")
 2457                        .HasDatabaseName("ix_person_deleted_at")
 2458                        .HasFilter("is_deleted = true AND anonymised_at IS NULL");
 2459
 2460                    b.HasIndex("Email")
 2461                        .HasDatabaseName("ix_person_email");
 2462
 2463                    b.HasIndex("PublicId")
 2464                        .IsUnique()
 2465                        .HasDatabaseName("ix_person_public_id");
 2466
 2467                    b.HasIndex("RoleId")
 2468                        .HasDatabaseName("ix_person_role_id");
 2469
 2470                    b.ToTable("person", "heimdall");
 4471                });
 472
 2473            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Role", b =>
 2474                {
 2475                    b.Property<long>("Id")
 2476                        .HasColumnType("bigint")
 2477                        .HasColumnName("id")
 2478                        .HasColumnOrder(1);
 2479
 2480                    b.Property<string>("Description")
 2481                        .HasMaxLength(500)
 2482                        .HasColumnType("character varying(500)")
 2483                        .HasColumnName("description");
 2484
 2485                    b.Property<string>("Name")
 2486                        .IsRequired()
 2487                        .HasMaxLength(200)
 2488                        .HasColumnType("character varying(200)")
 2489                        .HasColumnName("name");
 2490
 2491                    b.Property<Guid>("PublicId")
 2492                        .HasColumnType("uuid")
 2493                        .HasColumnName("public_id");
 2494
 2495                    b.HasKey("Id")
 2496                        .HasName("pk_role");
 2497
 2498                    b.HasIndex("Name")
 2499                        .IsUnique()
 2500                        .HasDatabaseName("ix_role_name");
 2501
 2502                    b.HasIndex("PublicId")
 2503                        .IsUnique()
 2504                        .HasDatabaseName("ix_role_public_id");
 2505
 2506                    b.ToTable("role", "heimdall");
 4507                });
 508
 2509            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Scope", b =>
 2510                {
 2511                    b.Property<long>("Id")
 2512                        .ValueGeneratedOnAdd()
 2513                        .HasColumnType("bigint")
 2514                        .HasColumnName("id")
 2515                        .HasColumnOrder(1);
 2516
 2517                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2518
 2519                    b.Property<DateTime>("CreatedAt")
 2520                        .ValueGeneratedOnAdd()
 2521                        .HasColumnType("timestamp with time zone")
 2522                        .HasColumnName("created_at")
 2523                        .HasDefaultValueSql("now()");
 2524
 2525                    b.Property<string>("Description")
 2526                        .HasMaxLength(500)
 2527                        .HasColumnType("character varying(500)")
 2528                        .HasColumnName("description");
 2529
 2530                    b.Property<bool>("GoogleSignInEnabled")
 2531                        .ValueGeneratedOnAdd()
 2532                        .HasColumnType("boolean")
 2533                        .HasDefaultValue(false)
 2534                        .HasColumnName("google_sign_in_enabled");
 2535
 2536                    b.Property<bool>("IsDeleted")
 2537                        .ValueGeneratedOnAdd()
 2538                        .HasColumnType("boolean")
 2539                        .HasDefaultValue(false)
 2540                        .HasColumnName("is_deleted");
 2541
 2542                    b.Property<string>("Name")
 2543                        .IsRequired()
 2544                        .HasMaxLength(200)
 2545                        .HasColumnType("character varying(200)")
 2546                        .HasColumnName("name");
 2547
 2548                    b.Property<Guid>("PublicId")
 2549                        .HasColumnType("uuid")
 2550                        .HasColumnName("public_id");
 2551
 2552                    b.Property<DateTime>("UpdatedAt")
 2553                        .ValueGeneratedOnAdd()
 2554                        .HasColumnType("timestamp with time zone")
 2555                        .HasColumnName("updated_at")
 2556                        .HasDefaultValueSql("now()");
 2557
 2558                    b.HasKey("Id")
 2559                        .HasName("pk_scope");
 2560
 2561                    b.HasIndex("Name")
 2562                        .IsUnique()
 2563                        .HasDatabaseName("ix_scope_name");
 2564
 2565                    b.HasIndex("PublicId")
 2566                        .IsUnique()
 2567                        .HasDatabaseName("ix_scope_public_id");
 2568
 2569                    b.ToTable("scope", "heimdall");
 4570                });
 571
 2572            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeOwner", b =>
 2573                {
 2574                    b.Property<long>("ScopeId")
 2575                        .HasColumnType("bigint")
 2576                        .HasColumnName("scope_id");
 2577
 2578                    b.Property<long>("PersonId")
 2579                        .HasColumnType("bigint")
 2580                        .HasColumnName("person_id");
 2581
 2582                    b.HasKey("ScopeId", "PersonId")
 2583                        .HasName("pk_scope_owner");
 2584
 2585                    b.HasIndex("PersonId")
 2586                        .HasDatabaseName("ix_scope_owner_person_id");
 2587
 2588                    b.ToTable("scope_owner", "heimdall");
 4589                });
 590
 2591            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopePermission", b =>
 2592                {
 2593                    b.Property<long>("Id")
 2594                        .ValueGeneratedOnAdd()
 2595                        .HasColumnType("bigint")
 2596                        .HasColumnName("id")
 2597                        .HasColumnOrder(1);
 2598
 2599                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2600
 2601                    b.Property<DateTime>("CreatedAt")
 2602                        .ValueGeneratedOnAdd()
 2603                        .HasColumnType("timestamp with time zone")
 2604                        .HasColumnName("created_at")
 2605                        .HasDefaultValueSql("now()");
 2606
 2607                    b.Property<string>("Description")
 2608                        .HasMaxLength(500)
 2609                        .HasColumnType("character varying(500)")
 2610                        .HasColumnName("description");
 2611
 2612                    b.Property<bool>("IncludeAsJwtClaim")
 2613                        .ValueGeneratedOnAdd()
 2614                        .HasColumnType("boolean")
 2615                        .HasDefaultValue(false)
 2616                        .HasColumnName("include_as_jwt_claim");
 2617
 2618                    b.Property<bool>("IsDeleted")
 2619                        .ValueGeneratedOnAdd()
 2620                        .HasColumnType("boolean")
 2621                        .HasDefaultValue(false)
 2622                        .HasColumnName("is_deleted");
 2623
 2624                    b.Property<string>("Name")
 2625                        .IsRequired()
 2626                        .HasMaxLength(200)
 2627                        .HasColumnType("character varying(200)")
 2628                        .HasColumnName("name");
 2629
 2630                    b.Property<Guid>("PublicId")
 2631                        .HasColumnType("uuid")
 2632                        .HasColumnName("public_id");
 2633
 2634                    b.Property<long>("ScopeId")
 2635                        .HasColumnType("bigint")
 2636                        .HasColumnName("scope_id");
 2637
 2638                    b.Property<DateTime>("UpdatedAt")
 2639                        .ValueGeneratedOnAdd()
 2640                        .HasColumnType("timestamp with time zone")
 2641                        .HasColumnName("updated_at")
 2642                        .HasDefaultValueSql("now()");
 2643
 2644                    b.HasKey("Id")
 2645                        .HasName("pk_scope_permission");
 2646
 2647                    b.HasIndex("PublicId")
 2648                        .IsUnique()
 2649                        .HasDatabaseName("ix_scope_permission_public_id");
 2650
 2651                    b.HasIndex("ScopeId")
 2652                        .HasDatabaseName("ix_scope_permission_scope_id");
 2653
 2654                    b.ToTable("scope_permission", "heimdall");
 4655                });
 656
 2657            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeUser", b =>
 2658                {
 2659                    b.Property<long>("ScopeId")
 2660                        .HasColumnType("bigint")
 2661                        .HasColumnName("scope_id");
 2662
 2663                    b.Property<long>("PersonId")
 2664                        .HasColumnType("bigint")
 2665                        .HasColumnName("person_id");
 2666
 2667                    b.HasKey("ScopeId", "PersonId")
 2668                        .HasName("pk_scope_user");
 2669
 2670                    b.HasIndex("PersonId")
 2671                        .IsUnique()
 2672                        .HasDatabaseName("ix_scope_user_person_id");
 2673
 2674                    b.ToTable("scope_user", "heimdall");
 4675                });
 676
 2677            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 2678                {
 2679                    b.Property<long>("Id")
 2680                        .ValueGeneratedOnAdd()
 2681                        .HasColumnType("bigint")
 2682                        .HasColumnName("id")
 2683                        .HasColumnOrder(1);
 2684
 2685                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2686
 2687                    b.Property<bool>("AppEnabled")
 2688                        .ValueGeneratedOnAdd()
 2689                        .HasColumnType("boolean")
 2690                        .HasDefaultValue(false)
 2691                        .HasColumnName("app_enabled");
 2692
 2693                    b.Property<DateTime>("CreatedAt")
 2694                        .ValueGeneratedOnAdd()
 2695                        .HasColumnType("timestamp with time zone")
 2696                        .HasColumnName("created_at")
 2697                        .HasDefaultValueSql("now()");
 2698
 2699                    b.Property<bool>("EmailEnabled")
 2700                        .ValueGeneratedOnAdd()
 2701                        .HasColumnType("boolean")
 2702                        .HasDefaultValue(false)
 2703                        .HasColumnName("email_enabled");
 2704
 2705                    b.Property<bool>("IsActive")
 2706                        .ValueGeneratedOnAdd()
 2707                        .HasColumnType("boolean")
 2708                        .HasDefaultValue(false)
 2709                        .HasColumnName("is_active");
 2710
 2711                    b.Property<long?>("LastTotpTimeStepUsed")
 2712                        .HasColumnType("bigint")
 2713                        .HasColumnName("last_totp_time_step_used");
 2714
 2715                    b.Property<long>("PersonId")
 2716                        .HasColumnType("bigint")
 2717                        .HasColumnName("person_id");
 2718
 2719                    b.Property<byte[]>("TotpSecretEncrypted")
 2720                        .HasColumnType("bytea")
 2721                        .HasColumnName("totp_secret_encrypted");
 2722
 2723                    b.Property<DateTime>("UpdatedAt")
 2724                        .ValueGeneratedOnAdd()
 2725                        .HasColumnType("timestamp with time zone")
 2726                        .HasColumnName("updated_at")
 2727                        .HasDefaultValueSql("now()");
 2728
 2729                    b.HasKey("Id")
 2730                        .HasName("pk_two_factor_auth");
 2731
 2732                    b.HasIndex("PersonId")
 2733                        .IsUnique()
 2734                        .HasDatabaseName("ix_two_factor_auth_person_id");
 2735
 2736                    b.ToTable("two_factor_auth", "heimdall");
 4737                });
 738
 2739            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorEmailCode", b =>
 2740                {
 2741                    b.Property<long>("Id")
 2742                        .ValueGeneratedOnAdd()
 2743                        .HasColumnType("bigint")
 2744                        .HasColumnName("id")
 2745                        .HasColumnOrder(1);
 2746
 2747                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2748
 2749                    b.Property<byte[]>("CodeHash")
 2750                        .IsRequired()
 2751                        .HasColumnType("bytea")
 2752                        .HasColumnName("code_hash");
 2753
 2754                    b.Property<DateTime>("CreatedAt")
 2755                        .ValueGeneratedOnAdd()
 2756                        .HasColumnType("timestamp with time zone")
 2757                        .HasColumnName("created_at")
 2758                        .HasDefaultValueSql("now()");
 2759
 2760                    b.Property<DateTime>("ExpiresAt")
 2761                        .HasColumnType("timestamp with time zone")
 2762                        .HasColumnName("expires_at");
 2763
 2764                    b.Property<int>("FailedAttempts")
 2765                        .HasColumnType("integer")
 2766                        .HasColumnName("failed_attempts");
 2767
 2768                    b.Property<byte[]>("Salt")
 2769                        .IsRequired()
 2770                        .HasColumnType("bytea")
 2771                        .HasColumnName("salt");
 2772
 2773                    b.Property<long>("TwoFactorAuthId")
 2774                        .HasColumnType("bigint")
 2775                        .HasColumnName("two_factor_auth_id");
 2776
 2777                    b.Property<bool>("Used")
 2778                        .ValueGeneratedOnAdd()
 2779                        .HasColumnType("boolean")
 2780                        .HasDefaultValue(false)
 2781                        .HasColumnName("used");
 2782
 2783                    b.HasKey("Id")
 2784                        .HasName("pk_two_factor_email_code");
 2785
 2786                    b.HasIndex("TwoFactorAuthId")
 2787                        .HasDatabaseName("ix_two_factor_email_code_two_factor_auth_id");
 2788
 2789                    b.ToTable("two_factor_email_code", "heimdall");
 4790                });
 791
 2792            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorRecoveryCode", b =>
 2793                {
 2794                    b.Property<long>("Id")
 2795                        .ValueGeneratedOnAdd()
 2796                        .HasColumnType("bigint")
 2797                        .HasColumnName("id")
 2798                        .HasColumnOrder(1);
 2799
 2800                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
 2801
 2802                    b.Property<byte[]>("CodeHash")
 2803                        .IsRequired()
 2804                        .HasColumnType("bytea")
 2805                        .HasColumnName("code_hash");
 2806
 2807                    b.Property<DateTime>("CreatedAt")
 2808                        .ValueGeneratedOnAdd()
 2809                        .HasColumnType("timestamp with time zone")
 2810                        .HasColumnName("created_at")
 2811                        .HasDefaultValueSql("now()");
 2812
 2813                    b.Property<long>("TwoFactorAuthId")
 2814                        .HasColumnType("bigint")
 2815                        .HasColumnName("two_factor_auth_id");
 2816
 2817                    b.Property<bool>("Used")
 2818                        .ValueGeneratedOnAdd()
 2819                        .HasColumnType("boolean")
 2820                        .HasDefaultValue(false)
 2821                        .HasColumnName("used");
 2822
 2823                    b.Property<DateTime?>("UsedAt")
 2824                        .HasColumnType("timestamp with time zone")
 2825                        .HasColumnName("used_at");
 2826
 2827                    b.HasKey("Id")
 2828                        .HasName("pk_two_factor_recovery_code");
 2829
 2830                    b.HasIndex("TwoFactorAuthId")
 2831                        .HasDatabaseName("ix_two_factor_recovery_code_two_factor_auth_id");
 2832
 2833                    b.ToTable("two_factor_recovery_code", "heimdall");
 4834                });
 835
 2836            modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
 2837                {
 2838                    b.Property<int>("Id")
 2839                        .ValueGeneratedOnAdd()
 2840                        .HasColumnType("integer")
 2841                        .HasColumnName("id");
 2842
 2843                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
 2844
 2845                    b.Property<string>("FriendlyName")
 2846                        .HasColumnType("text")
 2847                        .HasColumnName("friendly_name");
 2848
 2849                    b.Property<string>("Xml")
 2850                        .HasColumnType("text")
 2851                        .HasColumnName("xml");
 2852
 2853                    b.HasKey("Id")
 2854                        .HasName("pk_data_protection_keys");
 2855
 2856                    b.ToTable("data_protection_keys", "heimdall");
 4857                });
 858
 2859            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Application", b =>
 2860                {
 2861                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Owner")
 2862                        .WithMany("OwnedApplications")
 2863                        .HasForeignKey("OwnerId")
 2864                        .OnDelete(DeleteBehavior.Cascade)
 2865                        .IsRequired()
 2866                        .HasConstraintName("fk_application_person_owner_id");
 2867
 2868                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 2869                        .WithMany("Applications")
 2870                        .HasForeignKey("ScopeId")
 2871                        .OnDelete(DeleteBehavior.Cascade)
 2872                        .IsRequired()
 2873                        .HasConstraintName("fk_application_scope_scope_id");
 2874
 2875                    b.Navigation("Owner");
 2876
 2877                    b.Navigation("Scope");
 4878                });
 879
 2880            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.EmailVerificationToken", b =>
 2881                {
 2882                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 2883                        .WithMany("EmailVerificationTokens")
 2884                        .HasForeignKey("PersonId")
 2885                        .OnDelete(DeleteBehavior.Cascade)
 2886                        .IsRequired()
 2887                        .HasConstraintName("fk_email_verification_token_person_person_id");
 2888
 2889                    b.Navigation("Person");
 4890                });
 891
 2892            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.GoogleUser", b =>
 2893                {
 2894                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 2895                        .WithMany("GoogleUsers")
 2896                        .HasForeignKey("ScopeId")
 2897                        .OnDelete(DeleteBehavior.Cascade)
 2898                        .IsRequired()
 2899                        .HasConstraintName("fk_google_user_scope_scope_id");
 2900
 2901                    b.Navigation("Scope");
 4902                });
 903
 2904            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.PasswordResetToken", b =>
 2905                {
 2906                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 2907                        .WithMany("PasswordResetTokens")
 2908                        .HasForeignKey("PersonId")
 2909                        .OnDelete(DeleteBehavior.Cascade)
 2910                        .IsRequired()
 2911                        .HasConstraintName("fk_password_reset_token_person_person_id");
 2912
 2913                    b.Navigation("Person");
 4914                });
 915
 2916            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 2917                {
 2918                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Role", "Role")
 2919                        .WithMany("Persons")
 2920                        .HasForeignKey("RoleId")
 2921                        .OnDelete(DeleteBehavior.Restrict)
 2922                        .IsRequired()
 2923                        .HasConstraintName("fk_person_roles_role_id");
 2924
 2925                    b.Navigation("Role");
 4926                });
 927
 2928            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeOwner", b =>
 2929                {
 2930                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 2931                        .WithMany("ScopeOwnerships")
 2932                        .HasForeignKey("PersonId")
 2933                        .OnDelete(DeleteBehavior.Cascade)
 2934                        .IsRequired()
 2935                        .HasConstraintName("fk_scope_owner_person_person_id");
 2936
 2937                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 2938                        .WithMany("Owners")
 2939                        .HasForeignKey("ScopeId")
 2940                        .OnDelete(DeleteBehavior.Cascade)
 2941                        .IsRequired()
 2942                        .HasConstraintName("fk_scope_owner_scope_scope_id");
 2943
 2944                    b.Navigation("Person");
 2945
 2946                    b.Navigation("Scope");
 4947                });
 948
 2949            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopePermission", b =>
 2950                {
 2951                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 2952                        .WithMany("ScopePermissions")
 2953                        .HasForeignKey("ScopeId")
 2954                        .OnDelete(DeleteBehavior.Cascade)
 2955                        .IsRequired()
 2956                        .HasConstraintName("fk_scope_permission_scope_scope_id");
 2957
 2958                    b.Navigation("Scope");
 4959                });
 960
 2961            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.ScopeUser", b =>
 2962                {
 2963                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 2964                        .WithOne("ScopeMembership")
 2965                        .HasForeignKey("ArturRios.Heimdall.Domain.Entities.ScopeUser", "PersonId")
 2966                        .OnDelete(DeleteBehavior.Cascade)
 2967                        .IsRequired()
 2968                        .HasConstraintName("fk_scope_user_person_person_id");
 2969
 2970                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Scope", "Scope")
 2971                        .WithMany("Users")
 2972                        .HasForeignKey("ScopeId")
 2973                        .OnDelete(DeleteBehavior.Cascade)
 2974                        .IsRequired()
 2975                        .HasConstraintName("fk_scope_user_scope_scope_id");
 2976
 2977                    b.Navigation("Person");
 2978
 2979                    b.Navigation("Scope");
 4980                });
 981
 2982            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 2983                {
 2984                    b.HasOne("ArturRios.Heimdall.Domain.Entities.Person", "Person")
 2985                        .WithOne("TwoFactorAuth")
 2986                        .HasForeignKey("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "PersonId")
 2987                        .OnDelete(DeleteBehavior.Cascade)
 2988                        .IsRequired()
 2989                        .HasConstraintName("fk_two_factor_auth_person_person_id");
 2990
 2991                    b.Navigation("Person");
 4992                });
 993
 2994            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorEmailCode", b =>
 2995                {
 2996                    b.HasOne("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "TwoFactorAuth")
 2997                        .WithMany("EmailCodes")
 2998                        .HasForeignKey("TwoFactorAuthId")
 2999                        .OnDelete(DeleteBehavior.Cascade)
 21000                        .IsRequired()
 21001                        .HasConstraintName("fk_two_factor_email_code_two_factor_auth_two_factor_auth_id");
 21002
 21003                    b.Navigation("TwoFactorAuth");
 41004                });
 1005
 21006            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorRecoveryCode", b =>
 21007                {
 21008                    b.HasOne("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", "TwoFactorAuth")
 21009                        .WithMany("RecoveryCodes")
 21010                        .HasForeignKey("TwoFactorAuthId")
 21011                        .OnDelete(DeleteBehavior.Cascade)
 21012                        .IsRequired()
 21013                        .HasConstraintName("fk_two_factor_recovery_code_two_factor_auth_two_factor_auth_id");
 21014
 21015                    b.Navigation("TwoFactorAuth");
 41016                });
 1017
 21018            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Person", b =>
 21019                {
 21020                    b.Navigation("EmailVerificationTokens");
 21021
 21022                    b.Navigation("OwnedApplications");
 21023
 21024                    b.Navigation("PasswordResetTokens");
 21025
 21026                    b.Navigation("ScopeMembership");
 21027
 21028                    b.Navigation("ScopeOwnerships");
 21029
 21030                    b.Navigation("TwoFactorAuth");
 41031                });
 1032
 21033            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Role", b =>
 21034                {
 21035                    b.Navigation("Persons");
 41036                });
 1037
 21038            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.Scope", b =>
 21039                {
 21040                    b.Navigation("Applications");
 21041
 21042                    b.Navigation("GoogleUsers");
 21043
 21044                    b.Navigation("Owners");
 21045
 21046                    b.Navigation("ScopePermissions");
 21047
 21048                    b.Navigation("Users");
 41049                });
 1050
 21051            modelBuilder.Entity("ArturRios.Heimdall.Domain.Entities.TwoFactorAuth", b =>
 21052                {
 21053                    b.Navigation("EmailCodes");
 21054
 21055                    b.Navigation("RecoveryCodes");
 41056                });
 1057#pragma warning restore 612, 618
 21058        }
 1059    }
 1060}