Overview of the iPhone app specs (not a work item itself). Written 2026-10-06 from a reading of every built spec and the code behind it. Each spec below is a separate work item on the roadmap.
Why
The site already works well on a phone (mobile.md): a tab bar, swipe rails, compact result rows, and topic pages that fold their deep dives. What a phone browser can't give is what people expect from an app they installed: it opens in under a second on the thing they looked at last, keeps working on a campus tour with one bar of signal, signs in once with Face ID, puts a college's deadline on the lock screen, and shares a college with a tap. Families in decision season use the site daily for a few months; that is exactly the use an app serves better than a browser tab.
The ask is every feature and function of the website, not a subset. The site has about 60 routes: home, Explore with four views, a profile overview plus six topic pages, a compare overview plus seven topic pages, the glossary, the Data page, national trends with six studies, movers, conferences and states, high schools, roadmap, release notes, sign-in, account and household, the student profile, saved lists, following and updates. The app gets all of them.
The three specs
| Spec | What it covers | Complexity |
|---|---|---|
| App API: Screen Documents for the iPhone App | The app API: JSON for every screen, computed by the same lib/ code the pages use, with a citation on every value. Today almost everything the site shows exists only as HTML, so this comes first |
Large |
| The iPhone App | The app itself: native SwiftUI, how it talks to the API and to Supabase Auth, offline behavior, deep links, the design system carried over, accessibility, telemetry, App Store release, and the test plan | Extra large |
| iPhone App: Screen-by-Screen Parity Map | The screen-by-screen parity map: every page and control of the site, what it becomes on iOS, and which API call feeds it, so nothing is dropped by accident | Large |
Decisions in short
Each is argued in The iPhone App.
- Native SwiftUI, not a web view and not React Native. Apple rejects apps that only wrap a site; a native app is the whole point of the ask.
- The app never computes a number. Every figure, percentile, takeaway, standout, and citation comes from the
server, which runs the same
lib/functions the site does. The app renders, navigates, caches, and shares. That keeps the site's rule that every value traces to its source and year, with one implementation. - Server-described screens. The API returns each screen as a list of typed blocks (stat tiles, a funnel, a range bar, a trend line, a table…) from a fixed catalog the app knows how to draw. Content changes on the site reach the app without an App Store release; only a new block kind needs one.
- One API for the app, shared code with the pages.
app/api/app/v1/*returns typed screen documents fromgetData(); the developer API (Data API: The Dataset, History, and Lineage for Developers) stays a separate, keyed product. - Supabase Auth directly from the app (Sign in with Apple, email and password, magic link), and every user-data read and write through the app API with the user's token, so the server-side rules the site already has (age gate, password rules, access logging, geocoding, deadlines) are not written twice.
- The same URLs. Every site URL opens in the app as a universal link, and everything the app shares is a site URL, so a recipient without the app lands on the same page.
Build order
api (read-only endpoints) ─► app shell + screens phase 1 (everything that works signed out)
api (user endpoints) ─► screens phase 2 (sign-in, account, household, student profile, lists, following, updates)
─► phase 3 (what only an app can do: widgets, Spotlight, Shortcuts, push for digests, iPad)
Phase 1 alone is shippable: it is the public site with nothing gated. Phase 2 reaches parity. Phase 3 is listed in The iPhone App and is not part of the parity ask.
Rules carried over from the site
- Cite everything. A value with no citation is a bug; the API test fails on it the way
tests/citation-guards.test.mtsdoes for the pages. - No hard-coded years. Year labels come from the API, which takes them from lineage.
- Public data stays free and signed out. Signing in adds memory and tools, never access to a number (Commercialization: Free, Plus, and Pro).
- Minors. Same age gate (13 and older), no behavioral ads, no replay, no location beyond what the person types (telemetry.md). The App Store age rating follows from that.
- User data lives only in Supabase, behind the same row-level security.