Skip to main content

Audience UI Migration — Technical Documentation

Last updated: March 2026 Track: B (UI Migration) Status: Planned


Table of Contents

  1. Overview
  2. Existing Foundation
  3. Target UI Architecture
  4. Implementation Plan
  5. New Types & DTOs
  6. New API Endpoints & Hooks
  7. Component Breakdown
  8. Verification

1. Overview

Build a complete audience management UI in data-admin (React + TypeScript) that replaces the audience creation and settings workflows currently in Sodastream's SoProMasterSearchController. This track is independent of Track A (Database Consolidation) — it can start at any time and benefits from a single-database foundation once Track A is complete.

Scope

CapabilityCurrent StateTarget
Audience creation from searchExists (CreateAudienceModal) — basic fields onlyEnhanced with campaign selector, dedup settings, audience type
Audience settings managementSodastream onlyNew Settings tab in data-admin audience details
Email profile pickerSodastream onlyData API proxy → data-admin dropdown
Queue import actionExists (useQueueAudienceImport)Verify end-to-end, no changes expected
Audience list & detailsExists (list, tabs, contacts)No changes needed

2. Existing Foundation

2.1 data-admin — Already Implemented

The data-admin app already has significant audience infrastructure:

Pages:

  • src/pages/Audiences/ — Audience list with search and pagination
  • src/pages/Audiences/AudienceDetails/ — Detail view with tabs (Overview, Contacts, Settings placeholder)

Components:

  • src/components/audience/CreateAudienceModal.tsx — Modal for creating audiences from search results
  • src/components/audience/ — Various audience-specific components

API Hooks (src/api/audience.queries.ts):

  • useAudienceHeaders — Paginated audience list
  • useAudienceHeaderDetails — Single audience detail
  • useCreateAudienceFromSearch — Create audience from filter data
  • useQueueAudienceImport — Trigger import job
  • useTriggerEmailFinding — Start email finding
  • useGetAudienceImports — Import history

Endpoints (src/api/endpoints.ts):

  • ~40+ audience endpoints already defined
  • Covers CRUD, imports, email finding, verification, statistics

Types (src/types/audiences/):

  • AudienceHeaderModel.ts — Main audience type
  • CreateAudienceFromFilterDataRequest.ts — Creation DTO
  • Various supporting types

2.2 Sodastream — Features to Replicate

From SoProMasterSearchController, the features data-admin needs:

FeatureSodastream Implementationdata-admin Status
Search with filtersSoProMasterSearchController.Index/Search✅ Already exists (Search page)
Create audience from searchSaveSearchModalCreateAudienceDTO⚠️ Exists but needs enhancement
Campaign selectorCampaignDropdown + SoProQueueAudience.CampaignId❌ Not yet — needs Data API proxy
Email profile pickerEmailProfileCheckboxList❌ Not yet — needs Data API proxy
Daily import volumeDailyImportVolume input❌ Not in creation modal
Prospects per companyProspectsPerCompanyPerDay input❌ Not in creation modal
Auto import toggleIsAutomaticImport checkbox❌ Not in creation modal
Dedup daysAudienceDuplicateProspectDays❌ Not in creation modal
Settings edit pageInline edits in Sodastream❌ No settings tab yet

3. Target UI Architecture


4. Implementation Plan

4.1 Enhance CreateAudienceModal

Current: Basic modal with name and filter summary. Target: Full creation form with all settings needed for import.

New fields to add:

  1. Campaign selector — Dropdown queried from Data API (proxy to Sodastream campaigns)
  2. Daily import volume (ContactsPerDay) — Number input
  3. Prospects per company per day (ContactsPerCompanyPerDay) — Number input
  4. Email profile picker — Multi-select checkbox, queried by campaign
  5. Dedup days (AudienceDuplicateProspectDays) — Number input
  6. Auto email finding toggle (IsEmailFindingActive) — Checkbox
  7. Audience type / approach (ApproachId) — Dropdown

4.2 Build Audience Settings Tab

New tab in the audience details page for editing audience settings post-creation.

Layout: Form with sections matching the creation modal fields, pre-populated from AudienceHeader data. Uses useForm (React Hook Form) for state management and validation.

Sections:

  • Import Configuration — Daily volume, per-company cap, auto email finding toggle
  • Campaign & Approach — Campaign (read-only or selectable), approach selector
  • Email Profiles — Multi-select profile picker (loaded by campaign)
  • Dedup Settings — Dedup window days, options
  • Active Toggles — Audience enabled, campaign audience active, ad sync flags

4.3 Email Profile Proxy Endpoint

Data API needs to proxy email profiles from Sodastream since they live in the Sodastream database.

GET /admin/Audience/GetEmailProfiles/{campaignId}

Backend: ISodaStreamService.GetEmailProfilesAsync(int campaignId) — calls Sodastream DB, returns list of { Id, Name, IsDeleted }.

4.4 Campaign List Proxy Endpoint

Data API needs to provide campaigns for the dropdown. Already partially exists via SodaStreamService.GetAllCampaignsAsync().

GET /admin/Audience/GetCampaigns

5. New Types & DTOs

5.1 Frontend Types (data-admin)

src/types/audiences/UpdateAudienceSettingsRequest.ts

export interface UpdateAudienceSettingsRequest {
audienceId: string;
name?: string;
contactsPerDay?: number;
contactsPerCompanyPerDay?: number;
isEmailFindingActive?: boolean;
isCampaignAudienceActive?: boolean;
isAudienceEnabled?: boolean;
isAdSync?: boolean;
isAdSyncActive?: boolean;
emailProfileIds?: string;
emailProfileNames?: string;
deletedEmailProfileIds?: string;
audienceDuplicateProspectDays?: number;
option?: number;
approachId?: number;
}

src/types/audiences/EmailProfileModel.ts

export interface EmailProfileModel {
id: number;
name: string;
isDeleted: boolean;
}

src/types/audiences/CampaignSelectModel.ts

export interface CampaignSelectModel {
id: number;
name: string;
clientName: string;
}

5.2 Backend DTOs (sopromasterdata)


6. New API Endpoints & Hooks

6.1 Endpoints to Add

src/api/endpoints.ts:

audiences: {
// ... existing endpoints ...
updateAudienceSettings: "/admin/Audience/UpdateAudienceSettings",
getEmailProfiles: "/admin/Audience/GetEmailProfiles", // + /{campaignId}
getCampaigns: "/admin/Audience/GetCampaigns",
}

6.2 New React Query Hooks

src/api/audience.queries.ts:

// Update audience settings
export const useUpdateAudienceSettings = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (request: UpdateAudienceSettingsRequest) => {
const response = await api.put(endpoints.audiences.updateAudienceSettings, request);
return response.data;
},
onSuccess: (_data, variables) => {
queryClient.invalidateQueries({ queryKey: ["audienceHeaderDetails", variables.audienceId] });
},
});
};

// Get email profiles for campaign
export const useGetEmailProfiles = (campaignId: number | null) => {
return useQuery({
queryKey: ["emailProfiles", campaignId],
queryFn: async () => {
const response = await api.get<EmailProfileModel[]>(`${endpoints.audiences.getEmailProfiles}/${campaignId}`);
return response.data;
},
enabled: !!campaignId,
});
};

// Get campaigns for dropdown
export const useGetCampaigns = () => {
return useQuery({
queryKey: ["campaigns"],
queryFn: async () => {
const response = await api.get<CampaignSelectModel[]>(endpoints.audiences.getCampaigns);
return response.data;
},
});
};

7. Component Breakdown

7.1 Enhanced CreateAudienceModal

ComponentLocationResponsibility
CreateAudienceModalsrc/components/audience/CreateAudienceModal.tsxModify — Add new form sections
CampaignSelectorsrc/components/audience/CampaignSelector.tsxNew — Campaign dropdown with search
EmailProfilePickersrc/components/audience/EmailProfilePicker.tsxNew — Multi-select email profiles
ImportSettingsFormsrc/components/audience/ImportSettingsForm.tsxNew — Daily volume, per-company cap, auto toggle

7.2 Audience Settings Tab

ComponentLocationResponsibility
AudienceSettingsTabsrc/pages/Audiences/AudienceDetails/tabs/AudienceSettingsTab.tsxNew — Settings form container
ImportConfigSectionsrc/components/audience/settings/ImportConfigSection.tsxNew — Import settings section
CampaignConfigSectionsrc/components/audience/settings/CampaignConfigSection.tsxNew — Campaign & approach section
EmailProfileSectionsrc/components/audience/settings/EmailProfileSection.tsxNew — Email profile management
DedupConfigSectionsrc/components/audience/settings/DedupConfigSection.tsxNew — Dedup settings section
ActiveTogglesSectionsrc/components/audience/settings/ActiveTogglesSection.tsxNew — Toggle switches section

7.3 Shared Components

Reuse existing UI components from src/components/ui/:

  • Button — Form actions
  • Badge — Status indicators
  • Form components — Input, Select, Checkbox, Toggle
  • Table — Email profile list
  • Spinner — Loading states

8. Verification

Create Audience Flow

  1. Navigate to Search page → Run search with filters
  2. Click "Create Audience" → Enhanced modal opens
  3. Fill in all fields: name, campaign, import volume, email profiles, dedup days
  4. Submit → POST /admin/Audience/CreateAudienceFromSearch called
  5. Verify AudienceHeader created with all settings
  6. Verify SoProQueueAudience created with mapped fields (if Track A not yet at A3)
  7. Navigate to new audience → All settings visible in Settings tab

Settings Edit Flow

  1. Navigate to existing audience → Settings tab
  2. Form pre-populated with current AudienceHeader values
  3. Edit fields → Submit
  4. PUT /admin/Audience/UpdateAudienceSettings called
  5. Verify AudienceHeader updated
  6. Verify reverse sync to SoProQueueAudience (if Track A not yet at A3)

Import Flow

  1. Create audience with settings → Queue import
  2. Verify TaskAudienceBuilderAutomationsDaily uses correct settings
  3. Verify prospects imported matching the configured volume and per-company caps

Edge Cases

  • Campaign with no email profiles → Show empty state with message
  • Setting ContactsPerDay to 0 → Warn user that imports will be paused
  • Audience already linked to campaign → Campaign selector read-only in settings

Repository Map

RepositoryLayerKey FilesAction
data-adminPagesrc/pages/Audiences/AudienceDetails/Add Settings tab
data-adminComponentsrc/components/audience/CreateAudienceModal.tsxEnhance with new fields
data-adminComponentsrc/components/audience/CampaignSelector.tsxNew
data-adminComponentsrc/components/audience/EmailProfilePicker.tsxNew
data-adminComponentsrc/components/audience/settings/New directory — all settings sections
data-adminAPI Hookssrc/api/audience.queries.tsAdd useUpdateAudienceSettings, useGetEmailProfiles, useGetCampaigns
data-adminEndpointssrc/api/endpoints.tsAdd 3 new endpoint entries
data-adminTypessrc/types/audiences/UpdateAudienceSettingsRequest.tsNew
data-adminTypessrc/types/audiences/EmailProfileModel.tsNew
data-adminTypessrc/types/audiences/CampaignSelectModel.tsNew
sopromasterdataControllerAPI/.../Admin/AudienceController.csAdd GetEmailProfiles, GetCampaigns
sopromasterdataServiceSodaStreamServices/SodaStreamService.csAdd GetEmailProfilesAsync()