Skip to main content

Environment Setup — Technical Documentation

Also known as: Multi-environment isolation, staging/testing infrastructure, environment separation Last updated: February 2026


Table of Contents

  1. Overview
  2. Architecture
  3. Current State
  4. Target State
  5. Repository Map
  6. Database Topology
  7. Connection Resolution Flow
  8. Key Vault Configuration
  9. API Deployment
  10. AudienceConsoles Deployment
  11. Sodastream Wiring
  12. data-admin Configuration
  13. Queue Infrastructure
  14. Configuration Reference
  15. Integration Points

1. Overview

Sopro Data currently runs a single production environment — one Data API instance, one set of databases — shared by all three Sodastream environments (production, staging, testing). RequestedBySystem (an integer enum) is the only discriminator between environments at the data level.

The goal is full environment isolation: each Sodastream environment gets its own Data API deployment, its own databases, its own Key Vault, and its own queue connections. No code changes are required — the existing Settings DB + Key Vault configuration pattern already supports multi-environment deployments.


2. Architecture

Current (Single Environment)

Target (Isolated Per Environment)


3. Current State

ComponentProductionStagingTesting
Sodastreamsopro-sodastream (live)sodastreamfresh (staging)testing instance
Data APIapi.soprodata.com (single)← same← same
Audience DBsingle shared DB← same← same
Master DBsingle shared DB (deprecated)← same← same
ClickHousesingle shared DB← same← same
Key Vaultsingle vault← same← same
Azure QueuesSoProQueueStorageSoProQueueStagingStorage (exists)not configured
AudienceConsolesEnvironment.txt = ProductionConsumerConsoleStaging (legacy)not deployed
Data separationRequestedBySystem = 1RequestedBySystem = 3RequestedBySystem = 6

Key problems:

  • All environments write to the same databases — a staging test can corrupt production data
  • Campaign ID collisions — Sodastream campaign 4092 in staging is a different campaign than 4092 in production, but they share the same Audience DB table
  • No safe testing — automation tests run against production data
  • No feature verification — can't test staging API changes against staging Sodastream end-to-end

4. Target State

ComponentProductionStagingTesting
Sodastreamsopro-sodastream (live)sodastreamfresh (staging)testing instance
Data APIapi.soprodata.comapi-staging.soprodata.comapi-testing.soprodata.com
Audience DBaudience_prodaudience_stagingaudience_testing
MarketMap DBmarketmap_prodmarketmap_stagingmarketmap_testing
Logging DBlogging_prodlogging_staginglogging_testing
Hangfire DBhangfire_prodhangfire_staginghangfire_testing
Data Verification DBverification_prodverification_stagingverification_testing
ClickHousesoprodata_prodsoprodata_stagingsoprodata_testing
Key Vaultsopro-data-keyvaultsopro-data-keyvault-stagingsopro-data-keyvault-testing
Azure QueuesSoProQueueStorageSoProQueueStagingStorageSoProQueueTestingStorage
AudienceConsolesEnvironment.txt = ProductionEnvironment.txt = StagingEnvironment.txt = Testing
Settings DBproduction Settings DBstaging Settings DBtesting Settings DB

Databases NOT replicated (deprecated/not needed):

  • Master DB — deprecated; staging/testing running without it validates the system has no remaining dependency
  • Sphinx/Manticore — deprecated search index; same rationale
  • Crunchbase — external reference data; not needed for testing

5. Repository Map

RepositoryRole in Environment SetupChanges Needed
sopromasterdataData API, Hangfire, AudienceConsoles, Settings DB resolutionNone — same codebase, different config per deployment
sopro-sodastreamCalls Data API via SoProMasterDBAdapterFix hardcoded localhost:5000 in SimpleInjectorInitializer.cs; update SoProMasterDBAdapterClientCredentials per environment
data-adminReact frontend, connects to APIAdd .env.staging pointing to staging API URL
sopro-automation-testsE2E/API testsConfigure Data API tests to run against testing environment

6. Database Topology

Databases Per Environment (Clone Schema Only, No Data)

DatabasePurposeKey Tables/Entities
AudienceCore operational dataAudienceHeader, AudienceContact, AudienceImport, SoproCampaigns, SoproClients, AudienceStatistics
MarketMapMarket segmentation dataMAP definitions, coverage data
LoggingApplication logsSerilog sink tables
HangfireBackground job stateJob, State, Server, Set, Hash (Hangfire schema)
Data VerificationEmail verification jobsVerificationJob, VerificationResult
ClickHouseAnalytics, prospect sync, reportingsAudience, AudienceDetails, SoproProspect, Reportings

Databases Not Cloned

DatabaseReason
Master DBDeprecated — not replicating validates no dependency
Sphinx/ManticoreDeprecated search index
CrunchbaseExternal reference data, not needed for testing

7. Connection Resolution Flow

All Sopro Data applications resolve database connections dynamically at startup. No connection strings are hardcoded in appsettings files.

Key files:

  • API/SoProMasterDBAPI/Configuration/ConnectionOptions.cs — holds all resolved connection strings as properties (Master, Audience, Settings, MarketMap, Logging, Reporting, DataVerification, Clickhouse, Sphinx, Sopro, SoproQueue, etc.)
  • API/SoProMasterDBAPI/Extensions/ApiServiceExtensions.cs — registers DbContexts and Dapper services with environment-specific connections
  • AudienceConsoles/Extensions/ServiceCollectionExtensions.cs — same pattern for console apps, reads Environment.txt or ASPNETCORE_ENVIRONMENT

8. Key Vault Configuration

Each environment gets its own Azure Key Vault to prevent cross-environment secret access.

EnvironmentKey Vault NameStores
Productionsopro-data-keyvaultProduction DB connections, API keys, JWT signing key, queue connections
Stagingsopro-data-keyvault-stagingStaging equivalents of all above
Testingsopro-data-keyvault-testingTesting equivalents of all above

Existing pattern: AudienceConsoles/Extensions/ServiceCollectionExtensions.cs already supports environment-specific Key Vault sections (KeyVault, KeyVaultTesting, KeyVaultExternal).

Each environment's appsettings.{Environment}.json points to its own Key Vault URI:

{
"KeyVault": {
"VaultUri": "https://sopro-data-keyvault-staging.vault.azure.net/"
}
}

9. API Deployment

The Data API runs Hangfire in-process — deploying a staging API automatically creates staging Hangfire workers.

Per-environment deployment:

SettingHow It Differs
SoProMasterSettingsConnectionPoints to environment-specific Settings DB
Key Vault URIPoints to environment-specific Key Vault
ASPNETCORE_ENVIRONMENTProduction / Staging / Testing
Hangfire DBResolved from Settings DB → isolated job state
HangfireComputers tableControls per-machine worker count in each environment's Settings DB

Recurring Hangfire jobs (auto-scheduled at startup in Program.cs):

  • ScheduleEmailFindingJobsRecurringJob
  • FetchLinkedInAccountMasterConnections
  • CalculateTrustScore
  • ScheduleRecurringCampaignStatisticsRefreshJob
  • ScheduleDailySyncJob

All jobs process data from whichever database their environment's Settings DB points to — no code changes needed.


10. AudienceConsoles Deployment

Environment selection: Environment.txt file (or ASPNETCORE_ENVIRONMENT env var) at the console binary's location.

Config chain: Environment.txtappsettings.{Env}.json → Key Vault → Settings DB → resolved connections

Precedent: ConsumerConsoleStaging project already exists with appsettings.Staging.json and appsettings.StagingExternal.json.

Console Inventory

#ConsoleTypeEnvironment Relevance
1EmailFindingConsoleQueueMust process environment-specific queue
3RecalculateCampaignStatisticsConsoleQueueWrites stats to environment's Audience DB
97AudienceFetchProspectsConsoleQueueFetches prospects into environment's Audience DB
99ProcessDataVerificationConsoleQueueProcesses verification jobs in environment's Verification DB
100SoproSyncConsoleQueueCriticalConnectionOptions.Sopro must point to the correct Sodastream SQL Server (staging vs production)
200SyncAudienceChangesToClickhouseConsoleSyncSyncs to environment's ClickHouse DB
201SyncDetailsChangesToClickhouseConsoleSyncSyncs to environment's ClickHouse DB
209SyncSoproProspectsToClickhouseConsoleSyncIncremental sync to environment's ClickHouse DB
302ProcessCompanySuitabilityConsoleQueueProcesses suitability in environment's Audience DB
303AutoRefreshCampaignAudiencesConsoleQueueAuto-refresh in environment's Audience DB

11. Sodastream Wiring

Each Sodastream environment stores its Data API target in the SoProMasterDBAdapterClientCredentials table.

ColumnProductionStagingTesting
ApiUrlhttps://api.soprodata.comhttps://api-staging.soprodata.comhttps://api-testing.soprodata.com
ApiKeyproduction keystaging keytesting key
RequesterEnum1 (Sodastream)3 (StagingSodastream)6 (SodastreamTesting)

Required fix: Sodastream/Web/Web/App_Start/SimpleInjectorInitializer.cs currently hardcodes credentials.ApiUrl = "http://localhost:5000", overriding the database value. This line must be removed so the URL is read from the SoProMasterDBAdapterClientCredentials table.

// REMOVE THIS LINE:
credentials.ApiUrl = "http://localhost:5000";

15 adapters route through ApiControllers which gets its URL from this single credential record: AuthAdapter, AudienceAdapter, CompanyAdapter, ProspectAdapter, MarketMapAdapter, UtilsAdapter, LocationAdapter, SalesAgentAdapter, UniqueDomainAdapter, TechnologyCompanyEmailsAdapter, ListBuildAccountAdapter, DataNotificationAdapter, DataVerificationAdapter, HostMachinesAdapter, GeneralAdapter.


12. data-admin Configuration

FileAPI URLUsage
.env.developmenthttps://localhost:5001/apiLocal development
.env.staging (new)https://api-staging.soprodata.com/apiStaging testing
.env.productionhttps://api.soprodata.com/apiProduction build

When embedded in Sodastream's iframe, the frontend inherits the environment from the JWT token — the Sodastream environment determines which API the embedded app talks to.

Sodastream's AudiencesController.BuildEmbedUrl() needs a configurable dataAdminBaseUrl (currently hardcoded to http://localhost:5173) — sourced from Web.config appSetting or the SoProMasterDBAdapterClientCredentials table.


13. Queue Infrastructure

Queue ConnectionEnvironmentConfig Key
SoProQueueStorageProductionExisting
SoProQueueStagingStorageStagingExisting (pattern)
SoProQueueTestingStorageTestingNew

Queue-based consoles (BaseQueueConsole<T>) resolve their queue connection string from the environment's Key Vault / Settings DB. Staging and testing consoles read from isolated queues — no cross-environment message leakage.


14. Configuration Reference

appsettings Keys

KeyPurposePer-Environment
SoProMasterSettingsConnectionBootstrap connection to Settings DBYes
KeyVault:VaultUriAzure Key Vault URIYes
ConnectionOptions:*All database connections (resolved from Settings DB)Yes (via Settings DB)
SoProQueueStorageProduction Azure Storage Queue connectionYes (via Key Vault)
SoProQueueStagingStorageStaging Azure Storage Queue connectionYes (via Key Vault)
JwtSettings:KeyJWT signing keyYes (via Key Vault)
SoproDataAuth:SoproDataApiKeyAPI key for X-SoproDataApiKey validationYes (via Key Vault)

Settings DB — Connections Table

ColumnPurpose
NameConnection identifier (e.g. Master, Audience, Clickhouse)
ConnectionTypeEnvironment discriminator (Internal, External)
ConnectionStringEncrypted connection string (decrypted via SimpleStringCipher)

15. Integration Points

Each arrow stays within its environment boundary. Production Sodastream → Production API → Production databases. Staging Sodastream → Staging API → Staging databases. No cross-environment communication.