Document development workflow and internals
This commit is contained in:
118
docs/internal/postgres-sink.md
Normal file
118
docs/internal/postgres-sink.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Postgres Sink Internals
|
||||
|
||||
## Purpose
|
||||
|
||||
`internal/sinks/postgres` defines weatherfeeder's canonical-event-to-Postgres
|
||||
mapping. It supplies a schema definition and mapper to feedkit's generic
|
||||
Postgres sink.
|
||||
|
||||
The consumer-facing table contract is
|
||||
[`docs/integrations/postgres.md`](../integrations/postgres.md). This document
|
||||
describes the internal ownership boundary.
|
||||
|
||||
## Inputs And Outputs
|
||||
|
||||
Inputs are canonical feed events. The mapper currently handles these schemas:
|
||||
|
||||
- `weather.observation.v1`
|
||||
- `weather.forecast.v1`
|
||||
- `weather.forecast_discussion.v1`
|
||||
- `weather.weather_story.v1`
|
||||
- `weather.alert.v1`
|
||||
|
||||
Outputs are feedkit `PostgresWrite` values for weatherfeeder-owned tables.
|
||||
Unsupported schemas produce no writes and no error.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Weatherfeeder owns table definitions in `schema.go`.
|
||||
- Weatherfeeder owns canonical payload mapping in `map.go`.
|
||||
- Feedkit owns database opening, table and index creation, transactions,
|
||||
inserts, context-aware consumption, and prune execution.
|
||||
- Postgres mapping consumes canonical events only. It should not understand raw
|
||||
provider schemas.
|
||||
|
||||
## Config Fields Used
|
||||
|
||||
Weatherfeeder registers the `postgres` sink by passing `PostgresSchema()` to
|
||||
feedkit. Feedkit parses sink params:
|
||||
|
||||
- `uri`
|
||||
- `username`
|
||||
- `password`
|
||||
- `prune`, optional duration
|
||||
|
||||
Weatherfeeder-owned mapper code does not read config directly.
|
||||
|
||||
## External Adapters Used
|
||||
|
||||
The runtime registers the sink with:
|
||||
|
||||
```go
|
||||
sinkReg.Register("postgres", fksinks.PostgresFactory(wfpgsink.PostgresSchema()))
|
||||
```
|
||||
|
||||
Feedkit validates events at the sink boundary, calls the weatherfeeder mapper,
|
||||
validates writes against the compiled schema, inserts rows in a transaction, and
|
||||
optionally prunes rows older than the configured window.
|
||||
|
||||
## State
|
||||
|
||||
The mapper is stateless. Durable state is stored in Postgres through feedkit's
|
||||
sink implementation.
|
||||
|
||||
## Mapping Rules
|
||||
|
||||
Parent rows preserve event envelope fields where the table supports them:
|
||||
|
||||
- `event_id`
|
||||
- `event_kind`
|
||||
- `event_source`
|
||||
- `event_schema`
|
||||
- `event_emitted_at`
|
||||
- `event_effective_at`
|
||||
|
||||
Child rows use positional indexes to preserve canonical array order:
|
||||
|
||||
- `weather_index`
|
||||
- `period_index`
|
||||
- `message_index`
|
||||
- `story_index`
|
||||
- `alert_index`
|
||||
- `reference_index`
|
||||
|
||||
Required canonical fields are validated before writes are returned:
|
||||
|
||||
- observations require `timestamp`;
|
||||
- forecasts require `issuedAt` and `product`, and each period requires
|
||||
`startTime` and `endTime`;
|
||||
- forecast discussions require `issuedAt` and `product`;
|
||||
- weather story runs require `asOf`, and each story requires `startTime`,
|
||||
`endTime`, and `updatedAt`;
|
||||
- alert runs require `asOf`, and each alert requires `id`.
|
||||
|
||||
Nullable canonical values are converted to SQL nulls by mapper helpers.
|
||||
Observation present-weather raw values are stored as compact JSON text.
|
||||
|
||||
## Failure Behavior
|
||||
|
||||
Payload decode failures, missing required fields, invalid compact JSON values,
|
||||
or schema/write mismatches return errors to feedkit's sink. Feedkit rolls back
|
||||
the transaction when a write fails.
|
||||
|
||||
Unsupported canonical schemas are ignored by this mapper so other routed events
|
||||
can use different sinks without Postgres-specific failures.
|
||||
|
||||
## Tests To Inspect
|
||||
|
||||
- `internal/sinks/postgres/schema_test.go`
|
||||
- `internal/sinks/postgres/map_test.go`
|
||||
- feedkit Postgres sink tests when changing generic sink behavior assumptions
|
||||
|
||||
## Invariants
|
||||
|
||||
- Persist only canonical schemas.
|
||||
- Preserve event envelope fields in parent rows.
|
||||
- Preserve array order with child positional indexes.
|
||||
- Validate required fields before writing.
|
||||
- Keep table-contract docs synchronized with schema and mapper changes.
|
||||
Reference in New Issue
Block a user