An R analysis script turned into an authenticated Plumber API, an LLM-powered summary API built on top of it, and two React front ends (web + mobile) that consume both.
From Plumbing Your Way to React: Using Plumber APIs to Evolve Shiny Systems, useR!2026.
- Docker + Docker Compose: for the one-step setup
- R (tested on 4.5.0) and Node.js (tested on 22.x): only needed for the local, per-project setup
- An OpenRouter API key: only needed to get real text out of
summary-api; everything else works without one
cp .env.example .envOpen .env and set OPENROUTER_API_KEY. Then:
docker compose up --build- Web app: http://localhost:5173
- Mobile app: http://localhost:5174
- flights-api docs: http://localhost:8001/__docs__/
- summary-api: http://localhost:8002
The first build restores each R project's renv.lock and compiles any packages without a prebuilt binary, so it takes a while the first time. Later builds reuse Docker's layer cache and are fast unless a lockfile changes.
To stop everything:
docker compose downRscript analysis-script/analysis.Rcd flights-api
Rscript -e "renv::restore()"
PORT=8001 FLIGHTS_API_KEY=changeme-demo-key Rscript plumber.Rcd summary-api
Rscript -e "renv::restore()"
PORT=8002 FLIGHTS_API_URL=http://localhost:8001 FLIGHTS_API_KEY=changeme-demo-key \
OPENROUTER_API_KEY=sk-or-... Rscript plumber.Rcd web-app
FLIGHTS_API_KEY=changeme-demo-key npm install && npm run devcd mobile-app
FLIGHTS_API_KEY=changeme-demo-key npm install && npm run dev -- --port 5174FLIGHTS_API_KEY is deliberately not called API_KEY; R's .Renviron loading takes precedence over inline/shell-exported environment variables, so a generic name can silently collide with something unrelated already set on your machine.
analysis-script: A plain R script using dplyr, tidyr, stringr, purrr, lubridate, and ggplot2 over the nycflights13 dataset. Defines the functions everything else in this repo is built on: carrier delays, top routes, monthly trends, and airport traffic.
flights-api: The real backend: Plumber, renv, and Docker, with a static API key checked on every request. Structured with routers, middleware, hooks, and an OpenAPI spec patch. Every other service in this repo talks to this one.
summary-api: A second Plumber API that calls flights-api over HTTP and hands the JSON to an LLM through ellmer and OpenRouter to generate a plain-English summary.
web-app: A React (Vite) app: animated stat cards, an interactive route map plotted from real airport coordinates, a carrier delay chart, and AI-generated summaries pulled from summary-api.
mobile-app: A React (Vite) app styled for mobile: the same data as a set of swipeable, single-stat screens.
- Docker / Docker Compose
- R / tidyverse
- Plumber
- renv
- ellmer
- OpenRouter
- nycflights13
- React
- Vite
- recharts
flights-api's router/middleware/hooks structure and OpenAPI patch are adapted from Gotfrid/plumber-cookbook.
