Перейти к основному содержимому

Структура app-config.yaml

Нормативная спецификация не фиксирует конкретные секции — любая верхнеуровневая секция определяется приложением-потребителем. Ниже — соглашения по именованию и структурированию, выработанные экосистемой dagstack.

Верхнеуровневые секции общего назначения

Набор секций, которые встречаются в большинстве dagstack-приложений независимо от домена (биллинг, аналитика, чат-бот, индексатор, сервис нотификаций, и т.д.):

СекцияНазначениеОбязательно
appМетаинформация приложения (name, tagline).Нет, но рекомендуется.
dagstackНастройки plugin-system (plugin_dirs, переопределения).Если используется plugin-system.
loggingСтруктурированный логгер (dagstack/logger-spec).Рекомендуется.
tenancyМодель мульти-клиентности (dagstack/tenancy-spec).Если multi-tenant.
databaseПодключение к БД (host, port, pool_size).Domain-specific.
cacheRedis / memcached / локальный кеш.Domain-specific.
metricsPrometheus / OTLP endpoint.Рекомендуется в production.
<kind>.<name>Секция конкретного плагина вида kind с именем name.plugin-system apps.

Всё остальное — domain-specific секции, специфичные для приложения (billing, notifications, workers, auth, rag, email, scheduler, api, и т.д.).

Соглашения по именованию

ПравилоПример
snake_case для ключейbase_url, max_retries
Существительное в ед. числеdatabase, не databases
Boolean без is_ / has_enabled, не is_enabled
Timestamps в ISO 8601"2026-04-21T12:00:00Z"
Длительности с суффиксом _s / _ms / _mintimeout_s: 30, cache_ttl_min: 15
Размеры с суффиксом _bytes / _mb / _gbmax_upload_mb: 10

Пример: service-бэкенд

app-config.yaml
app:
name: "order-service"
tagline: "Обработчик заказов"

dagstack:
plugin_dirs:
- plugins/

database:
host: "${DB_HOST:-localhost}"
port: "${DB_PORT:-5432}"
name: "${DB_NAME:-orders}"
user: "${DB_USER}"
password: "${DB_PASSWORD}"
pool_size: 20

cache:
url: "${REDIS_URL:-redis://localhost:6379/0}"
ttl_min: 15

api:
host: "0.0.0.0"
port: 8080
cors_origins:
- "https://app.example.com"

workers:
concurrency: 8
queue_name: "orders"

logging:
level: "${LOG_LEVEL:-INFO}"
format: "${LOG_FORMAT:-json}"

tenancy:
mode: "${TENANCY_MODE:-single}"

Пример: data-processing-приложение с plugin-system

app-config.yaml
app:
name: "data-indexer"

dagstack:
plugin_dirs:
- plugins/

# Секции конкретных плагинов — по правилу <kind>.<name>:

source:
s3_bucket: # секция плагина source.s3_bucket
bucket: "${INGEST_BUCKET}"
region: "eu-central-1"
postgres: # секция плагина source.postgres
url: "${SOURCE_DB_URL}"

processor:
normalize: # секция плагина processor.normalize
locale: "en_US"
enrich: # секция плагина processor.enrich
api_key: "${ENRICHMENT_API_KEY}"

sink:
elasticsearch: # секция плагина sink.elasticsearch
url: "${ES_URL}"
index: "documents"

Каждый плагин читает свою секцию <kind>.<name> через config.getSection() — общий паттерн независимо от домена приложения.

Domain-specific примеры

dagstack одинаково подходит для разных классов приложений — несколько типичных конфигов:

E-commerce-биллинг (расчёт платежей):

billing:
provider: "${BILLING_PROVIDER:-stripe}"
webhook_secret: "${BILLING_WEBHOOK_SECRET}"
currency: "USD"
tax_rates:
default: 0.20
reduced: 0.05

Агрегатор нотификаций:

notifications:
email:
smtp_host: "${SMTP_HOST}"
from_address: "no-reply@example.com"
sms:
api_key: "${SMS_API_KEY}"
from_number: "+1-555-0100"
push:
fcm_key: "${FCM_KEY}"

AI / RAG-платформа (один из возможных кейсов):

llm:
base_url: "${OPENAI_BASE_URL:-https://api.openai.com/v1}"
api_key: "${OPENAI_API_KEY}"
model: "${OPENAI_MODEL:-gpt-4o-mini}"

vector_store:
url: "${QDRANT_URL:-http://localhost:6333}"
api_key: "${QDRANT_API_KEY}"

retrieval:
top_k: 10
min_score: 0.55

Во всех трёх кейсах механизмы конфиг-стека те же — слои, env-интерполяция, getSection(), подписки на изменения. Знания, специфичные для домена, живут в приложении, не в конфиг-стеке.

Правила merge для массивов

app-config.yaml
dagstack:
plugin_dirs:
- plugins/
- examples/plugins/
app-config.production.yaml
dagstack:
plugin_dirs:
- /opt/dagstack/plugins/

После merge (DAGSTACK_ENV=production):

dagstack:
plugin_dirs:
- /opt/dagstack/plugins/ # массив полностью заменён

Массив не конкатенируется. См. Слои — правила merge.

Null в слое-переопределении

app-config.yaml
cache:
redis:
url: "redis://localhost:6379/0"
app-config.local.yaml
cache:
redis: null # явное отключение кеша локально

null в слое-переопределении явно перекрывает значение базового слоя. Отсутствие ключа в переопределении — не изменяет base.

Комментарии

YAML поддерживает #-комментарии. Хорошая практика:

api:
# Максимум запросов в секунду на клиента. По умолчанию 10,
# для internal-сервисов можно поднять до 100.
rate_limit_rps: 10

Комментарии помогают оператору понять назначение неочевидных полей.

См. также