server:
  addr: ":8080"
  web_ui_base_url: "${ALERTSTORE_WEB_UI_BASE_URL}"
  ops_portal_base_url: "${OPS_PORTAL_BASE_URL}"

database:
  dsn: "${DB_DSN}"

im:
  provider: lark
  main_channel_id: "${LARK_MAIN_CHANNEL_ID}"
  app_id: "${LARK_APP_ID}"
  app_secret: "${LARK_APP_SECRET}"
  lark_base_url: "https://open.feishu.cn"

clinic:
  base_url: "https://clinic.pingcap.com"
  token: "${CLINIC_TOKEN}"
  # jiralert prod's ActivityHub endpoint, chosen while alertstore dev mirrored
  # the jiralert prod feed. That forward is off now, so this wants revisiting
  # once a non-prod ActivityHub source exists.
  activity_url: "https://e4hr1v4oqh.execute-api.us-west-2.amazonaws.com/activities/"
  activity_source: "eventbus"
  activity_key: "${EVENT_KEY}"
  timeout: 5s

# The DevOps ops portal, which owns the commercial view of a tenant: the sales
# region it belongs to (NA/EMEA/APAC/…, not the cloud region an alert's labels
# carry) and whether the account is internal or a customer's. jiralert and
# jiraport read the same two columns straight out of `devops_prod.tenants`;
# alertstore asks the service that owns them. Leave base_url empty to disable —
# alerts then carry neither field.
#
# Deployments point at the portal's own listener, in the same cluster, and read
# it through `/api/v1/devops-internal`, which carries no auth middleware and is
# reachable on the private network only — so api_token stays empty there, the
# same arrangement as oncall and directory below. Set it to a service token only
# when talking to the authenticated `/api/v1/devops` route through the shared
# gateway instead.
devops:
  base_url: "${DEVOPS_BASE_URL}"
  api_token: "${DEVOPS_API_TOKEN}"
  timeout: 5s
  cache_ttl: 30m

# The oncall v2 service (services/oncall), which owns duty schedules. Alerts
# route by their `oncall_team` label; default_team owns the ones without it.
# Leave base_url empty to disable — alerts are then created unassigned.
#
# Deployments point at that service's internal listener
# (`oncall-internal.<ns>.svc.cluster.local`), which is ClusterIP-only and
# authenticates nothing, so api_key stays empty there. Set it to a service key
# with the `oncall:read` scope when talking to the authenticated listener
# instead.
oncall:
  base_url: "${ONCALL_BASE_URL}"
  api_key: "${ONCALL_TOKEN}"
  default_team: "${ONCALL_DEFAULT_TEAM}"
  timeout: 5s
  cache_ttl: 1m
  # Honor the per-rule `assign` label (`none` skips assignment, an email pins
  # the owner). Unset means false — prod honors it. Set the literal `true` in
  # dev/staging so production rules' opt-outs and real emails are ignored and
  # every alert routes through the duty schedule instead.
  ignore_assign_label: ${ALERTSTORE_IGNORE_ASSIGN_LABEL}

# core-server's user directory (services/core-server), a mirror of the Lark org
# chart. It backs the assignee autocomplete in the web UI: type part of a name
# or an email and pick the person instead of recalling their address. Leave
# base_url empty to disable — the field is free text either way, it just stops
# suggesting.
#
# core-server runs in the same cluster, and its own listener authenticates
# nothing — the shared devops gateway does that in front of it — so this call
# carries no credential at all.
directory:
  base_url: "${CORE_SERVER_BASE_URL}"
  timeout: 5s
  cache_ttl: 5m

alert:
  response_deadline: 15m
  recovery_deadline: 4h

# Agents. Which agents exist and which alerts they want lives in the
# agent_subscription table, not here — an agent's reach changes as it earns
# trust, and that is data, not a redeploy. This section only says how to reach
# alertstore back, and how much of the agent's opinion is withheld from the
# people whose independent judgement is the yardstick it is scored against.
#
# Leave callback_base_url empty to disable dispatch entirely. In-cluster, this
# is alertstore's own service address: agents talk to it directly and never
# through the public gateway.
agent:
  callback_base_url: "${ALERTSTORE_AGENT_CALLBACK_BASE_URL}"
  timeout: 10s
  # 0 while no agent output is rendered on any human surface. Raise it in the
  # same release that first shows a verdict to a resolver — a held sample cannot
  # be created after the fact, and labels collected without one are anchored on
  # the verdict they are supposed to be judging.
  hold_rate: 0

webhook:
  # Accepted bearer tokens; the --secrets overlay replaces this list. Name is
  # for observability only, not access.
  alertmanager_tokens:
    - name: default
      secret: "${ALERTSTORE_WEBHOOK_TOKEN}"

# Transitional, deleted along with jiralert. See docs/design.md "The Cutover".
#
# A rule carrying `response_class` is alertstore's: naming the response it wants
# is what asks this service to run it, and jiralert reads the same label to stop
# responding to it. Everything else is a shadow copy of jiralert's alert —
# stored and queryable, topic posted marked "Recorded only", but no owner, no
# buzz, no subscription forward and no Jira issue, because jiralert and jiraport
# are still doing all three. Dropping the label hands one rule back; its
# classification then falls back to severity, as a shadow alert's always has.
#
# own_everything ignores the label. Unset means false; set the literal `true`.
cutover:
  own_everything: ${ALERTSTORE_OWN_EVERYTHING}

# The Jira mirror: alertstore creates the ticket jiralert used to, so automation
# reading Jira keeps working. Only owned alerts get one. Leave any of the four
# empty to disable, which is the end state.
#
# project/summary_prefix match what jiralert uses for this environment's
# receivers (O11Y/[PROD], O11YSTAG/[STAGING], O11YDEV/[DEV]); they follow the
# deployment because each alertstore serves one environment. Everything else
# about the issue is fixed in pkg/jira.
#
# This file is baked into the image and only env-substituted at startup, so
# anything per-environment has to be an env var, not a literal.
jira:
  base_url: "${JIRA_BASE_URL}"
  user: "${JIRA_USER}"
  token: "${JIRA_TOKEN}"
  project: "${JIRA_PROJECT}"
  summary_prefix: "${JIRA_SUMMARY_PREFIX}"
