4.7 KiB
Registration Service
ASP.NET Core (.NET 8) service for managing prospect registration in AdPlatform.
Self-hosted via docker-compose as registration:8080 behind nginx / Gateway.
Architecture
Client SPA (client.positivespend.com)
└─► Gateway (portal.positivespend.com)
└─► Registration API (regapi.positivespend.com → registration:8080)
├─► dbRegistration (10.10.99.212 — Registrations table, spRegistration)
└─► CIAM (PositiveSpendClients.ciamlogin.com — token validation)
Management API (mgmt.positivespend.com)
└─► Registration API (admin endpoints, x-functions-key auth)
└─► dbRegistration
The Registration service never touches dbAdPlatform. Management never touches dbRegistration.
Approval provisioning into dbAdPlatform is the Management API's responsibility, called after
the complete action marks a registration as Approved.
Endpoints
| Method | Route | Auth | Description |
|---|---|---|---|
POST |
/api/registration/register |
Bearer (CIAM JWT) | New prospect signup |
GET |
/api/registration/pending |
x-functions-key | List pending applicants |
GET |
/api/registration/item/{id} |
x-functions-key | Get single applicant |
POST |
/api/registration/action/{id}/reject |
x-functions-key | Reject applicant |
POST |
/api/registration/action/{id}/complete |
x-functions-key | Mark approved |
GET |
/api/health |
Anonymous | Health check |
entraSubjectId is never read from the request body on /register — it is extracted
from the validated CIAM Bearer token (OID claim). The client cannot spoof it.
Authentication
Client-facing endpoint (/register): Bearer token issued by
PositiveSpendClients.ciamlogin.com (tenant cbf8b7d7). Validated by
Microsoft.Identity.Web against the CIAM tenant. The Client SPA acquires this
token via MSAL after the user signs in with Google, Apple, or Microsoft.
Admin endpoints (pending / item / reject / complete): x-functions-key header
validated by ApiKeyAuthFilter. Key must match Registration__FunctionKey env var.
These endpoints are called by the Management API, not the browser.
CIAM Tenant Reference
| Field | Value |
|---|---|
| Tenant | Positive Spend Clients |
| Tenant ID | cbf8b7d7-1e13-486d-b5b0-287ba79fdf0b |
| Client SPA App ID | c426967f-bfcc-46af-b4e5-d69dc01cbf75 |
| Authority | https://PositiveSpendClients.ciamlogin.com/cbf8b7d7.../ |
This is the client-facing CIAM tenant — separate from the internal positivespend.com
org tenant (f56a3c51) used by Management and the Tech/Admin consoles.
Mock Mode
Switch in Program.cs to run without a database (seeds 4 test applicants in memory):
services.AddSingleton<IRegistrationDataService, MockDataService>();
State resets on container restart — by design.
Database Setup
Run dbo.spRegistration.sql against dbRegistration on 10.10.99.212 once.
It is idempotent (CREATE OR ALTER PROCEDURE, IF OBJECT_ID ... IS NULL guard on the table).
docker-compose Environment Variables
# SQL Server
ConnectionStrings__Sql=Server=10.10.99.212;Database=dbRegistration;User Id=appAdPlatformReg;Password=...;TrustServerCertificate=True;
# CIAM — already correct in .env
AzureAd__Instance=https://PositiveSpendClients.ciamlogin.com/
AzureAd__TenantId=cbf8b7d7-1e13-486d-b5b0-287ba79fdf0b
AzureAd__ClientId=c426967f-bfcc-46af-b4e5-d69dc01cbf75
# CORS — already in .env
CORS__AllowedOrigins=https://client.positivespend.com,https://portal.positivespend.com,...
# Admin key — already in .env
Registration__FunctionKey=mra0B2boC5m36E7CUn-Urhwp7k3t3QvPZKjJvtNVEdVgAzFuuaAyRA==
Health Check
curl https://regapi.positivespend.com/api/health
# {"ok":true,"service":"registration","mode":"database","timestamp":"..."}
SSL
sudo certbot --nginx -d regapi.positivespend.com
Host Swap — Restore Azure Functions
Three files change. Everything else (Data layer, Mock layer, models, SQL) is identical.
| File | Change |
|---|---|
Registration.csproj |
Comment ASP.NET Core ItemGroup, uncomment Functions ItemGroup, restore <AzureFunctionsVersion>v4</AzureFunctionsVersion>, change Sdk to Microsoft.NET.Sdk |
Program.cs |
Comment ASP.NET Core block, uncomment Functions HostBuilder block |
Functions/RegistrationFunctions.cs |
Swap class declaration, swap each method signature (all marked ◄ INACTIVE) |
Client changes when restoring Functions:
authConfig.js: setAPI_BASE_URLto the Azure Function App URL, setAPI_FUNCTION_KEYfrom Azure Portal → App Keys → default
Run locally in Functions mode:
func start
curl http://localhost:7071/api/health