Initial commit: CRDC Arrests API demo app
Deploy to Git Pages / build-and-deploy (push) Failing after 19s
Deploy to Git Pages / build-and-deploy (push) Failing after 19s
React + Vite static site demonstrating the CRDC School Arrest Rate API. Features 6 interactive charts comparing observed arrest data against Bayesian model estimates across U.S. school districts, with Civilytics visual identity. - State selector and district search with 'interesting' suggestions (top arrests) - Animated histogram loading grid showing posterior draw progress - Charts: time series, rate by group, district vs national, model comparison quadrants, density proxy, exceedance probability - Static JSON fixture for national rates (no API changes needed) - Dockerfile + docker-compose.yml for self-hosted deployment - GitHub Actions workflow and _config.yml for Git Pages
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
# CRDC Arrests API Demo
|
||||
|
||||
A demonstration web application for the [CRDC School Arrest Rate API](https://crdc-api.civilytics.org/api/v1/), showing Bayesian model comparisons of school-based arrest rates across U.S. districts. Built with React + Vite, deployable as a static site or Docker container.
|
||||
|
||||
## Quick Start (Development)
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm ci
|
||||
|
||||
# Start dev server on localhost:5173
|
||||
npm run dev
|
||||
|
||||
# Build for production
|
||||
npm run build # outputs to dist/
|
||||
npm run preview # serve built files locally
|
||||
```
|
||||
|
||||
## What It Does
|
||||
|
||||
Visitors select a U.S. state, search for a school district (with suggestions of districts that have the most arrests), and see 6 charts comparing observed data against Bayesian model estimates:
|
||||
|
||||
1. **Arrests over time** — raw counts by CRDC wave with per-1k rate labels
|
||||
2. **Rate by student group** — bar chart, most recent year (observed vs. modeled)
|
||||
3. **District vs. national** — highest-rate group compared to the U.S. average
|
||||
4. **Model predictions vs. observed** — four quadrants (one-year/three-year × baseline/covariate)
|
||||
5. **Observed rate vs. model distribution** — ridgeline-style comparison across models
|
||||
6. **Exceedance probability** — P(district > national) per student group
|
||||
|
||||
## Architecture
|
||||
|
||||
### Tech Stack
|
||||
- **React 19** + **Vite** (static site generation, no backend required)
|
||||
- Plain CSS custom properties for styling (matches Civilytics design tokens exactly)
|
||||
- SVG-based charts rendered inline (no D3 or charting library dependencies)
|
||||
- Calls the public read-only API directly from the browser
|
||||
|
||||
### File Structure
|
||||
```
|
||||
crdc-demo/
|
||||
├── index.html # Entry point
|
||||
├── vite.config.mjs # Vite build config
|
||||
├── src/
|
||||
│ ├── main.jsx # React entry
|
||||
│ ├── App.jsx # Main router (state → search → loading → charts)
|
||||
│ ├── hooks/useApi.js # API client with retry/backoff + endpoint wrappers
|
||||
│ ├── components/
|
||||
│ │ ├── StateSelector.jsx # Landing screen — state dropdown/grid
|
||||
│ │ ├── DistrictSearch.jsx # Search + "interesting" district suggestions
|
||||
│ │ ├── LoadingAnimation.jsx # Animated histogram grid during data fetch
|
||||
│ │ └── ChartPanel.jsx # Orchestrates all 6 charts + data fetching
|
||||
│ ├── charts/
|
||||
│ │ ├── ArrestsOverTime.jsx # Chart 1 — line chart by wave
|
||||
│ │ ├── RateByGroupBar.jsx # Chart 2 — bar chart by group
|
||||
│ │ ├── DistrictVsNational.jsx # Chart 3 — comparison vs. national avg
|
||||
│ │ ├── ModelDrawsComparison.jsx # Chart 4 — quadrant model comparison
|
||||
│ │ ├── ObservedRateDensity.jsx # Chart 5 — ridgeline proxy from intervals
|
||||
│ │ └── ExceedanceProbability.jsx # Chart 6 — P(district > nat) per group
|
||||
│ ├── styles/tokens.css # Civilytics design tokens (colors, fonts, spacing)
|
||||
│ └── data/national_rates.json # Static national rates fixture for comparisons
|
||||
├── Dockerfile # Multi-stage build → nginx static server
|
||||
├── docker-compose.yml # Local dev / self-hosted deployment
|
||||
├── _config.yml # Git Pages (self-hosted equivalent) config
|
||||
└── .github/workflows/deploy.yml # CI/CD — builds and uploads artifacts
|
||||
```
|
||||
|
||||
### API Endpoints Used
|
||||
| Endpoint | Purpose | Frequency |
|
||||
|---|---|---|
|
||||
| `/api/v1/models` | List available Bayesian model specs | Once (cached) |
|
||||
| `/api/v1/districts?q=&state=` | District name/geo lookup → LEAID | On keystroke |
|
||||
| `/api/v1/estimates/{leaid}?model=X&year=Y` | Estimates for one district/model/year/group | ~40 calls per district |
|
||||
| `/data/national_rates.json` | Static national rates fixture (committed) | Once per session |
|
||||
|
||||
## Deployment
|
||||
|
||||
### Option A: Git Pages (self-hosted equivalent — recommended)
|
||||
The app is a static site. Upload the `dist/` directory to your self-hosted Git Pages server after building:
|
||||
|
||||
```bash
|
||||
npm run build # produces dist/
|
||||
# Upload dist/ contents to your git-pages host
|
||||
```
|
||||
|
||||
For CI/CD, see `.github/workflows/deploy.yml` which builds and uploads artifacts automatically on push to `main`.
|
||||
|
||||
### Option B: Docker (self-hosted fleet)
|
||||
Build and run the nginx container on your infrastructure (`efron`, `maxwell`, etc.):
|
||||
|
||||
```bash
|
||||
docker compose up -d # builds + serves on localhost:8080
|
||||
|
||||
# Or build manually for your registry:
|
||||
docker buildx build --platform linux/amd64 -t registry.civilytics.org/crdc-demo:latest .
|
||||
docker push registry.civilytics.org/crdc-demo:latest
|
||||
```
|
||||
|
||||
The container is ~5MB (nginx Alpine) and serves static files with immutable cache headers. A `/healthz` endpoint supports container orchestration health checks.
|
||||
|
||||
### Environment Variables
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `VITE_API_BASE` | `https://crdc-api.civilytics.org/api/v1` | Override to point at a staging API (set in Dockerfile build or docker-compose) |
|
||||
|
||||
## Visual Design
|
||||
|
||||
This app follows the Civilytics visual identity as defined in:
|
||||
- `theme/_tokens.scss` — colors, typography, spacing tokens
|
||||
- `social_media_posts.md` — chart patterns from published social media figures
|
||||
- `white_paper.qmd` / `R/paper_figures.R` — white paper figure builders
|
||||
|
||||
Key design decisions:
|
||||
- **Color palette**: Warm paper background (`#FAF7F2`), civic navy text (`#0E1A2B`), ember accent (`#C25311`)
|
||||
- **Data viz colors**: Teal, plum, moss, brass from the supporting palette
|
||||
- **Fonts**: Libre Franklin/Inter for display and body, JetBrains Mono for code
|
||||
- **Chart patterns**: Pointrange comparisons (model vs. observed), ridgeline-style density bars, faceted small multiples
|
||||
|
||||
## Citation & Attribution
|
||||
|
||||
The CRDC School Arrest Rate API: Knowles, J.E., & Miller, H. (2025). *CRDC School Arrest Rate API v1*. Civilytics Consulting. https://crdc-api.civilytics.org/api/v1/
|
||||
|
||||
Data source: US Department of Education, Office for Civil Rights. Civil Rights Data Collection (2021-22).
|
||||
|
||||
This research was supported by a grant from the American Educational Research Association which receives funds for its "AERA Grants Program" from the National Science Foundation under NSF award NSF-DRL #1749275. Opinions reflect those of the author and do not necessarily reflect those AERA or NSF.
|
||||
Reference in New Issue
Block a user