phenix-marketing-campaigns-api
.NET 8 API managing marketing campaigns, templates, recipient lists and segmentation criteria over MongoDB, sending campaign email via MassTransit and importing legacy campaign data from the Phenix SQL database.
Health score
0 to 100 across seven weighted factors; nothing is hidden. Green is 75 and above, amber 50 to 74, red below 50. How scoring works.
Facts
| Languages | csharp |
| Frameworks | ASP.NET Core 8, MediatR, FluentValidation |
| Runtimes | .NET 8 |
| Tests / CI | good / CI in place |
| Last commit | 2026-02-16 |
| Owner | Owner unknown (mapping to be curated) |
| Domain | Customer communications (system generated; curate in repo-owners.json to override) |
| Product area | Phenix |
| Hosted | On-prem Deployed to our own machines
|
| Releases | 2 release pipeline(s): \marketing\marketing-campaigns\phenix-marketing-campaigns-api master; \marketing\marketing-campaigns\phenix-marketing-campaigns-api release |
| Integration | rest, masstransit, sqs, redis, jwt |
| Source | Open in Azure DevOps |
Dependencies in context
Entanglement
kernel Bound into the core by 2 mechanism(s).
- Pinning dependency: phenix-feature-service
- Shares core database sqlserver:Phenix
Detaches when its pinning dependencies are cut or multi-targeted (phenix-feature-service); and when the shared database group it belongs to gains an owned API or completes schema separation (sqlserver:Phenix).
Depends on / used by
Migration playbooks
Generated from this repo's assessment data: what is feasible, what blocks it, and the steps in order. Ratings: green means actionable now, amber means sequence other work first, red means blocked, grey means not applicable.
ZDD adoption
Ready with guardrailsClose: the deployment path exists, but specific checks are needed first, typically raising tests, auditing serialized data, or respecting a shared schema with expand and contract. Shares sqlserver:Phenix: expand and contract is mandatory for any schema change.
- Shares sqlserver:Phenix with 21 system(s): destructive schema change is prohibited in a single release; expand and contract only
- Serialized state or messages in flight (Redis or queues): new code must deserialize objects written by the previous version
- Feature flags come from phenix-feature-service (WCF-only): flag reads themselves are a legacy dependency to watch
- Adopt the four-stage discipline from the ZDD engineering standard: pre-deployment compatibility, deployment, feature activation behind a flag, post-release cleanup.
- Make every change dual-version safe: backwards-compatible APIs (new major version for breaking wire changes), expand and contract for any schema change, and consumers tolerant of unknown fields.
- Audit serialized data: anything in Redis, queues or shared caches must deserialize cleanly across adjacent versions.
- Wrap behaviour changes in feature flags so code deploys dark and release becomes a business decision, not a deployment event.
- Route deployments through the Workflow Engine's automated drain, deploy, health-check, return cycle (the path proven by the first automated production run in mid-2026).
- Verify with area-scoped regression rather than the whole-platform cycle, and watch error rates after rollout with automated rollback on alert.
SQL Server exit
Blocked by a shared core databasesqlserver:Phenix is shared, so this system cannot change engine on its own: every sharer moves in convoy. The stage 4 work (named owner, declarative schema, owned API) has to land first; after that, the steps below apply to whatever slice this system ends up owning.
- Inventory the schema and query surface of sqlserver:Phenix: tables, stored procedures, triggers, cross-database joins and anything else engine-specific.
- Confirm the target: PostgreSQL (relational model; keep transactions and joins, swap the engine).
- Data access is not through an ORM, so port the SQL by hand: translate T-SQL constructs, replace stored procedures with application code or target-native equivalents, and add integration tests around the queries that matter first.
- Stand up the target alongside SQL Server, backfill with an ETL pass (pgloader or an export/import job), then dual-write or replicate until parity is proven.
- Move reads to the target, watch correctness and latency, then cut writes over and keep SQL Server read-only until confidence is earned.
- Decommission the SQL Server database and remove the connection strings and firewall paths that pointed at it.
Containerisation
Ready to containeriseModern runtime, no hosted legacy transport: this service can follow the estate's proven container path (Dockerfile, shared pipeline template, ECS via Terraform).
- Add a Dockerfile and make the app read all configuration from environment variables and the secrets manager, never from machine-local files.
- Log to stdout and expose a health check endpoint so ECS can supervise it.
- Adopt the shared ci.yml pipeline template with the container parameters (awsRegion, containerAfterBuild, ecsTerraformRepo), which is exactly how the estate's existing AWS services deploy.
- Define the service in the Terraform repo, deploy to a non-production environment, then shift traffic and disarm the deployment-group release pipeline.
Recommended actions
No specific actions for this repo. It either needs only normal maintenance, or its work is covered by an estate-level action. See the full programme.
Assessment notes
phenix-marketing-campaigns-api
Purpose
Marketing campaigns service: CRUD and workflow for campaigns, campaign types, templates (HtmlAgilityPack templating with tags), recipient lists and segmentation criteria, plus activity tracking. Includes a migration subsystem that bulk-imports legacy campaign/template/recipient data from Phenix SQL tables (MarketingCampaignType, MarketingTemplate, etc.) into MongoDB with migration-history tracking.
Tech stack
C# .NET 8 minimal-API style (endpoint extensions, Asp.Versioning), MediatR, FluentValidation with auto-validation, central package management (Directory.Packages.props), Swashbuckle, PhenixAuth JWT authentication scheme, TC.Diagnostics health checks, Scrutor, RestEase HTTP clients, global.json pinning SDK 8 with rollForward latestMajor.
Deployment
prod_application with 2 releases. One YAML build (phenix-marketing-campaigns-api, azure-pipelines.yml using shared InternalOSS templates v1.0, SDK 8.x) feeding release pipelines under \marketing\marketing-campaigns\ (master, release). New Relic app names configured per environment (eight appsettings variants including training/datafixqa).
Dependencies
Internal: TC.ConnectionBroker suite (Sql, Mongo, Redis, Api, Aws, Wcf) → tc-connectionbroker; TC.Exceptions → tc-exceptions; TC.Mail.Sender.Contracts → tc-mail-sender (email dispatch); TC.Phenix.Feature → phenix-feature-service; TC.Phenix.CompanyInfo → company-info-api; TC.UserAccount.ServiceClient → backoffice-useraccount-service; RestEase clients for the Contact API (phenix-contact-api, sales-person and marketing segmentation queries) and Web Details API (tc-web-details-api). External: AWS SQS transport for MassTransit, New Relic.
Data stores
Owns MongoDB database PhenixMarketing (via Mongo ConnectionBroker; embedded JSON seeding for segmentation criteria and template tags). Reads the shared Phenix SQL database through the SQL ConnectionBroker for one-way legacy data migration. Redis backs the Phenix user cache (TC.Cache RedisDual).
Integration points
Inbound REST with JWT auth. Outbound REST to contact and web-details APIs; publishes mail-send commands over MassTransit/AmazonSQS; Redis caching. A WCF ConnectionBroker is registered for the UserAccount service client.
Code health
Strong: five test projects (unit tests per layer plus integration tests, 65 test files) on xUnit v3 with NSubstitute/Shouldly; YAML CI runs all non-integration tests. Actively developed (last commit 2026-02-16). README is untouched boilerplate.
Modernisation risks
Low priority — modern .NET 8, good tests, YAML CI. Residual risks: the migration path keeps a read dependency on the shared Phenix SQL database (removable once migration completes), and the UserAccount WCF client is a legacy protocol edge. Otherwise a model citizen for the target architecture.