diff --git a/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApproval.cs b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApproval.cs
index 0525ba82..5b2624ab 100644
--- a/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApproval.cs
+++ b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApproval.cs
@@ -26,6 +26,10 @@ private RuntimeApproval(RuntimeApprovalProps props) : base(props) { }
public string? CorrelationId => Props.CorrelationId;
public string? RequestedBy => Props.RequestedBy;
public string? ExecutionMode => Props.ExecutionMode;
+
+ /// GT-590 — el objeto bajo decisión, cuando el runtime lo declaró. Nulo si no.
+ public RuntimeApprovalSubject? Subject => Props.Subject;
+
public string Status => Props.Status;
public string? Approver => Props.Approver;
public string? Reason => Props.Reason;
@@ -43,7 +47,8 @@ public static Result Submit(
string? initiativeId = null,
string? correlationId = null,
string? requestedBy = null,
- string? executionMode = null)
+ string? executionMode = null,
+ RuntimeApprovalSubject? subject = null)
{
if (tenantId == Guid.Empty) return Result.Failure("RuntimeApproval.TenantRequired");
if (string.IsNullOrWhiteSpace(skillId)) return Result.Failure("RuntimeApproval.SkillRequired");
@@ -63,6 +68,7 @@ public static Result Submit(
CorrelationId = string.IsNullOrWhiteSpace(correlationId) ? null : correlationId,
RequestedBy = requestedBy,
ExecutionMode = executionMode,
+ Subject = subject,
Status = RuntimeApprovalStatus.Pending,
RequestedAtUtc = now,
ExpiresAtUtc = now.Add(ttl),
diff --git a/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalProps.cs b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalProps.cs
index 19a4357d..ea6c0429 100644
--- a/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalProps.cs
+++ b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalProps.cs
@@ -24,6 +24,13 @@ public sealed record RuntimeApprovalProps : IProps
public string? ExecutionMode { get; init; }
+ ///
+ /// GT-590 — QUÉ se decide, cuando `skillId` + `intent` no lo dicen. Nulo en toda aprobación
+ /// abierta por un runtime anterior a GT-590, y nulo sigue siendo válido: el sujeto es opcional
+ /// en el contrato del Core y hacerlo obligatorio aquí rompería a los runtimes desplegados.
+ ///
+ public RuntimeApprovalSubject? Subject { get; init; }
+
public string Status { get; init; } = RuntimeApprovalStatus.Pending;
/// Humano que resolvio. Un `approved` sin aprobador deja el ledger sin responsable.
diff --git a/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalSubject.cs b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalSubject.cs
new file mode 100644
index 00000000..f3461479
--- /dev/null
+++ b/src/apps/tracker-api/Tracker.Domain/Governance/RuntimeApproval/RuntimeApprovalSubject.cs
@@ -0,0 +1,148 @@
+using System.Text.Json;
+
+namespace Tracker.Domain.Governance.RuntimeApproval;
+
+///
+/// GT-590 — QUÉ se está decidiendo, cuando el id de la capacidad no lo dice.
+///
+/// Hasta aqui una llevaba solo `skillId` + `intent`, asi que TODA
+/// decision tomada a traves de una misma capacidad se veia igual: igual para el humano que la
+/// concede e igual en el ledger que la registra. Eso basta para «¿puede ejecutarse esta
+/// capacidad?» y NO basta para «¿es ESTA la correspondencia correcta?» —una decision de gobierno
+/// sobre un objeto concreto, que es lo que el Core empezo a enrutar por esta compuerta.
+///
+/// El contrato lo fija el Core en `approval.port.ts` (`ApprovalSubject`) y aqui se ESPEJA, no se
+/// reinterpreta:
+/// · Kind — familia del sujeto, con espacio de nombres de la capacidad que la introduce.
+/// · Ref — referencia estable al objeto concreto, unica dentro de su Kind.
+/// · Summary — una linea sobre la que un humano puede decidir sin abrir nada mas.
+/// · Confidence — confianza de la propuesta que se ratifica, si vino de un proponente
+/// probabilistico. Existe para DECIRLE al humano que esta ratificando una CONJETURA.
+/// · PayloadJson — opaco. Se guarda y se devuelve verbatim; el Tracker NUNCA lo
+/// interpreta, igual que el Core no lo interpreta.
+///
+/// Todo el sujeto es OPCIONAL: las versiones del runtime que ya estan desplegadas no lo envian y
+/// deben seguir funcionando exactamente igual. Pero un sujeto PRESENTE y a medias se rechaza en
+/// vez de recortarse: si llega un kind sin summary, el humano decidiria a ciegas
+/// creyendo que ve el objeto, que es peor que no ver nada. Ausente es ausente; roto es un 400.
+///
+public sealed record RuntimeApprovalSubject
+{
+ public const int MaxKindLength = 100;
+ public const int MaxRefLength = 500;
+ public const int MaxSummaryLength = 1000;
+
+ ///
+ /// El payload viaja a una columna jsonb de una fila de auditoria, no a un almacen de objetos.
+ /// El tope existe para que un adjunto desmedido no convierta el ledger en un blobstore.
+ ///
+ public const int MaxPayloadLength = 16 * 1024;
+
+ private RuntimeApprovalSubject(
+ string kind, string reference, string summary, double? confidence, string? payloadJson)
+ {
+ Kind = kind;
+ Ref = reference;
+ Summary = summary;
+ Confidence = confidence;
+ PayloadJson = payloadJson;
+ }
+
+ /// Familia del sujeto, p. ej. c4-binding. Indexable.
+ public string Kind { get; }
+
+ /// Referencia estable al objeto bajo decision, unica dentro de .
+ public string Ref { get; }
+
+ /// La linea que el humano lee para decidir.
+ public string Summary { get; }
+
+ /// Confianza en [0,1] cuando la propuesta es probabilistica; nula si no lo es.
+ public double? Confidence { get; }
+
+ /// JSON opaco tal cual llego. Nunca se interpreta aqui.
+ public string? PayloadJson { get; }
+
+ ///
+ /// Valida y construye. se exige OBJETO JSON porque el contrato
+ /// del Core lo declara Record<string, unknown>; admitir un escalar o un array
+ /// dejaria pasar formas que ninguna superficie de lectura sabe mostrar.
+ ///
+ public static Result Create(
+ string? kind,
+ string? reference,
+ string? summary,
+ double? confidence = null,
+ string? payloadJson = null)
+ {
+ if (string.IsNullOrWhiteSpace(kind))
+ return Result.Failure("RuntimeApproval.Subject.KindRequired");
+ if (kind.Length > MaxKindLength)
+ return Result.Failure("RuntimeApproval.Subject.KindTooLong");
+
+ if (string.IsNullOrWhiteSpace(reference))
+ return Result.Failure("RuntimeApproval.Subject.RefRequired");
+ if (reference.Length > MaxRefLength)
+ return Result.Failure("RuntimeApproval.Subject.RefTooLong");
+
+ // Sin resumen el sujeto es un identificador opaco y el humano vuelve a decidir a ciegas,
+ // que es exactamente lo que este campo existe para evitar.
+ if (string.IsNullOrWhiteSpace(summary))
+ return Result.Failure("RuntimeApproval.Subject.SummaryRequired");
+ if (summary.Length > MaxSummaryLength)
+ return Result.Failure("RuntimeApproval.Subject.SummaryTooLong");
+
+ // Fuera de [0,1] no es «poco fiable»: es que quien la emitio no esta hablando de una
+ // probabilidad, y mostrarla como tal enganaria a quien decide.
+ if (confidence is not null &&
+ (double.IsNaN(confidence.Value) || confidence.Value < 0 || confidence.Value > 1))
+ {
+ return Result.Failure("RuntimeApproval.Subject.ConfidenceOutOfRange");
+ }
+
+ string? payload = null;
+ if (!string.IsNullOrWhiteSpace(payloadJson))
+ {
+ if (payloadJson.Length > MaxPayloadLength)
+ return Result.Failure("RuntimeApproval.Subject.PayloadTooLarge");
+
+ // Se valida AQUI y no en la base: un jsonb invalido reventaria en `SaveChanges` como
+ // un 500 opaco, cuando lo cierto es que el cuerpo de la peticion venia mal.
+ try
+ {
+ using var parsed = JsonDocument.Parse(payloadJson);
+ if (parsed.RootElement.ValueKind != JsonValueKind.Object)
+ return Result.Failure("RuntimeApproval.Subject.PayloadNotAnObject");
+ }
+ catch (JsonException)
+ {
+ return Result.Failure("RuntimeApproval.Subject.PayloadNotJson");
+ }
+
+ payload = payloadJson;
+ }
+
+ return Result.Success(
+ new RuntimeApprovalSubject(kind.Trim(), reference.Trim(), summary.Trim(), confidence, payload));
+ }
+
+ ///
+ /// Rehidrata desde persistencia sin revalidar: la fila ya paso por .
+ /// Devuelve null cuando la fila no lleva sujeto —el caso de toda aprobacion abierta por
+ /// un runtime anterior a GT-590, que debe releerse igual que siempre.
+ ///
+ public static RuntimeApprovalSubject? Rehydrate(
+ string? kind, string? reference, string? summary, double? confidence, string? payloadJson)
+ {
+ // La ausencia se decide por `kind`: es el unico campo que ninguna fila con sujeto puede
+ // tener vacio. Una fila a medias se lee como SIN sujeto en vez de fabricar uno inventado.
+ if (string.IsNullOrWhiteSpace(kind) ||
+ string.IsNullOrWhiteSpace(reference) ||
+ string.IsNullOrWhiteSpace(summary))
+ {
+ return null;
+ }
+
+ return new RuntimeApprovalSubject(kind, reference, summary, confidence, payloadJson);
+ }
+}
diff --git a/src/apps/tracker-api/Tracker.Infrastructure/Migrations/20260731191456_AddRuntimeApprovalSubject.Designer.cs b/src/apps/tracker-api/Tracker.Infrastructure/Migrations/20260731191456_AddRuntimeApprovalSubject.Designer.cs
new file mode 100644
index 00000000..34aea805
--- /dev/null
+++ b/src/apps/tracker-api/Tracker.Infrastructure/Migrations/20260731191456_AddRuntimeApprovalSubject.Designer.cs
@@ -0,0 +1,3759 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Tracker.Infrastructure.Persistence;
+
+#nullable disable
+
+namespace Tracker.Infrastructure.Migrations
+{
+ [DbContext(typeof(TrackerDbContext))]
+ [Migration("20260731191456_AddRuntimeApprovalSubject")]
+ partial class AddRuntimeApprovalSubject
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("tracker_governance")
+ .HasAnnotation("ProductVersion", "10.0.10")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "ltree");
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Artifacts.Entities.EvidenceRecordRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("AdapterVersion")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("adapter_version");
+
+ b.Property("ArtifactId")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("artifact_id");
+
+ b.Property("ArtifactType")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("artifact_type");
+
+ b.Property("Classification")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("classification");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("content");
+
+ b.Property("ContentHash")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("content_hash");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("Determinism")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("unspecified")
+ .HasColumnName("determinism");
+
+ b.Property("Dimension")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("unspecified")
+ .HasColumnName("dimension");
+
+ b.Property("EvidenceType")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("evidence_type");
+
+ b.Property("Immutable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(false)
+ .HasColumnName("immutable");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("MetadataJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("metadata");
+
+ b.Property("Producer")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("producer");
+
+ b.Property("ReferencesJson")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("jsonb")
+ .HasDefaultValue("[]")
+ .HasColumnName("references");
+
+ b.Property("RetentionPolicyRef")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("retention_policy_ref");
+
+ b.Property("SourceProvider")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text")
+ .HasDefaultValue("")
+ .HasColumnName("source_provider");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("status");
+
+ b.Property("SubmittedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("submitted_at");
+
+ b.Property("SubmittedBy")
+ .HasColumnType("uuid")
+ .HasColumnName("submitted_by");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Classification");
+
+ b.HasIndex("Dimension");
+
+ b.HasIndex("TenantId");
+
+ b.HasIndex("ArtifactType", "ArtifactId");
+
+ b.ToTable("evidence_records", "tracker_governance");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Audit.Entities.AuditEntryRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Action")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("action");
+
+ b.Property("ActorId")
+ .HasColumnType("uuid")
+ .HasColumnName("actor_id");
+
+ b.Property("ChangesJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("changes");
+
+ b.Property("CorrelationId")
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("correlation_id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("EntityId")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("entity_id");
+
+ b.Property("EntityType")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("entity_type");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("TimestampUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("timestamp");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ActorId");
+
+ b.HasIndex("TenantId");
+
+ b.HasIndex("EntityType", "EntityId");
+
+ b.ToTable("audit_entries", "tracker_governance");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Design.Entities.TechnicalBlueprintRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("FacetsJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("facets");
+
+ b.Property("InitiativeId")
+ .HasColumnType("uuid")
+ .HasColumnName("initiative_id");
+
+ b.Property("InitiativeType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("initiative_type");
+
+ b.Property("IntegrationAdrRef")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)")
+ .HasColumnName("integration_adr_ref");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("Notes")
+ .HasColumnType("text")
+ .HasColumnName("notes");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(16)
+ .HasColumnType("character varying(16)")
+ .HasColumnName("status");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("InitiativeId")
+ .IsUnique();
+
+ b.HasIndex("TenantId");
+
+ b.ToTable("technical_blueprints", "tracker_governance");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Discovery.Entities.InitiativeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("ApprovalComplete")
+ .HasColumnType("boolean")
+ .HasColumnName("approval_complete");
+
+ b.Property("ApprovedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("approved_at");
+
+ b.Property("ApprovedBy")
+ .HasColumnType("uuid")
+ .HasColumnName("approved_by");
+
+ b.Property("BusinessCaseJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("business_case");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("code");
+
+ b.Property("ConstituentsJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("constituents");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("description");
+
+ b.Property("FacetsJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("facets");
+
+ b.Property("FunctionalBriefJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("functional_brief");
+
+ b.Property("InitiativeType")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("initiative_type");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("MetadataJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("metadata");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("name");
+
+ b.Property("Origin")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("origin");
+
+ b.Property("OriginRef")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("origin_ref");
+
+ b.Property("ProductScopeJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("product_scope");
+
+ b.Property("RejectionReason")
+ .HasColumnType("text")
+ .HasColumnName("rejection_reason");
+
+ b.Property("RequiredApproversJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("required_approvers");
+
+ b.Property("StakeholdersJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("stakeholders");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("status");
+
+ b.Property("SupersededByInitiativeId")
+ .HasColumnType("uuid")
+ .HasColumnName("superseded_by_initiative_id");
+
+ b.Property("TechnicalBriefJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("technical_brief");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("TypeFrozen")
+ .HasColumnType("boolean")
+ .HasColumnName("type_frozen");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("TenantId");
+
+ b.HasIndex("TenantId", "Code");
+
+ b.ToTable("initiatives", "tracker_governance", t =>
+ {
+ t.HasCheckConstraint("ck_initiatives_status", "status IN ('draft', 'submitted', 'approved', 'rejected', 'consolidated')");
+ });
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Discovery.Entities.OpportunityRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("code");
+
+ b.Property("ConsolidatedInitiativeId")
+ .HasColumnType("uuid")
+ .HasColumnName("consolidated_initiative_id");
+
+ b.Property("ContextJson")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("jsonb")
+ .HasDefaultValue("{}")
+ .HasColumnName("context");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("CustomFieldsJson")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("jsonb")
+ .HasDefaultValue("{}")
+ .HasColumnName("custom_fields");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("description");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("MetadataJson")
+ .IsRequired()
+ .HasColumnType("jsonb")
+ .HasColumnName("metadata");
+
+ b.Property("Priority")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("priority");
+
+ b.Property("PromotedInitiativeId")
+ .HasColumnType("uuid")
+ .HasColumnName("promoted_initiative_id");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)")
+ .HasColumnName("source");
+
+ b.Property("Status")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)")
+ .HasColumnName("status");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)")
+ .HasColumnName("title");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("TenantId");
+
+ b.HasIndex("TenantId", "Code")
+ .IsUnique();
+
+ b.ToTable("opportunities", "tracker_governance");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.CatalogReleaseRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("code");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("PublishedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("published_at");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("source");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Code")
+ .IsUnique();
+
+ b.ToTable("catalog_release", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.CountryRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DefaultCurrencyCode")
+ .HasMaxLength(3)
+ .HasColumnType("character varying(3)")
+ .HasColumnName("default_currency_code");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean")
+ .HasColumnName("is_active");
+
+ b.Property("IsoAlpha2")
+ .IsRequired()
+ .HasMaxLength(2)
+ .HasColumnType("character(2)")
+ .HasColumnName("iso_alpha2")
+ .IsFixedLength();
+
+ b.Property("IsoAlpha3")
+ .IsRequired()
+ .HasMaxLength(3)
+ .HasColumnType("character(3)")
+ .HasColumnName("iso_alpha3")
+ .IsFixedLength();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(96)
+ .HasColumnType("character varying(96)")
+ .HasColumnName("name");
+
+ b.Property("NumericCode")
+ .HasMaxLength(3)
+ .HasColumnType("character(3)")
+ .HasColumnName("numeric_code")
+ .IsFixedLength();
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IsoAlpha2")
+ .IsUnique();
+
+ b.HasIndex("IsoAlpha3")
+ .IsUnique();
+
+ b.ToTable("country", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.CurrencyRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(3)
+ .HasColumnType("character varying(3)")
+ .HasColumnName("code");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean")
+ .HasColumnName("is_active");
+
+ b.Property("MinorUnits")
+ .HasColumnType("smallint")
+ .HasColumnName("minor_units");
+
+ b.Property("Symbol")
+ .IsRequired()
+ .HasMaxLength(8)
+ .HasColumnType("character varying(8)")
+ .HasColumnName("symbol");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Code")
+ .IsUnique();
+
+ b.ToTable("currency", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.ExchangeRateRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("BaseCode")
+ .IsRequired()
+ .HasMaxLength(3)
+ .HasColumnType("character varying(3)")
+ .HasColumnName("base_code");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("QuoteCode")
+ .IsRequired()
+ .HasMaxLength(3)
+ .HasColumnType("character varying(3)")
+ .HasColumnName("quote_code");
+
+ b.Property("Rate")
+ .HasColumnType("numeric(20,10)")
+ .HasColumnName("rate");
+
+ b.Property("Source")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("source");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.Property("ValidFrom")
+ .HasColumnType("date")
+ .HasColumnName("valid_from");
+
+ b.Property("ValidTo")
+ .HasColumnType("date")
+ .HasColumnName("valid_to");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BaseCode", "QuoteCode", "ValidFrom")
+ .HasDatabaseName("ix_exchange_rate_pair");
+
+ b.ToTable("exchange_rate", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LanguageRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(8)
+ .HasColumnType("character varying(8)")
+ .HasColumnName("code");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("name");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Code")
+ .IsUnique();
+
+ b.ToTable("language", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LocaleProfileRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(16)
+ .HasColumnType("character varying(16)")
+ .HasColumnName("code");
+
+ b.Property("CountryId")
+ .HasColumnType("uuid")
+ .HasColumnName("country_id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("DateFormat")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("date_format");
+
+ b.Property("FirstDayOfWeek")
+ .HasColumnType("smallint")
+ .HasColumnName("first_day_of_week");
+
+ b.Property("Name")
+ .HasMaxLength(96)
+ .HasColumnType("character varying(96)")
+ .HasColumnName("name");
+
+ b.Property("NumberFormat")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("number_format");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Code")
+ .IsUnique();
+
+ b.HasIndex("CountryId");
+
+ b.ToTable("locale_profile", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LocationCodeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("LocationId")
+ .HasColumnType("uuid")
+ .HasColumnName("location_id");
+
+ b.Property("Scheme")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("scheme");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("value");
+
+ b.HasKey("Id");
+
+ b.HasIndex("LocationId", "Scheme")
+ .IsUnique();
+
+ b.HasIndex("Scheme", "Value")
+ .IsUnique();
+
+ b.ToTable("location_code", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LocationI18nRecord", b =>
+ {
+ b.Property("LocationId")
+ .HasColumnType("uuid")
+ .HasColumnName("location_id");
+
+ b.Property("Locale")
+ .HasMaxLength(16)
+ .HasColumnType("character varying(16)")
+ .HasColumnName("locale");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)")
+ .HasColumnName("name");
+
+ b.HasKey("LocationId", "Locale");
+
+ b.ToTable("location_i18n", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LocationLevelRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("code");
+
+ b.Property("CountryId")
+ .HasColumnType("uuid")
+ .HasColumnName("country_id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("name");
+
+ b.Property("Ordinal")
+ .HasColumnType("smallint")
+ .HasColumnName("ordinal");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CountryId", "Ordinal")
+ .IsUnique();
+
+ b.ToTable("location_level", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.LocationRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CatalogReleaseId")
+ .HasColumnType("uuid")
+ .HasColumnName("catalog_release_id");
+
+ b.Property("CountryId")
+ .HasColumnType("uuid")
+ .HasColumnName("country_id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("IsActive")
+ .HasColumnType("boolean")
+ .HasColumnName("is_active");
+
+ b.Property("LevelId")
+ .HasColumnType("uuid")
+ .HasColumnName("level_id");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(160)
+ .HasColumnType("character varying(160)")
+ .HasColumnName("name");
+
+ b.Property("ParentId")
+ .HasColumnType("uuid")
+ .HasColumnName("parent_id");
+
+ b.Property("Path")
+ .IsRequired()
+ .HasColumnType("ltree")
+ .HasColumnName("path");
+
+ b.Property("SupersedesId")
+ .HasColumnType("uuid")
+ .HasColumnName("supersedes_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.Property("ValidFrom")
+ .HasColumnType("date")
+ .HasColumnName("valid_from");
+
+ b.Property("ValidTo")
+ .HasColumnType("date")
+ .HasColumnName("valid_to");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ParentId")
+ .HasDatabaseName("ix_location_parent");
+
+ b.HasIndex("Path")
+ .HasDatabaseName("ix_location_path");
+
+ NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Path"), "gist");
+
+ b.HasIndex("CountryId", "ParentId")
+ .HasDatabaseName("ix_location_country_parent");
+
+ b.ToTable("location", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.TaxRateRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("LocationId")
+ .HasColumnType("uuid")
+ .HasColumnName("location_id");
+
+ b.Property("OperationType")
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("operation_type");
+
+ b.Property("Rate")
+ .HasColumnType("numeric(6,4)")
+ .HasColumnName("rate");
+
+ b.Property("TaxSchemeId")
+ .HasColumnType("uuid")
+ .HasColumnName("tax_scheme_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.Property("ValidFrom")
+ .HasColumnType("date")
+ .HasColumnName("valid_from");
+
+ b.Property("ValidTo")
+ .HasColumnType("date")
+ .HasColumnName("valid_to");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TaxSchemeId", "LocationId", "ValidFrom")
+ .HasDatabaseName("ix_tax_rate_scheme_location");
+
+ b.ToTable("tax_rate", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.TaxSchemeRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Code")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("character varying(32)")
+ .HasColumnName("code");
+
+ b.Property("CountryId")
+ .HasColumnType("uuid")
+ .HasColumnName("country_id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(96)
+ .HasColumnType("character varying(96)")
+ .HasColumnName("name");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CountryId", "Code")
+ .IsUnique();
+
+ b.ToTable("tax_scheme", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Geo.Entities.TimeZoneRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CountryCode")
+ .HasMaxLength(2)
+ .HasColumnType("character varying(2)")
+ .HasColumnName("country_code");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("IanaId")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("iana_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CountryCode");
+
+ b.HasIndex("IanaId")
+ .IsUnique();
+
+ b.ToTable("time_zone", "tracker_geo");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Governance.Entities.ArtifactFieldSchemaRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("ArtifactType")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("character varying(64)")
+ .HasColumnName("artifact_type");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("created_by");
+
+ b.Property("CustomFieldsJson")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasColumnType("jsonb")
+ .HasDefaultValue("[]")
+ .HasColumnName("custom_fields");
+
+ b.Property("DeletedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("deleted_at");
+
+ b.Property("DeletedBy")
+ .HasColumnType("text")
+ .HasColumnName("deleted_by");
+
+ b.Property("IsDeleted")
+ .HasColumnType("boolean")
+ .HasColumnName("is_deleted");
+
+ b.Property("TenantId")
+ .HasColumnType("uuid")
+ .HasColumnName("tenant_id");
+
+ b.Property("UpdatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at");
+
+ b.Property("UpdatedBy")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasColumnName("updated_by");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ArtifactType")
+ .IsUnique();
+
+ b.ToTable("artifact_field_schemas", "tracker_governance");
+ });
+
+ modelBuilder.Entity("Tracker.Infrastructure.Persistence.Governance.Entities.ExceptionRequestRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at_utc");
+
+ b.Property("CreatedBy")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("created_by");
+
+ b.Property("CriterionId")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("criterion_id");
+
+ b.Property