Skip to main content

Audience Management — Technical Documentation

Last updated: February 2026


Table of Contents

  1. Overview
  2. Architecture
  3. Repository Map
  4. Core Flows
  5. Entities & Data Model
  6. API Endpoints
  7. Services & Business Logic
  8. ClickHouse Integration
  9. Configuration
  10. Integration Points

1. Overview

Audience Management handles the full lifecycle of prospect target groups — creation, prospect imports, deduplication (engaged/in-other-audiences/remaining), statistics recalculation, ClickHouse sync, status transitions, and webhook triggers. It spans two repositories: sopromasterdata (backend API + Hangfire jobs) and data-admin (React frontend).


2. Architecture


3. Repository Map

RepositoryLayerKey Files
sopromasterdataAPI ControllerAPI/SoProMasterDBAPI/Controllers/AudienceController.cs
sopromasterdataAdmin ControllerAPI/SoProMasterDBAPI/Controllers/AudienceAdminController.cs
sopromasterdataServiceAudienceServices/AudienceService.cs
sopromasterdataHangfire ServiceHangfireServices/AudienceHangfireService.cs
sopromasterdataRepositoryRepository/Audience/AudienceRepository.cs
sopromasterdataContact RepositoryRepository/Audience/AudienceContactRepository.cs
sopromasterdataEntitiesAudienceEntities/Audience.cs, AudienceContact.cs
sopromasterdataClickHouseClickhouse/AudienceClickhouseService.cs
data-adminPagessrc/pages/audiences/
data-adminAPI Hookssrc/api/audience.queries.ts
data-adminTypessrc/types/audiences/

4. Core Flows

4.1 Audience Creation Flow

4.2 Import & Deduplication Flow

4.3 Statistics Recalculation


5. Entities & Data Model

5.1 SQL Server Entities

Audience

ColumnTypeDescription
Idint (PK)Auto-increment primary key
Namenvarchar(255)Audience display name
ClientIdint (FK)Linked client
Statusint (enum)Draft, Active, Paused, Completed
CreatedAtdatetimeCreation timestamp
UpdatedAtdatetimeLast modification timestamp
CreatedBynvarchar(100)User who created the audience

AudienceContact

ColumnTypeDescription
Idlong (PK)Auto-increment primary key
AudienceIdint (FK)Parent audience
ProspectIdlong (FK)Link to prospect record
Statusint (enum)Engaged, InOtherAudience, Remaining
ImportBatchIdintWhich import batch added this contact
CreatedAtdatetimeWhen the contact was added

AudienceFilter

ColumnTypeDescription
Idint (PK)Auto-increment primary key
AudienceIdint (FK)Parent audience
FilterTypeint (enum)Type of filter (Industry, Title, Location, etc.)
FilterValuenvarchar(500)Filter value

AudienceStatistics

ColumnTypeDescription
Idint (PK)Auto-increment primary key
AudienceIdint (FK)Parent audience
TotalProspectsintTotal prospect count
EngagedCountintCount of engaged prospects
InOtherAudiencesCountintCount in other audiences
RemainingCountintCount of remaining prospects
TargetCoveragedecimalCoverage percentage
CalculatedAtdatetimeLast calculation timestamp

AudienceImport

ColumnTypeDescription
Idint (PK)Auto-increment primary key
AudienceIdint (FK)Parent audience
ImportedCountintNumber of prospects imported
Sourcenvarchar(100)Data source identifier
Statusint (enum)Pending, Processing, Complete, Failed
StartedAtdatetimeImport start time
CompletedAtdatetime?Import completion time

5.2 ClickHouse Tables

audience_contacts (ClickHouse)

Used for fast analytics reads. Synced from SQL Server after imports.

ColumnTypeDescription
audience_idUInt32Audience identifier
prospect_idUInt64Prospect identifier
statusUInt8Contact status (enum)
created_atDateTimeSync timestamp

Engine: MergeTree() ordered by (audience_id, prospect_id)


6. API Endpoints

Public API (/api/Audience)

MethodEndpointDescription
GET/api/Audience/GetAudiencesList audiences with pagination
GET/api/Audience/GetAudienceById/{id}Get audience detail
GET/api/Audience/GetAudienceContactsGet contacts for an audience
GET/api/Audience/GetAudienceStatistics/{id}Get statistics for an audience
POST/api/Audience/CreateAudienceCreate a new audience

Admin API (/api/admin/Audience)

MethodEndpointDescription
GET/api/admin/Audience/GetImportsByAudience/{id}Get import history
POST/api/admin/Audience/RecalculateStatistics/{id}Trigger stats recalculation
POST/api/admin/Audience/SyncToClickhouse/{id}Manual ClickHouse sync

7. Services & Business Logic

AudienceService

Location: AudienceServices/AudienceService.cs
Interface: IAudienceService
DI Registration: AddScoped<IAudienceService, AudienceService>() in ApiServiceExtensions.cs

Key methods:

MethodDescription
CreateAudienceAsync()Creates audience + filters, enqueues import job
GetAudienceByIdAsync()Returns audience with stats and filters
GetAudienceContactsAsync()Paginated contact list with search
RecalculateStatisticsAsync()Recounts all deduplication categories

AudienceHangfireService

Location: HangfireServices/AudienceHangfireService.cs
Interface: IAudienceHangfireService
DI Registration: AddTransient<IAudienceHangfireService, AudienceHangfireService>()

Key methods:

MethodDescription
RunImportJobAsync()Imports prospects in batches, runs dedup
RunDeduplicationAsync()Categorizes contacts as engaged/other/remaining
SyncToClickhouseAsync()Syncs audience data to ClickHouse

AudienceContactRepository

Location: Repository/Audience/AudienceContactRepository.cs
Interface: IAudienceContactRepository

Key methods:

MethodDescription
GetContactsByAudienceAsync()Paginated query with filters
InsertBatchAsync()Bulk insert contacts
CheckDuplicatesAsync()Check against engaged and other audiences
GetDeduplicationCountsAsync()Counts per category for statistics

8. ClickHouse Integration

Audience data is synced to ClickHouse for fast analytical reads. The sync uses the Dapper-based ClickHouse service.

Service: IRepositoryDapperClickhouseDbService
Pattern: Always use Dapper, never raw ExecuteReader

// Example: Querying ClickHouse for audience stats
await _dapperClickhouseDbService.Get<AudienceStatsDto>(
"SELECT audience_id, count() as total FROM audience_contacts WHERE audience_id = @audienceId GROUP BY audience_id",
new Dictionary<string, object> { { "audienceId", audienceId } },
useCache: false,
provider: DbProvider.Clickhouse
);

Sync trigger: After import completion and statistics recalculation.


9. Configuration

DI Registration

DataApi: API/SoProMasterDBAPI/Extensions/ApiServiceExtensions.cs

services.AddScoped<IAudienceService, AudienceService>();
services.AddScoped<IAudienceRepository, AudienceRepository>();
services.AddScoped<IAudienceContactRepository, AudienceContactRepository>();

Hangfire: Registered as AddTransient for background job isolation.

Frontend Configuration

API Hooks: src/api/audience.queries.ts
Endpoints: src/api/endpoints.tsendpoints.audiences


10. Integration Points

Upstream (data flows in)

SourceDataMechanism
Prospect DatabaseProspect records matching audience filtersSQL query during import
Campaign SystemEngaged status (which prospects are in active campaigns)Deduplication check at import

Downstream (data flows out)

TargetDataMechanism
ClickHouseAudience contact data for fast analyticsDapper-based sync after import
Campaign ManagementAudience linked to campaign for outreachForeign key relationship
Data Admin UIAudience stats, contacts, import historyREST API → React Query

Cross-Feature Dependencies

FeatureRelationship
Campaign ManagementCampaigns link to audiences; campaign status affects dedup
Verification PipelineVerified email status can affect prospect availability
Search & FiltersAudience targeting uses the same filter system