A demo that updates itself: PEGELONLINE
What runs
The hourly Airflow DAG pegelonline_hourly in stardelt-demos/dags/pegelonline_hourly.py fetches the German waterway gauge API (PEGELONLINE, public JSON, no key). Rows are appended with pyiceberg to the Iceberg table shared.bronze.pegelonline_measurements, partitioned by day on measured_at.
The platform's own warehouse is not used: the DAG overrides the pyiceberg warehouse property to the shared catalog.
Schema (15 columns, in order):
station_uuidstation_numberstation_namewateragencykmlatitudelongitudetimeseriesunitmeasured_atmeasurement_valuestate_mnw_mhwstate_nsw_hswingested_at
Enable it
The DAG ships paused (Airflow's default for a new DAG), so nothing is written until it is turned on.
For a platform installed from this repository, unpause it in the scheduler:
kubectl -n stardelt exec deploy/airflow-scheduler -c scheduler -- \
airflow dags unpause pegelonline_hourly
You can do the same in the Airflow UI at the platform's Airflow host.
Check it
List the DAG runs in the scheduler:
kubectl -n stardelt exec deploy/airflow-scheduler -c scheduler -- \
airflow dags list-runs pegelonline_hourly -o plain
Each run appears as a row; state reaches success when the data has landed.
In Nova's SQL editor, check the table:
SELECT count(*) AS rows, max(measured_at) AS newest, max(ingested_at) AS landed
FROM shared.bronze.pegelonline_measurements;
See it change
The schedule is 7 * * * * (seven minutes past every hour), so newest advances once an hour and landed is the run's own time.
For the modelling steps onward, see From source to dashboard.
The same rows on the bus
The DAG also publishes each fetched row to the bus on the topic
pegelonline.measurements. A StreamApp reads that topic and writes
mobility.bronze.pegelonline_stream, merging on (station_uuid, timeseries, measured_at).
The example lives in stardelt-demos/examples/pegelonline/:
streamapp.yaml— theStreamApp(topic in, Iceberg table out,ownerGroup: mobility-analytics);sink.sql— the target table, with the same 15 columns and both timestamps;README.md— the two apply commands.
Apply the table first, then the stream:
kubectl -n stardelt apply -f examples/pegelonline/sink.sql # or run it in Nova's SQL editor
kubectl -n stardelt apply -f examples/pegelonline/streamapp.yaml
Check that rows arrive in Nova's SQL editor:
SELECT count(*) AS rows, max(measured_at) AS newest
FROM mobility.bronze.pegelonline_stream;
The stream starts from the topic's earliest offset (startingOffsets: earliest), so the first
run reads the whole retained topic. Follow it on the Streams page; stopping it
keeps the checkpoint.
Why bronze only
The demo stops at bronze so the streaming path and the hourly path can be compared row for row. Modelling onward is the source-to-dashboard guide's job.