Overview
PriceSignal uses ASP.NET Core’s configuration system, which supports multiple configuration sources including appsettings.json, environment variables, and mounted secrets.
Configuration Priority
Configuration is loaded in this order (later sources override earlier ones):
appsettings.json - Base configuration
Environment-specific files - appsettings.{Environment}.json
Environment variables
Mounted secrets (production only)
Environment Variables
Required Variables
# ASP.NET Core Environment
ASPNETCORE_ENVIRONMENT = Development
# Database Connection
ConnectionStrings__PriceSignalDB = Host = localhost ; Port = 5432 ; Database = price_signal ; Username = postgres ; Password = yourpassword
# NATS Message Broker
Nats__Url = nats://localhost:4222
Optional Variables
# Binance Settings (when enabled)
Binance__Enabled = true
Binance__WebsocketUrl = wss://stream.binance.com:9443/stream? streams = btcusdt@aggTrade/ethusdt@aggTrade
Binance__ApiUrl = https://api.binance.com
# Alpaca Settings
Alpaca__ApiUrl = https://data.alpaca.markets
# Logging
Logging__LogLevel__Default = Information
Logging__LogLevel__Microsoft.AspNetCore =Warning
Logging__LogLevel__Microsoft.EntityFrameworkCore.Database.Command =Warning
Configuration Sections
Database Configuration
The database connection method differs between development and production environments.
Development
Uses connection string from appsettings.json or environment variable:
{
"ConnectionStrings" : {
"PriceSignalDB" : "Host=localhost;Port=5432;Database=price_signal;Username=postgres;Password=example"
}
}
Or as environment variable:
ConnectionStrings__PriceSignalDB = "Host=localhost;Port=5432;Database=price_signal;Username=postgres;Password=example"
Production
Reads PostgreSQL URI from /app/secrets/uri file (mounted from Kubernetes secret):
postgresql://username:password@host:5432/price_signal
The application automatically converts this to Npgsql format:
if ( isDevelopment )
{
connectionString = configuration . GetConnectionString ( "PriceSignalDB" );
}
else
{
connectionString = ConvertToNpgsqlConnectionString ( File . ReadAllText ( "/app/secrets/uri" ));
}
NATS Configuration
NATS is used for message passing between services (e.g., Telegram bot notifications):
# Docker development
Nats__Url = nats://host.docker.internal:4222
# Kubernetes production
Nats__Url = nats://nats:4222
# External NATS cluster
Nats__Url = nats://nats-1:4222,nats://nats-2:4222,nats://nats-3:4222
Binance Configuration
Binance integration provides real-time cryptocurrency price feeds:
appsettings.json
Environment Variables
{
"Binance" : {
"WebsocketUrl" : "wss://stream.binance.com:9443/stream?streams=btcusdt@aggTrade/ethusdt@aggTrade" ,
"ApiUrl" : "https://api.binance.com" ,
"Enabled" : "true"
}
}
When Binance__Enabled=true, the application starts background services for:
BinancePairUpdateService - Monitors trading pairs
BinancePriceFetcherService - Fetches real-time prices
BinanceBackfillService - Backfills historical data
BinanceProcessingService - Processes price updates
Alpaca Configuration
Alpaca provides stock and cryptocurrency market data:
appsettings.json
Environment Variables
{
"Alpaca" : {
"ApiUrl" : "https://data.alpaca.markets"
}
}
Logging Configuration
{
"Logging" : {
"LogLevel" : {
"Default" : "Information" ,
"Microsoft.AspNetCore" : "Warning" ,
"Microsoft.EntityFrameworkCore.Database.Command" : "Warning"
}
}
}
Override with environment variables:
Logging__LogLevel__Default = Debug
Logging__LogLevel__Microsoft.AspNetCore =Information
Logging__LogLevel__Microsoft.EntityFrameworkCore.Database.Command =Information
Authentication Configuration
PriceSignal uses Firebase Authentication:
options . Authority = "https://securetoken.google.com/nxtspec" ;
options . TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true ,
ValidIssuer = "https://securetoken.google.com/nxtspec" ,
ValidateAudience = true ,
ValidAudience = "nxtspec" ,
ValidateLifetime = true
};
The Firebase project ID (nxtspec) is hardcoded. To use a different Firebase project, you’ll need to modify the authentication configuration in Program.cs:75-83.
Docker Configuration
Docker Compose Environment
services :
server :
image : nayth/price-signal-graph:latest
environment :
- ASPNETCORE_ENVIRONMENT=Development
- Nats__Url=nats://host.docker.internal:4222
- Binance__Enabled=false
ports :
- 8080:8080
Using .env File
Create a .env file in the same directory as compose.yaml:
# .env
ASPNETCORE_ENVIRONMENT = Development
NATS_URL = nats://host.docker.internal:4222
BINANCE_ENABLED = false
# For production
ALPACA_API_KEY = your_key_here
ALPACA_API_SECRET = your_secret_here
DB_USER = postgres
DB_PASSWORD = strong_password_here
Reference in compose.yaml:
services :
server :
environment :
- ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT}
- Nats__Url=${NATS_URL}
- Binance__Enabled=${BINANCE_ENABLED}
- Alpaca__ApiKey=${ALPACA_API_KEY}
- Alpaca__ApiSecret=${ALPACA_API_SECRET}
Kubernetes Configuration
ConfigMap for appsettings.json
The Pulumi deployment creates a ConfigMap from the application’s appsettings.json:
var webserverconfig = new ConfigMap ( "appsettings" , new ()
{
Metadata = new ObjectMetaArgs
{
Namespace = webserverNs . Metadata . Apply ( m => m . Name ),
},
Data =
{
{ "appsettings.json" , File . ReadAllText ( "../src/PriceSignal/appsettings.json" ) },
},
});
This is mounted at /app/appsettings.json in the container.
Environment Variables from Pulumi Config
Sensitive values are injected as environment variables:
var env = new []
{
new EnvVarArgs ()
{
Name = "Alpaca__ApiKey" ,
Value = config . RequireSecret ( "alpacaApiKey" ),
},
new EnvVarArgs ()
{
Name = "Alpaca__ApiSecret" ,
Value = config . RequireSecret ( "alpacaApiSecret" ),
},
new EnvVarArgs ()
{
Name = "Nats__Url" ,
Value = config . require ( "natsUrl" ),
},
};
Secrets Volume Mount
Database credentials are mounted from a Kubernetes secret:
volumeMounts :
- mountPath : /app/secrets
name : price-signal-secret-volume
readOnly : true
volumes :
- name : price-signal-secret-volume
secret :
secretName : timescale-cluster-app
Frontend Configuration
The React frontend is built with a configured WebSocket URL:
Build-time Configuration
FROM node:21 AS build-node
WORKDIR /app
COPY src/react-app/ ./
ENV VITE_WS_URL=wss://price-signal-graph.nxtspec.com/graphql
RUN npm install && npm run build
Custom WebSocket URL
Build with a custom URL:
docker build \
--build-arg VITE_WS_URL=wss://your-domain.com/graphql \
-t price-signal:custom .
Configuration Best Practices
Never commit sensitive credentials to version control. Use environment variables, secrets managers, or encrypted Pulumi configs.
Development
Use appsettings.Development.json for local overrides
Keep a .env.example file with dummy values
Use host.docker.internal for Docker-to-host connections
Enable detailed logging for debugging
Production
Use environment-specific appsettings.Production.json
Store secrets in Kubernetes Secrets or secret managers
Use encrypted Pulumi config for sensitive values
Enable only necessary logging to reduce noise
Use strong, randomly generated passwords
Restrict network access to databases and internal services
Validation
Check Configuration at Runtime
# View environment variables in container
docker compose exec server env | sort
# Check appsettings.json
docker compose exec server cat /app/appsettings.json
# Kubernetes pod
kubectl exec -it < pod-nam e > -- env | sort
kubectl exec -it < pod-nam e > -- cat /app/appsettings.json
Test Database Connection
# From application container
docker compose exec server dotnet PriceSignal.dll --check-db
# Direct PostgreSQL test
psql " $ConnectionStrings__PriceSignalDB " -c "SELECT version();"
Next Steps