# Configuration Reference ## Config File `weatherfeeder` reads exactly one YAML file named `config.yml` from the current working directory. There is no config path flag and no search path. YAML decoding is strict for config struct fields: misspelled fields such as `sources[].drviver` fail startup. Driver-specific `params` maps are validated by the source or sink constructor that consumes them. The top-level file contains: ```yaml sources: - name: NWSObservationKSTL mode: poll driver: nws_observation every: 10m kinds: ["observation"] params: url: "https://api.weather.gov/stations/KSTL/observations/latest" user_agent: "Example weatherfeeder operator (ops@example.com)" sinks: - name: stdout driver: stdout params: {} routes: - sink: stdout kinds: ["observation"] ``` `sources` and `sinks` must each contain at least one entry. `routes` is optional. When `routes` is omitted, every configured sink receives every event kind. ## Production-Oriented Shape A typical deployment uses multiple polling sources and sends the same canonical event stream to a broker or database: ```yaml sources: - name: NWSAlertsLocal mode: poll driver: nws_alerts every: 1m kinds: ["alert"] params: url: "https://api.weather.gov/alerts?point=38.6239,-90.3571&limit=20" user_agent: "Example weatherfeeder operator (ops@example.com)" sinks: - name: nats_weather driver: nats params: url: nats://nats:4222 subject: weatherfeeder - name: pg_weather driver: postgres params: uri: postgres://weatherdb:5432/weatherdb?sslmode=disable username: weatherdb password: "" prune: 3d routes: - sink: nats_weather kinds: ["observation", "forecast", "forecast_discussion", "weather_story", "alert"] - sink: pg_weather kinds: ["observation", "forecast", "forecast_discussion", "weather_story", "alert"] ``` Do not commit real API keys, database passwords, or personal contact addresses in copyable configs. ## Top-Level Fields | Field | Required | Description | |---|:---:|---| | `sources` | yes | List of configured input sources. | | `sinks` | yes | List of configured output sinks. | | `routes` | no | List of sink routing rules. If omitted, all sinks receive all kinds. | ## Source Fields | Field | Required | Description | |---|:---:|---| | `name` | yes | Unique source name. Used as the event source identifier. | | `driver` | yes | Source driver name. | | `mode` | no | `poll`, `stream`, or omitted for auto. Current weatherfeeder drivers are polling drivers. | | `every` | yes | Poll interval for current weatherfeeder source drivers. | | `kinds` | no | Expected event kinds. If present, startup verifies they match the source driver. | | `params` | driver-specific | Driver parameters. Current source drivers require HTTP params. | Current event kinds are `observation`, `forecast`, `forecast_discussion`, `weather_story`, and `alert`. ## Source Drivers | Driver | Kind | Upstream product | |---|---|---| | `nws_observation` | `observation` | NWS station latest observation. | | `nws_alerts` | `alert` | NWS alerts collection. | | `nws_forecast_hourly` | `forecast` | NWS hourly gridpoint forecast. | | `nws_forecast_narrative` | `forecast` | NWS narrative gridpoint forecast. | | `nws_forecast_discussion` | `forecast_discussion` | NWS forecast discussion HTML product. | | `nws_weatherstories` | `weather_story` | NWS office weather stories. | | `openmeteo_observation` | `observation` | Open-Meteo current conditions. | | `openmeteo_forecast` | `forecast` | Open-Meteo hourly forecast. | | `openweather_observation` | `observation` | OpenWeather current weather. | ## HTTP Source Params All current source drivers use the shared HTTP polling helper. | Param | Required | Description | |---|:---:|---| | `url` | yes | Full upstream request URL. `URL` is also accepted by the helper. | | `user_agent` | yes | User-Agent sent to the upstream provider. `userAgent` is also accepted by the helper. | | `conditional` | no | Boolean. Defaults to `true`; enables ETag and Last-Modified conditional requests. | | `http_timeout` | no | Positive duration for the HTTP client timeout. | | `http_response_body_limit_bytes` | no | Positive integer response body limit in bytes. | When `conditional` is enabled and the upstream returns `304 Not Modified`, the source emits no events for that poll. OpenWeather observation URLs must include `units=metric`. Startup fails if the URL omits it or sets another unit system. ## Sink Fields | Field | Required | Description | |---|:---:|---| | `name` | yes | Unique sink name. Routes refer to this value. | | `driver` | yes | Sink driver name. | | `params` | driver-specific | Sink parameters. | ## Sink Drivers ### `stdout` Prints each event as JSON to stdout. ```yaml sinks: - name: stdout driver: stdout params: {} ``` ### `nats` Publishes each event as JSON to a NATS subject. | Param | Required | Description | |---|:---:|---| | `url` | yes | NATS server URL, such as `nats://localhost:4222`. | | `subject` | yes | Subject to publish events to. | ### `postgres` Writes supported canonical weather events to Postgres using weatherfeeder's registered schema mapping. | Param | Required | Description | |---|:---:|---| | `uri` | yes | PostgreSQL connection URI. | | `username` | yes | Database username. | | `password` | yes | Database password. | | `prune` | no | Retention window. If set, rows older than the window are pruned on each write transaction. | `prune` accepts Go duration strings such as `72h`, plus day and week suffixes such as `3d` and `2w`. ## Routes Routes connect event kinds to sinks: ```yaml routes: - sink: stdout kinds: ["observation", "alert"] ``` | Field | Required | Description | |---|:---:|---| | `sink` | yes | Name of a configured sink. | | `kinds` | no | Event kinds to send to that sink. Omit or use an empty list to match all kinds. | Route `kinds` values are trimmed and lowercased by the dispatcher. Blank entries are rejected. ## Duration Formats Top-level source `every` accepts: - Go duration strings such as `30s`, `10m`, or `1h`; - integer values, interpreted as minutes; - numeric strings such as `"15"`, also interpreted as minutes. HTTP param durations such as `http_timeout` accept Go duration strings. Numeric values and numeric strings are interpreted as seconds. Postgres `prune` must be a string duration. ## Secrets The config file is read directly from disk and has no built-in secret expansion. Keep real credentials out of repository-tracked configs. Use deployment tooling to render `config.yml` with the needed secret values before starting the daemon.