Files
weatherapi/docs/policy/development.md

160 lines
5.9 KiB
Markdown

# Development Policy
This document gives developers and LLM coding agents the concrete workflow for
changing `weatherapi` safely. Architecture invariants are defined in
[`docs/policy/architecture.md`](architecture.md).
## Repository Layout
| Path | Purpose |
| --- | --- |
| `cmd/weatherapi` | executable composition root |
| `internal/app` | read use cases, repository port, current-conditions model |
| `internal/adapters/inbound/httpapi` | route definitions, query binding, handlers |
| `internal/adapters/inbound/httpapi/presenter` | response payload shaping |
| `internal/adapters/outbound/postgres` | SQL reads and row mapping |
| `templates` | text response templates |
| `docs` | current documentation, policy, internals, integrations, roadmap |
| `examples` | copyable config and request examples |
## Build and Test Commands
Build:
```sh
go build ./cmd/weatherapi
```
Run all tests:
```sh
go test ./...
```
Focused tests:
```sh
go test ./internal/app
go test ./internal/adapters/inbound/httpapi
go test ./internal/adapters/inbound/httpapi/presenter
go test ./internal/adapters/outbound/postgres
```
Private module access is required for `feedapi` and `weatherfeeder` downloads.
If tests fail because Go cannot fetch a private module, fix module access before
treating package tests as behavior failures.
## Coding Conventions
- Keep `cmd/weatherapi` thin.
- Keep application use cases independent of HTTP, SQL, renderers, and templates.
- Keep query validation in the HTTP adapter.
- Keep unit conversion, rounding, timezone presentation, and payload copy
behavior in presenters.
- Keep SQL text, row structs, null handling, and UTC normalization in the
Postgres adapter.
- Prefer small focused changes over broad refactors.
- Preserve contextual error wrapping in repository and runtime code.
## Dependency Policy
Current direct dependencies are:
- `feedapi` for config, DB registry, endpoint definitions, renderers,
middleware, templates, and HTTP runtime;
- `weatherfeeder` for canonical model and standards types;
- `github.com/lib/pq` for the Postgres driver.
Do not add dependencies for small conveniences. New dependencies need a clear
adapter or domain purpose and should not leak through application boundaries
unless they are the explicit boundary contract.
## Adding or Changing Endpoints
1. Add or update the `Service` method in `internal/adapters/inbound/httpapi` if
the handler needs a new application read.
2. Add or update the application repository port in `internal/app`.
3. Implement the read in the Postgres adapter if needed.
4. Add the endpoint definition and binder in `internal/adapters/inbound/httpapi`.
5. Add presenter behavior in `presenter` instead of shaping payloads in handlers.
6. Add or update text templates when `format=text` should be supported.
7. Add endpoint tests for registration, query validation, formats, errors,
`data: null`, and representative payload behavior.
8. Update [`docs/api.md`](../api.md) and examples when the public HTTP contract changes.
## Changing Query Parameters
- Update binder functions and endpoint tests together.
- Preserve strict unknown-parameter rejection unless the route explicitly allows
a new parameter.
- Keep timezone parsing limited to route families that support it.
- Keep precision range validation aligned with presenter rounding support.
- Update [`docs/api.md`](../api.md) for public query behavior changes.
## Adding Config Fields
Config shape is loaded by feedapi. When `weatherapi` starts using a new config
field:
1. update runtime composition or the relevant adapter;
2. update [`docs/config.md`](../config.md);
3. update examples under `examples/` if operators need to set it;
4. add config/runtime tests where practical;
5. avoid committing real credentials or private infrastructure details.
## Adding CLI Flags
The executable currently supports only `-config`. If adding a flag:
1. keep parsing in `cmd/weatherapi`;
2. avoid putting business logic in `cmd`;
3. document precedence with environment variables if applicable;
4. update [`docs/cli.md`](../cli.md);
5. add tests when flag behavior is not trivial.
## Changing Repository Reads
- Keep SQL in `*_queries.go`.
- Keep row DTOs in `*_rows.go`.
- Keep mapping/null handling in `*_mapper.go`.
- Return `nil, nil` for missing latest parent rows.
- Normalize timestamps to UTC in mappers.
- Preserve child ordering from stored index columns.
- Update [`docs/internal/postgres-repository.md`](../internal/postgres-repository.md)
and [`docs/integrations/weatherfeeder-postgres.md`](../integrations/weatherfeeder-postgres.md)
when table or column assumptions change.
## Changing Presenters or Templates
- Copy input values before conversion, rounding, or timezone changes.
- Preserve nil pointer and `omitempty` behavior.
- Keep text-template helper fields out of JSON/XML when they are not public API
fields.
- Check `templates/*.txt.tmpl` for field references.
- Update presenter tests and endpoint text tests.
- Update [`docs/api.md`](../api.md) when response shape changes.
## Updating Examples
Examples must be copyable, valid, and free of secrets.
- Config examples belong under `examples/config.*.yml`.
- HTTP examples belong in `examples/requests.http`.
- Do not include unimplemented routes.
- Re-run YAML syntax checks or config loading tests when config examples change.
## Documentation Checklist
When behavior changes, update the canonical doc in the same change:
- README for project orientation and shortest useful command;
- `docs/api.md` for public HTTP behavior;
- `docs/config.md` for YAML config;
- `docs/cli.md` for executable flags and environment variables;
- `docs/operations.md` and `docs/troubleshooting.md` for operator behavior;
- `docs/internal/` for implementation boundaries;
- `docs/integrations/` for external storage/runtime contracts;
- `docs/roadmap/` only for unimplemented work.
Do not describe unimplemented behavior outside `docs/roadmap/`.