# Aviso Server example configuration (local-test friendly).
# Adjust URLs, secrets, and schema fields for your environment.
application:
# HTTP bind address/port.
host: "127.0.0.1"
port: 8000
# Used in generated metadata links.
base_url: "http://localhost"
# Landing-page assets.
static_files_path: "./src/static"
watch_endpoint:
# SSE heartbeat interval (seconds).
sse_heartbeat_interval_sec: 30
# Max watch connection lifetime (seconds).
connection_max_duration_sec: 3600
# Replay tuning.
replay_batch_size: 100
max_historical_notifications: 10000
replay_batch_delay_ms: 100
# Parallel event conversion workers.
concurrent_notification_processing: 15
notification_backend:
# `in_memory` or `jetstream`.
kind: in_memory
in_memory:
# Retained messages per topic.
max_history_per_topic: 10000
# Tracked topics.
max_topics: 100
# Authentication and authorization
# - disabled: API is public only when schemas do not declare stream auth rules
# - enabled:
# - admin endpoints always require auth + one of `admin_roles`
# - notify/watch/replay enforce auth only when stream has `auth.required: true`
# - if auth-o-tron is unreachable, authenticated requests fail with 503
auth:
# Enable authentication middleware.
enabled: true
# Authentication mode:
# - direct: Aviso authenticates credentials via auth-o-tron (JWT/Basic).
# - trusted_proxy: Aviso validates a forwarded Bearer JWT using jwt_secret.
mode: direct
# auth-o-tron base URL (required when enabled=true and mode=direct).
auth_o_tron_url: "http://localhost:8080"
# JWT secret (required when enabled=true).
# Keep empty when auth is disabled.
# Must match auth-o-tron signing configuration.
# For scripts/example_auth_config.yaml, this should be "your-shared-secret".
jwt_secret: "your-shared-secret"
# Realm-scoped roles allowed on /api/v1/admin/* (must be non-empty when enabled=true).
# Maps realm names (from JWT `realm` claim) to authorized role lists.
admin_roles:
localrealm: ["admin"]
# auth-o-tron request timeout (milliseconds).
timeout_ms: 5000
# trusted_proxy mode validates forwarded Bearer JWT using jwt_secret.
# No extra trusted_proxy block is needed.
metrics:
# Enable Prometheus metrics on a separate internal port.
enabled: false
# Bind address for the metrics server. Defaults to 127.0.0.1 (loopback).
# host: "127.0.0.1"
# Required when enabled=true; must differ from application.port.
# port: 9090
logging:
# OTel-aligned JSON logs.
level: info
format: json
# Schema definitions
# Each stream defines topic shape, identifier validation, payload requirement,
# and optional auth policy. These schemas are used by scripts/smoke_test.py.
notification_schema:
# Public stream (no auth block => anonymous access even when auth.enabled=true).
test_polygon:
payload:
required: true
topic:
base: "polygon"
key_order: ["date", "time"]
identifier:
date:
type: DateHandler
canonical_format: "%Y%m%d"
required: false
time:
type: TimeHandler
required: false
polygon:
type: PolygonHandler
required: true
# Authenticated stream with read/write role separation.
# - Any authenticated user in localrealm can read (wildcard).
# - Only producer or admin roles can write.
mars:
payload:
required: false
topic:
base: "mars"
key_order: ["class", "expver", "domain", "date", "time", "stream", "step"]
auth:
required: true
read_roles:
localrealm: ["*"]
write_roles:
localrealm: ["producer"]
identifier:
class:
type: StringHandler
max_length: 2
required: true
date:
type: DateHandler
canonical_format: "%Y%m%d"
required: false
domain:
type: EnumHandler
values: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
required: false
expver:
type: ExpverHandler
default: "0001"
required: false
step:
type: IntHandler
range: [0, 100000]
required: false
stream:
type: StringHandler
required: false
time:
type: TimeHandler
required: false
# Authenticated stream with admin-only writes.
# - Any authenticated user can read (no read_roles restriction).
# - Only admins can write (no write_roles => defaults to admin_roles).
dissemination:
payload:
required: true
topic:
base: "diss"
key_order: ["destination", "target", "class", "expver", "domain", "date", "time", "stream", "step"]
auth:
required: true
identifier:
class:
type: StringHandler
max_length: 2
required: true
date:
type: DateHandler
canonical_format: "%Y%m%d"
required: false
destination:
type: StringHandler
required: true
target:
type: StringHandler
required: false
domain:
type: EnumHandler
values: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
required: false
expver:
type: ExpverHandler
default: "0001"
required: false
step:
type: IntHandler
range: [0, 100000]
required: false
stream:
type: StringHandler
required: false
time:
type: TimeHandler
required: false
# Smoke test auth verification (with scripts/example_auth_config.yaml):
# 1) test_polygon without Authorization => 200 (no auth block)
# 2) mars without Authorization => 401 (auth.required=true)
# 3) mars with reader-user => read 200, write 403
# 4) mars with producer-user => write 200
# 5) mars with admin-user => read 200, write 200
# 6) dissemination with reader-user => read 200, write 403 (admin-only writes)
# 7) dissemination with admin-user => read 200, write 200