AdminAnalytics/README.md
emfurst 30b89e2fc4 Correct IRS 990 filer description: UD files its own 990
The docs said the UD Foundation was the 990 source. The configured EINs
are UD itself (all Schedule J rows) and the UD Research Foundation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X9jG4CUFcH6n4vFvgtwndY
2026-10-17 12:20:45 -04:00

6.4 KiB

Admin Analytics

University of Delaware administrative cost benchmarking using public data (IRS 990, IPEDS, EADA, BLS CPI-U). Ingests data into a local DuckDB database and serves an interactive Dash dashboard for analysis.

Scope

This project is currently scoped to the University of Delaware as a single institution. It tracks:

  • Executive compensation from IRS 990 Schedule J filings by the University of Delaware (EIN 516000297) and UD Research Foundation (EIN 516017306)
  • Administrative cost ratios from IPEDS finance surveys (expenses by function, staffing levels, enrollment)
  • Endowment performance and philanthropic giving from IPEDS F2 (FASB) financial data
  • Intercollegiate athletics spending from Equity in Athletics Disclosure Act (EADA) filings, set against university-wide spending and athletics leadership compensation
  • Administrative headcount via web scraping, currently focused on the College of Engineering line management (COE Central, department offices) and the Provost's Office

Changing the target institution

The institution scope is controlled by constants in src/admin_analytics/config.py:

  • UD_UNITID = 130943 -- IPEDS institution identifier. Change this to target a different institution. Look up UNITIDs at the IPEDS Data Center.
  • UD_EINS = [516000297, 516017306] -- IRS Employer Identification Numbers for 990 filings. Update these to the EINs of the target institution's nonprofit entities.

All IPEDS and EADA loaders accept a unitid_filter parameter (EADA is keyed by the same UNITID). The scraper URLs in src/admin_analytics/scraper/directory.py are UD-specific and would need to be updated for a different institution.

Multi-institution comparisons (AAU peers, Carnegie peers) are planned for a future phase.

Prerequisites

  • Python 3.11+
  • uv package manager
  • Playwright browsers (only needed for the scrape command)

Setup

# Clone and install
git clone <repo-url>
cd AdminAnalytics
uv sync

# Install Playwright browsers (optional, only for scraping)
uv run playwright install chromium

Ingesting Data

Load data from public sources into the local DuckDB database (data/admin_analytics.duckdb).

# Ingest everything (IPEDS + IRS 990 + CPI + EADA + scraper)
uv run admin-analytics ingest all

# Or ingest individual sources
uv run admin-analytics ingest ipeds --year-range 2005-2024
uv run admin-analytics ingest irs990 --year-range 2019-2025
uv run admin-analytics ingest cpi
uv run admin-analytics ingest eada --year-range 2007-2025
uv run admin-analytics ingest scrape

Use --force on any command to re-download files that already exist locally.

Downloaded files are stored in data/raw/ (gitignored).

Launching the Dashboard

uv run admin-analytics dashboard

Opens at http://localhost:8050. Use --port to change the port, or --host 0.0.0.0 for network access (e.g. over Tailscale).

For a production server, run it under gunicorn instead of Dash's development server:

uv run gunicorn -w 2 -b 127.0.0.1:8050 admin_analytics.dashboard.wsgi:server

Each worker opens its own read-only DuckDB connection. Don't use --preload, which would share one connection across forked workers.

The dashboard must be restarted to pick up newly ingested data (DuckDB opens in read-only mode to avoid lock conflicts).

The dashboard has eight tabs:

  • Executive Compensation -- top earners from IRS 990 Schedule J, President and top-10 CAGR, trends by role, compensation breakdown by component, growth vs CPI-U (tax years 2015-2024)
  • Admin Cost Overview -- admin cost ratios, expense breakdown by function, cost per student, admin-to-faculty ratio (IPEDS data, 2005-2024)
  • Staffing & Enrollment -- staff composition, student-to-staff ratios, management vs faculty vs enrollment growth (indexed)
  • Endowment -- endowment value trends, CAGR, investment return rate, CIO compensation vs endowment growth (IPEDS F2)
  • Philanthropy -- total private gifts and grants, gift allocation, President and VP Development compensation growth vs fundraising (IPEDS F2 and IRS 990)
  • Athletics -- athletics expenses by football, basketball, other sports, and spending not allocated by sport (FY2007-2025, FBS transition marked); growth vs university and instruction spending; cost per full-time undergraduate; share of university expenses; head coach and athletic director compensation (EADA, IPEDS, IRS 990)
  • Current Headcount -- scraped UD staff directory data with overhead/non-overhead classification by unit
  • About -- data sources, methodology, and limitations

Validating Data

Check row counts, NULL rates, year coverage, and cross-source consistency:

uv run admin-analytics validate

Running Tests

uv sync --group dev
uv run pytest

Project Structure

src/admin_analytics/
    cli.py              # CLI entry point (typer)
    config.py           # Constants (UD identifiers, URLs, paths)
    db/                 # DuckDB schema and connection
    ipeds/              # IPEDS download, parsing, loading
    irs990/             # IRS 990 XML download, parsing, title normalization
    bls/                # BLS CPI-U download and loading
    eada/               # EADA athletics download and loading
    scraper/            # UD staff directory scraper and classifier
    dashboard/          # Dash app, queries, page layouts
    validation.py       # Data validation queries
data/raw/               # Downloaded files (gitignored)
docs/data_dictionary.md # Schema documentation
tests/                  # pytest test suite

Data Sources

Source What it provides Years
IPEDS Institutional directory, expenses by function, staffing, enrollment 2005-2024
IRS 990 e-file Filings by the University of Delaware and UD Research Foundation; executive compensation (Schedule J, from UD's own filings) Tax years 2015-2025
EADA Athletics expenses by sport, participants, coaching salaries, full-time undergraduate enrollment FY2007-2025 (academic years 2006-07 to 2024-25)
BLS CPI-U Consumer Price Index for inflation adjustment Full history
UD staff directories Admin office headcounts and overhead classification Current snapshot