Post-mortem · Geomatics & linear engineering

Base-station network portal

A portal for a GNSS reference-station operator: 54 always-on stations, health and RINEX data for the public, and subscription-gated correction streams with key management behind them.

Book a scope review →All delivery records
Context

The situation.

A GNSS reference-station operator. 54 stations, always on, in two climate zones.

Scope

Public and subscriber-facing portal over a CORS network: station health (receiver temperature, supply voltage, lock status), RINEX availability windows, multipath signature panels per station, and subscription-gated stream access with key management.

Outcome

Operational SLA dashboard for 50+ stations, sub-minute alerting, zero unnoticed outages since go-live.

Stack
Next.jsTimescaleDBGrafana
Topology

Receivers at the 54 CORS stations report health readings, receiver temperature, supply voltage and lock status, into TimescaleDB, where they live as time series next to the RINEX availability windows computed as data files land. Next.js serves both faces of the portal: the public view with station health, availability windows and per-station multipath signature panels, and the subscriber view that manages stream keys and gates access to the correction streams. Grafana reads the same series for operations, so the operator's SLA dashboard and the public status page cannot disagree. A nightly job packs RINEX files and stages them to edge storage; subscribers fetch from the edge rather than from the station network. Alerting on the health series fires within a minute of a threshold crossing, which is where the sub-minute figure in the acceptance record comes from.

Trade-offs
  • Considered: Absorb the 06:00 UTC rover peak with more origin capacity.

    Chose: Stage RINEX files to edge storage and rate-limit stream access by subscription tier.

    Because: The collision is between two predictable workloads, European rovers at dawn and nightly packing, and moving one of them off the origin costs less than provisioning for both.

  • Considered: Let subscribers report decoder breakage after each firmware rollout.

    Chose: A message-set fingerprinter that watches the RTCM stream and flags drift on its own.

    Because: Firmware updates changed the RTCM message set silently about twice a year. Subscribers are the worst possible detector: they pay for the service and find the fault first.

  • Considered: A general relational store with a reporting layer bolted on.

    Chose: TimescaleDB as the primary store.

    Because: Every signal here is a series with retention and windowing needs, and availability windows come from the same timeline as the health readings.

  • Considered: Hide station detail behind the subscription wall.

    Chose: Publish health, availability and multipath signatures publicly and gate only the streams.

    Because: The public pages are what make the portal credible, and the streams are the only part that carries the subscription's value.

Stack rationale

Next.js because the portal is a content surface as much as an application: station pages, availability tables and subscription flows want server rendering and quick loads. TimescaleDB because the queries that matter are all windows over series, and nothing in the system needs anything else. Grafana because operations should not depend on the product UI; both it and the public pages read one set of series. The stack is deliberately unexotic. The hard work sits in the fingerprinter and the delivery strategy; the framework just has to stay boring.

Telemetry

The delivery record carries one measured change and three acceptance outcomes, and nothing else is quoted here. Firmware updates had been changing the RTCM message set roughly twice a year without anyone noticing; the fingerprinter now detects decoder drift before subscribers do. The 06:00 UTC collision between European rover demand and nightly RINEX packing ended when files moved to edge storage behind tier-based rate limits. The acceptance record closes on three items: an operational SLA dashboard covering more than 50 stations, sub-minute alerting, and zero unnoticed outages since go-live. No uptime percentage appears in this write-up because no such figure exists in the record; quoting one would be invented precision.

Section 1

What discovery found

The operator runs 54 reference stations, always on, in two climate zones. Station health existed as receiver console readings, RINEX availability lived in file listings, and multipath was something an engineer diagnosed by hand. Three audiences wanted the same facts: the public wanted to know whether a station is healthy and has data, subscribers wanted their streams and keys, and the operator's own staff wanted to see which station is drifting before subscribers call. The brief was to serve all three from one data plane.

Section 2

The hard problem

Two failure modes dominated. Receiver firmware updates silently changed the RTCM message set, about twice a year, and the first people to notice were paying subscribers. That is the worst alert path a service can have. The second was load: European rovers peak at 06:00 UTC, exactly when nightly RINEX packing saturates the origin, and the two workloads collided on the same machine.

Section 3

The build

The fingerprinter watches the structure of the RTCM stream rather than its content: it fingerprints the message set each station emits and flags any shift, whatever firmware version produced it. Firmware changes show up as structural drift while the data still decodes, so the warning arrives before anyone loses a fix. For load, the fix was to stop the fight over one disk. RINEX files pack nightly and stage to edge storage, subscribers fetch from the edge, and stream access rate-limits by subscription tier so the cheapest plan cannot starve the origin at peak.

Section 4

Verification

The SLA dashboard covers more than 50 stations and doubles as the acceptance surface: sub-minute alerting on station health, and the number that matters most is the outages nobody noticed. That count has been zero since go-live. Uptime percentages are absent because the delivery record does not hold one; the acceptance items above are the whole record, and they are what the operator signed against.

Section 5

Handover

Operations run in Grafana on the same series the public pages read, so what staff see and what a subscriber sees cannot disagree. The fingerprinter and the edge staging both run unattended. Stations keep picking up firmware updates; the system's job is that nobody has to find out from a subscriber.

Have a similar problem?

Fixed scope, senior engineers, staging from week one.

Book a scope review →