229 lines
8.0 KiB
Markdown
229 lines
8.0 KiB
Markdown
# Development Policy
|
|
|
|
## Purpose
|
|
|
|
This document describes how to change `weatherfeeder` safely. It is for
|
|
maintainers and coding agents working in the repository.
|
|
|
|
Use this alongside the [architecture policy](architecture.md). User-facing CLI,
|
|
configuration, operations, and wire-contract details belong in their canonical
|
|
docs, not here.
|
|
|
|
## Repository Layout
|
|
|
|
- `cmd/weatherfeeder/`: executable wiring, sample `config.yml`, and runtime
|
|
composition tests.
|
|
- `model/`: canonical weather payload structs. JSON tags are part of the wire
|
|
contract.
|
|
- `standards/`: schema strings, versioning conventions, WMO constants, and
|
|
shared wire-format policy.
|
|
- `internal/sources/`: source adapters that poll upstream providers and emit raw
|
|
feed events.
|
|
- `internal/normalizers/`: raw-to-canonical event transforms.
|
|
- `internal/providers/`: pure provider helper code shared by sources and
|
|
normalizers.
|
|
- `internal/sinks/postgres/`: weatherfeeder-owned Postgres schema and canonical
|
|
event mapper.
|
|
- `docs/`: current behavior, policies, integration contracts, and roadmap files.
|
|
- `examples/`: maintained, copyable configuration examples.
|
|
|
|
## Build And Test
|
|
|
|
Run the full test suite before committing behavior or documentation changes that
|
|
depend on code behavior:
|
|
|
|
```sh
|
|
go test ./...
|
|
```
|
|
|
|
Use narrower commands while iterating:
|
|
|
|
```sh
|
|
go test ./cmd/weatherfeeder
|
|
go test ./internal/sources/...
|
|
go test ./internal/normalizers/...
|
|
go test ./internal/sinks/postgres
|
|
```
|
|
|
|
Format Go code before committing:
|
|
|
|
```sh
|
|
gofmt -w <changed-go-files>
|
|
```
|
|
|
|
Do not require live upstream weather services, NATS, or Postgres for unit tests.
|
|
Use fixtures, local test servers, and package-level tests.
|
|
|
|
## Coding Conventions
|
|
|
|
- Keep `cmd/weatherfeeder` focused on composition: config load, registry setup,
|
|
scheduler jobs, processor chain, dispatch, signal handling, and logging.
|
|
- Keep source fetching separate from normalizer mapping.
|
|
- Match normalizers by schema constants from `standards`, not source names.
|
|
- Keep provider-specific helper code under `internal/providers/<provider>` when
|
|
both sources and normalizers use it.
|
|
- Keep cross-provider normalizer helpers pure and deterministic under
|
|
`internal/normalizers/common`.
|
|
- Keep sink persistence mapping isolated under `internal/sinks/<sink>`.
|
|
- Wrap errors with operation context, but do not include whole upstream payloads
|
|
in errors or logs by default.
|
|
- Prefer explicit registries and small package-level constructors over hidden
|
|
global behavior.
|
|
|
|
## Architecture-Preserving Changes
|
|
|
|
When changing `weatherfeeder`, preserve the split between feedkit
|
|
infrastructure and weather-domain behavior.
|
|
|
|
Do:
|
|
|
|
- keep generic scheduling, dispatch, processor, config, and sink mechanics in
|
|
feedkit;
|
|
- keep weather provider rules in source adapters, provider helpers, and
|
|
normalizers;
|
|
- keep canonical weather payloads in `model` and schema/wire identifiers in
|
|
`standards`;
|
|
- keep Postgres table and row mapping under `internal/sinks/postgres`;
|
|
- use explicit registries for built-in sources and normalizers.
|
|
|
|
Do not:
|
|
|
|
- move provider parsing, WMO mapping, or canonical weather policy into
|
|
`cmd/weatherfeeder`;
|
|
- move weather-specific constants, schemas, or validation rules into feedkit;
|
|
- put database column metadata or sink-specific tags on canonical model structs;
|
|
- replace explicit registries with dynamic plugin loading;
|
|
- introduce broad abstractions when a small provider-specific helper preserves
|
|
clarity.
|
|
|
|
## Dependency Policy
|
|
|
|
Prefer the Go standard library unless a dependency materially improves
|
|
maintainability or interoperability.
|
|
|
|
`feedkit` owns generic daemon infrastructure for config, HTTP source helpers,
|
|
scheduling, processors, dispatch, and sinks. Weatherfeeder code should contain
|
|
weather-domain behavior and narrow adapter logic rather than duplicating feedkit
|
|
infrastructure.
|
|
|
|
Do not add broad dependencies for small conveniences. Do not let
|
|
dependency-specific types leak across package boundaries unless that dependency
|
|
is the package contract.
|
|
|
|
## Adding Config Fields
|
|
|
|
Generic config shape is owned by feedkit. Weatherfeeder-specific config behavior
|
|
belongs in source or sink constructors, registry setup, and tests.
|
|
|
|
When adding config behavior:
|
|
|
|
- validate required params at the adapter boundary;
|
|
- keep secrets in environment variables or placeholders, not committed values;
|
|
- update [configuration docs](../config.md);
|
|
- update maintained examples when the change affects normal operation;
|
|
- add or update config-load tests for example files when practical.
|
|
|
|
## Adding CLI Flags
|
|
|
|
The executable currently reads `config.yml` from the current working directory.
|
|
If CLI flags are added:
|
|
|
|
- keep parsing in `cmd/weatherfeeder`;
|
|
- avoid moving config policy into domain packages;
|
|
- update [CLI docs](../cli.md);
|
|
- update tests that exercise command behavior.
|
|
|
|
## Adding A Source Driver
|
|
|
|
Source drivers should fetch upstream data and emit raw events with minimal
|
|
metadata decoding.
|
|
|
|
Checklist:
|
|
|
|
- implement the driver under `internal/sources/<provider>`;
|
|
- build from `config.SourceConfig`;
|
|
- validate required params in the constructor;
|
|
- use feedkit HTTP helpers for HTTP polling when applicable;
|
|
- emit raw schema constants from `standards`;
|
|
- advertise emitted kinds through `Kinds()`;
|
|
- decode only metadata needed for event ID and effective time;
|
|
- register the driver in `internal/sources/builtins.go`;
|
|
- add constructor, kind, and polling tests;
|
|
- update config docs and examples when operators need new configuration;
|
|
- add provider integration notes when the provider contract needs maintenance
|
|
context.
|
|
|
|
## Adding A Normalizer
|
|
|
|
Normalizers own provider-to-canonical mapping.
|
|
|
|
Checklist:
|
|
|
|
- add one normalizer type per normalizer file;
|
|
- match using `Event.Schema`;
|
|
- decode raw payloads into provider structs;
|
|
- map to canonical `model` payloads;
|
|
- use `internal/normalizers/common.Finalize` so envelope handling and float
|
|
rounding stay consistent;
|
|
- preserve input envelope fields except schema, payload, and effective time;
|
|
- register through the provider package and `internal/normalizers/builtins.go`;
|
|
- add tests for schema matching, key payload fields, effective time, malformed
|
|
required data, and output validation.
|
|
|
|
## Adding Canonical Models Or Schemas
|
|
|
|
Canonical event changes affect multiple contracts.
|
|
|
|
Checklist:
|
|
|
|
- update payload structs in `model`;
|
|
- add or update schema constants in `standards`;
|
|
- update [event wire contract docs](../integrations/events.md);
|
|
- update normalizers that produce the schema;
|
|
- update Postgres mapping if the schema is persisted;
|
|
- add tests for wire shape and mapper behavior.
|
|
|
|
## Adding Postgres Mapping
|
|
|
|
Weatherfeeder owns the canonical-event-to-table mapping. Feedkit owns the
|
|
generic Postgres sink mechanics.
|
|
|
|
Checklist:
|
|
|
|
- update `internal/sinks/postgres/schema.go`;
|
|
- update `internal/sinks/postgres/map.go`;
|
|
- preserve event envelope columns in parent rows when the table supports them;
|
|
- validate required canonical fields before writing;
|
|
- use positional indexes for child rows that represent arrays;
|
|
- update mapper and schema tests;
|
|
- update [Postgres integration docs](../integrations/postgres.md) when the table
|
|
contract changes.
|
|
|
|
## Examples And Documentation
|
|
|
|
Documentation must follow the [documentation policy](documentation.md).
|
|
|
|
When behavior changes, update the canonical docs in the same change:
|
|
|
|
- config shape: `docs/config.md`;
|
|
- CLI behavior: `docs/cli.md`;
|
|
- operations and recovery: `docs/operations.md`;
|
|
- troubleshooting: `docs/troubleshooting.md`;
|
|
- external contracts: `docs/integrations/`;
|
|
- internal component behavior: `docs/internal/`;
|
|
- copyable configs: `examples/`.
|
|
|
|
Keep roadmap content under `docs/roadmap/`. Current-behavior docs must describe
|
|
implemented behavior only.
|
|
|
|
## Review Checklist
|
|
|
|
Before committing:
|
|
|
|
- run focused tests for changed packages;
|
|
- run `go test ./...` for broad behavior or documentation changes tied to code;
|
|
- verify maintained examples still load when examples or config docs changed;
|
|
- check links in changed docs;
|
|
- search for stale paths, unsupported features, and secret-like values;
|
|
- keep unrelated refactors out of the change.
|