Fabric Apps / Flood Insights

Flood Insights

Flood risk and gauge levels on a 3D terrain twin, with an IBCS Power BI report.

Reactthree.jsRayfinVite
Recorded from the app running locally.

A reconstruction of the Ahr valley flood of 14–15 July 2021, as an interactive 3D data twin.

⚠️ Demonstration and training purposes only. Not a real risk assessment and not a basis for insurance or financing decisions.

Flood Insights

flood-insights demo


What it does

On the night of 14 to 15 July 2021, 136 people died in Rhineland-Palatinate, most of them along the Ahr. This application reconstructs what happened entirely from publicly available data, to answer three questions: what was known, what was missing, and what would be possible today?

Flood Insights is a Microsoft Fabric App. It renders 24.6 km of the Ahr valley in 3D from official 1 m terrain and LoD2 building data, replays the flood along a scrubbable timeline driven by a stage-discharge rating built from real cross-sections, and closes by letting the user ask what would have helped? — more warning time, wider natural-hazard insurance cover, flood-adapted rebuilding — and watch the numbers move.

The reconstruction is checked, not asserted. The simulated extent is scored against the Copernicus EMSR517 flood trace at 4 m resolution and reports IoU 0.508 — good enough to reason about, not good enough to pretend it is truth. That number is shown inside the app, next to the map, including when it is unflattering.

It is not a disaster experience and not a sales prop. The framing, content and tone rules are binding and are written down alongside the project plan. They outrank every other part of this repository.

Getting started

You need Node 20+, Python 3.11+ and about 250 MB of download budget for the geodata.

npm install
pip install -r tools/requirements.txt

npm run data:build     # downloads and derives terrain, buildings and flood extent
npm run dev            # http://localhost:5173

data:build is the step people skip. Without it the app still starts, shows the remembrance screen, and then tells you exactly which command you are missing instead of failing with a blank canvas — but there is no twin to look at until it has run. It is safe to re-run and skips anything already downloaded.

Deploy to Fabric with Rayfin:

npx rayfin up --tenant <tenant-guid> --workspace "Rayfin Apps" --dry-run   # preview first
npx rayfin up --tenant <tenant-guid> --workspace "Rayfin Apps"

Then smoke-test the deployment itself:

FLUT_DEPLOYED_URL=https://<host>.webapp.fabricapps.net npx playwright test deployed

Project structure

config/aoi/     area-of-interest definitions — the app is parameterised, not hard-coded
docs/           research notes, source documents, licence evidence
tools/geodata/  ingestion and preprocessing (DGM1, LoD2, EMSR517, OSM, gauges) + pipeline.py
tools/fabric/   lakehouse, semantic model and Real-Time Intelligence setup
src/            React + Three.js front end
  data/         the fact register — every figure with its source
  twin3d/       terrain, water, buildings, hydrograph, what-if engine
  components/   remembrance screen, shell, validation and Act IV panels
  i18n/         de.json / en.json — all user-facing strings
public/terrain/ generated heightmap, flow field and building mesh (built, not committed)
rayfin/         Fabric App deployment config (.env and .deployments.json are gitignored)
e2e/            Playwright specs, including the guardrail tests

Scripts

Script What it does
npm run dev Vite dev server on port 5173
npm run build Type-check and build to dist/
npm run lint ESLint across the project
npm test Vitest unit tests — the what-if engine and the fact register
npm run test:e2e Playwright, 27 specs including the §2 guardrail rules
npm run data:build The full geodata pipeline; --list, --only and --skip are supported
npm run gauges:fetch Live Ahr gauge readings from the LfU Rheinland-Pfalz open API
npm run fabric:setup Create the lakehouse, load the tables, build the semantic model

Three conventions worth knowing before you change anything

The area of interest is configuration, not code. No coordinate, village name or gauge id belongs in a source file. It all lives in config/aoi/ahrtal-2021.json. Ahrtal 2021 is the first instance of this app, not the app itself.

An unsourced figure must look broken. Every number shown to a user is declared in src/data/facts.ts with its source. A fact with source: null renders through SourcedFigure as a loud defect marker, not as a clean number. That is deliberate: PLAN §4.8 says an unsourced claim does not ship, and a visible defect enforces that far better than a comment does. The death toll was such a fact until the final report of the Landtag's committee of inquiry was cited, and correcting it changed the number and the area it describes: the app claimed 134 deaths in the Landkreis Ahrweiler, while the inquiry states 136 for Rheinland-Pfalz and gives no district figure at all. isReleaseReady() now returns true, and a unit test pins both the value and its issuer so the scope cannot drift back.

Observed damage is quoted, never inferred. Real buildings carry damage grades only where Copernicus EMSR517 graded them — attributed to Copernicus, matched by point-in-footprint containment rather than proximity, never merged with modelled output, and never shown next to a monetary figure. The rules and the reasoning are in PLAN §2.2. An earlier nearest-neighbour join was thrown away when it turned out the median distance to a graded point was 255 m: close enough to label the wrong house.

Data

Every layer in this app is public data under an open licence. That is not a convenience — it is the point: the data existed in 2021, it just was not connected.

Full source list, licences and the mandatory attribution strings are in NOTICE.md. The attribution is not decorative; it must travel with any redistribution or public deployment.

Related

  • Base app: digital-twin-fabric-app (wind-farm 3D twin — SceneEngine, Foundry voice/chat, tour, Rayfin deploy)
  • Data pipeline patterns: DWD-Wetter-Insights

Fabric architecture

npx rayfin up provisions:

  • Entra sign-in (Fabric identity)
  • Static web app

Credits

Third-party data and licences: NOTICE.md. Licence: LICENSE. Copyright (c) Microsoft Corporation..