Context
When adding new capabilities (routing, pricing tiers, new enforcement rules), the system must remain backward-compatible. Existing plans, clients, and audit data cannot break.
Patterns
- Default to off: New feature fields default to null/false/zero —
UseMultiplierBilling = false,ModelRoutingPolicyId = null - Nullable Cosmos extensions: New fields on
AuditLogDocumentandBillingSummaryDocumentmust be nullable — existing documents won't have them - Precheck is the choke point: All enforcement converges at
/api/precheck. Enrich its response rather than adding new enforcement endpoints - Redis-backed config, Cosmos-backed audit: Configuration entities (plans, policies, pricing) live in Redis. Audit trail lives in CosmosDB. Don't mix.
- In-memory cache for hot-path data: Use the
ChargebackCalculatorpattern (30s refresh, non-blocking) for any data accessed per-request - APIM policy reads precheck response: The policy trusts precheck. Add new response fields; don't add new APIM-to-backend calls
- Frontend types mirror backend DTOs:
src/chargeback-ui/src/types.tsmust stay in sync withsrc/Chargeback.Api/Models/
Examples
- Extending
ModelPricingwithMultiplier— existing pricing withMultiplier = 1.0behaves identically - Extending precheck with
routedDeployment— APIM policies that don't read it work fine PlanData.UseMultiplierBilling = falsemeans legacy billing path is unchanged
Anti-Patterns
- Adding required fields to existing Cosmos documents (breaks deserialization of old data)
- Creating new Redis data structures when extending existing ones works
- Putting enforcement logic in APIM policy XML instead of in the precheck endpoint (harder to test, harder to debug)
- Breaking the existing API contract (existing frontend must work without changes until updated)