using Microsoft.EntityFrameworkCore;
using SmartStack.Application.Common.Interfaces.Identity;
using SmartStack.Application.Common.Interfaces.Tenants;
using SmartStack.Infrastructure.Persistence;
using SmartStack.Infrastructure.Persistence.Extensions;
using {{ProjectName}}.Application.Common.Interfaces;
namespace {{ProjectName}}.Infrastructure.Persistence;
///
/// DbContext for client-specific entities (schema: extensions).
///
/// Inherits , which exposes the V1
/// whitelist of Core entities — User, Role, Tenant, TenantOrganisation
/// (DbSet Organisations, the shared organisation directory), Department,
/// JobTitle, Office, Language, Group — as read-only DbSets via
/// ExcludeFromMigrations. This lets your entities declare REAL
/// navigation properties and SQL foreign keys to those Core entities.
///
/// Example — Order N:1 User + N:1 TenantOrganisation:
///
/// public class Order
/// {
/// public Guid CustomerUserId { get; private set; }
/// public Guid OrganisationId { get; private set; }
/// public User Customer { get; private set; } = null!;
/// public TenantOrganisation Organisation { get; private set; } = null!;
/// }
/// // and in OrderConfiguration:
/// builder.HasOne(o => o.Customer ).WithMany().HasForeignKey(o => o.CustomerUserId);
/// builder.HasOne(o => o.Organisation).WithMany().HasForeignKey(o => o.OrganisationId);
///
///
/// For Core entities OUTSIDE the V1 whitelist (sessions, tokens, navigation,
/// AI / workflow / support internals, audit logs, …) inject
/// and use its projection helpers
/// (GetUserBasicInfoAsync, GetRoleByIdAsync, …). See
/// docs/extensions/cross-context-references.md.
///
public class ExtensionsDbContext : SmartStackExtensionDbContext, IExtensionsDbContext
{
///
/// Forward EVERY optional base dependency — each one silently disables a
/// platform seam when omitted:
///
/// - tenantService — activates the named "Tenant" row filter
/// (multi-tenant isolation, TENANT-FILTERS markers below). Without it the
/// context is "system": every tenant-scoped query returns EVERY tenant's
/// rows.
/// - currentUserAccessor — activates the named "DataScope" row
/// filter (own/assigned lists). Without it the context is "system": never
/// scoped, every list returns every row.
/// - serviceProvider — activates gapless business-code
/// allocation for ICodedEntity entities. Without it allocation is
/// silently skipped.
///
/// At design time (migrations) they are null — the context stays unscoped,
/// which is exactly what EF tooling needs.
///
public ExtensionsDbContext(
DbContextOptions options,
ICurrentTenantService? tenantService = null,
ICurrentUserAccessor? currentUserAccessor = null,
IServiceProvider? serviceProvider = null)
: base(options, tenantService, currentUserAccessor, serviceProvider)
{
}
// === YOUR ENTITIES ===
// Add your DbSet properties here. Example:
// public DbSet Orders => Set();
protected override void OnExtensionModelCreating(ModelBuilder modelBuilder)
{
// All client entities default to the 'extensions' schema (Core whitelist
// entities keep their explicit ToTable("...", "core") from the base class).
modelBuilder.HasDefaultSchema(SchemaConstants.Extensions);
// Load entity configurations from this assembly
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ExtensionsDbContext).Assembly);
// ── Tenant isolation (named "Tenant" filter) ───────────────────────────
// One ApplyNamed{Strict|Optional}TenantFilter per tenant-scoped entity:
// every read (lists, lookups, detail, screen queries) is filtered to the
// current tenant — the extension mirror of CoreDbContext's per-entity
// tenant filters. Client entity configurations only carry the anonymous
// soft-delete filter; WITHOUT its line here an entity's reads are
// CROSS-TENANT. The scaffold-entity CLI maintains the markers (entities
// referenced fully-qualified); audited by DEV-API-032.
// <<< TENANT-FILTERS BEGIN >>>
// ApplyNamedStrictTenantFilter(modelBuilder);
// <<< TENANT-FILTERS END >>>
// ── Row-level data scopes (own/assigned lists) ─────────────────────────
// One ApplyDataScopeFilter per scoped entity mounts the named "DataScope"
// EF query filter: lists/details are filtered to the current user unless
// the caller holds the "{path}.read.all" bypass. The scaffold-data-scope
// CLI fills the markers (policies live in {{ProjectName}}.Application/…/Authorization).
// <<< DATA-SCOPE-FILTERS BEGIN >>>
// ApplyDataScopeFilter(modelBuilder, MyApp.Application.Crm.Pipeline.Authorization.OrderScopePolicy.Instance);
// <<< DATA-SCOPE-FILTERS END >>>
}
}