Configuration Recipes
Copy-ready patterns for the most common configuration tasks — Redis, Kafka, Observability, LLM models, JWT, and CORS.
Enabling Redis for a Tenant
Default cache is in-memory. To switch a tenant to Redis:
appsettings.Tenant.apexretail.json — switch the cache type (committed):
{
"SharpCache": {
"CacheType": "Redis"
}
}
appsettings.Tenant.apexretail.production.json — production Redis address (not committed):
{
"BizFirstAIDatabase": {
"Redis": "redis.apexretail.local:6379,password=<vault>,ssl=false,abortConnect=false,connectTimeout=5000"
},
"Database": {
"Redis": "redis.apexretail.local:6379,password=<vault>,ssl=false,abortConnect=false,connectTimeout=5000"
}
}
appsettings.Tenant.apexretail.development.json — local Docker Redis (committed):
{
"BizFirstAIDatabase": {
"Redis": "localhost:6379,abortConnect=false"
},
"Database": {
"Redis": "localhost:6379,abortConnect=false"
}
}
Enabling Kafka for a Tenant
Kafka is disabled by default. Topic names are stable across envs; broker addresses differ.
appsettings.Tenant.apexretail.json — enable and name topics (committed):
{
"EdgeStream": {
"Kafka": {
"Enabled": true,
"EventTopicName": "apexretail.events",
"DeadLetterTopicName": "apexretail.events.dlq",
"ConsumerGroupId": "apexretail-signalr",
"SeparateChatTopic": true,
"ChatTopicName": "apexretail.chat",
"TopicPartitionCount": 12,
"TopicReplicationFactor": 3,
"Acks": "all",
"EnableIdempotence": true,
"CompressionType": "snappy"
}
}
}
appsettings.Tenant.apexretail.production.json — broker addresses with SASL/SSL (not committed):
{
"EdgeStream": {
"Kafka": {
"BootstrapServers": "kafka1.apexretail.local:9092,kafka2.apexretail.local:9092,kafka3.apexretail.local:9092",
"SecurityProtocol": "sasl_ssl",
"SaslMechanism": "PLAIN",
"SaslUsername": "bizfirst-svc",
"SaslPassword": "<vault>",
"SslCaLocation": "/etc/ssl/certs/apexretail-ca.crt"
}
}
}
appsettings.Tenant.apexretail.development.json — local Kafka (committed):
{
"EdgeStream": {
"Kafka": {
"BootstrapServers": "localhost:9092",
"SecurityProtocol": "plaintext"
}
}
}
Tenant-Specific Observability
Each tenant can send traces and logs to their own Grafana/Loki/OTEL stack.
appsettings.Tenant.apexretail.production.json:
{
"BizFirst": {
"Observability": {
"ServiceName": "BizFirst.Ai.ApexRetail",
"Environment": "production",
"Tracing": {
"Enabled": true,
"OtlpEndpoint": "http://otel.apexretail.local:4317",
"SamplingRate": 0.1
},
"Logging": {
"Loki": {
"Enabled": true,
"Url": "http://loki.apexretail.local:3100",
"MinimumLevel": "Warning"
}
},
"Grafana": {
"Enabled": true,
"Url": "https://grafana.apexretail.local",
"ApiKey": "<vault>"
},
"DeepHealthChecks": {
"SqlServerConnectionString": "Data Source=sql.apexretail.local;...",
"RedisConnectionString": "redis.apexretail.local:6379,password=<vault>"
}
}
}
}
appsettings.Tenant.apexretail.development.json — verbose tracing, Loki off:
{
"BizFirst": {
"Observability": {
"ServiceName": "BizFirst.Ai.ApexRetail.Dev",
"Environment": "development",
"Tracing": {
"SamplingRate": 1.0
},
"Logging": {
"Loki": { "Enabled": false }
}
}
}
}
Tenant LLM Model Selection
Base defaults use gpt-4o-mini. A tenant on a premium plan gets gpt-4o
with their own API key.
appsettings.Tenant.apexretail.json — model preference (committed):
{
"Agent": {
"LlmConfig": {
"Provider": "openai",
"Model": "gpt-4o"
}
}
}
appsettings.Tenant.apexretail.production.json — API key (not committed):
{
"LlmProviders": [
{
"Provider": "openai",
"Models": [
{
"Id": "gpt-4",
"Name": "gpt-4o",
"Version": "2024-11-20",
"ApiKey": "<vault>",
"Type": "chat",
"MultiModal": true
}
]
}
]
}
Tenant JWT Configuration
Each tenant can have its own issuer, audience, and token lifetime.
appsettings.Tenant.apexretail.production.json:
{
"JWT": {
"Key": "<32-byte-base64-from-vault>",
"Issuer": "BizFirst.ApexRetail",
"Audience": "ApexRetail.Clients",
"ExpiryMinutes": 480
}
}
Tenant CORS Origins
The base appsettings.json lists localhost ports for development.
A tenant overrides this with their real portal URLs.
appsettings.Tenant.apexretail.json:
{
"CorsSettings": {
"AllowedOrigins": [
"https://portal.apexretail.com",
"https://admin.apexretail.com",
"https://pos.apexretail.com"
]
}
}
Decision Table — What Goes Where
| Setting type | File | Committed? |
|---|---|---|
| Feature flags, topic names, model choice | Tenant.{code}.json | Yes |
| Shared dev DB address | Tenant.{code}.development.json | Yes |
| Production DB, Redis, Kafka addresses | Tenant.{code}.production.json | No |
| Passwords, API keys, JWT signing keys | Tenant.{code}.production.json (from vault) | No |
| Your local SQL Server name | appsettings.Development.Local.json | No |
| Local Kafka / Redis (Docker) | appsettings.Development.Local.json | No |