data.nysais.org — Site Plan
Purpose
Regional analytics platform combining NYSAIS member school data (from NAIS DASL) with US Census demographics. Aggregate views only — never exposes single-school data.
Audiences
v1 (now): NYSAIS staff only, Google OAuth @nysais.org. Same auth pattern as PL, sponsors, staff-site, DASL Tracker.
v2 (later): Member schools, magic-link auth (same pattern as jobfair.nysais.org). Each school sees their region's aggregate + census data centered on their ZIP.
Core design rule
Never expose single-school data. All school-side aggregates must pass a k-anonymity threshold: minimum 5 schools per rendered cell. Enforced in the query layer, not the UI, so it's a structural guarantee rather than template discipline.
Regions (6, covering all 62 NY counties)
| Region | County count | Notes |
|---|---|---|
| Western + Central NY | 33 | Buffalo through Utica/Binghamton belt. Delaware County included (no schools there per user). |
| Capital District + Lake Placid | 13 | Capital 4 (Albany, Rensselaer, Saratoga, Schenectady) + Adirondacks incl. Essex/Lake Placid |
| Hudson Valley | 8 | Columbia, Greene, Ulster, Dutchess, Sullivan, Orange, Putnam, Rockland |
| Westchester | 1 | Own region for now |
| NYC | 5 | With borough drilldown where school count ≥ 5 (likely Manhattan + Brooklyn; TBD from DASL) |
| Long Island | 2 | Nassau + Suffolk |
NYC also drills to NTA-level neighborhoods for the census view (UWS, UES, Village, etc.) using NYC DCP's Neighborhood Tabulation Areas.
Census pipeline (prototype complete)
Standalone Node script fetches ACS 5-year 2022 metrics for a geography and returns population-weighted aggregates. In-tree at server/lib/census/.
Modes:
zip <zip> [radius_mi]— school's ZIP + 5/10/15/25 mi radiusborough <manhattan|bronx|brooklyn|queens|staten_island>region <region_key>neighborhood <alias>— friendly NYC neighborhood names (uws, ues, village, ...)nta <NTACode>— raw NYC NTA (~200 available)
Metrics pulled: population, K-12 age (5-17), households with children, education (bachelor's+), race, Hispanic ethnicity, language spoken at home, owner-occupancy, median household income, median home value.
Disk cache per county + variable set — 20× speedup on warm hits. Whole-NY cache is ~4 MB.
DASL integration (blocked on API access)
DASL API access being pitched to NAIS (see NAIS Proposal). Same pipeline will feed:
- DASL Tracker (per-school, staff-only — already shipped)
- data.nysais.org (aggregated with n≥5, this site)
One ingest, two consumers.
Currently the DASL Tracker uses manual XLSX upload. API access replaces that step.
Stack
Matches sister apps for consistency:
- Node.js 20, Express 5
- PostgreSQL 16 (
data_db/data_db_user) - Knex migrations
- React (Vite) + Zustand — coming in v0.2
- Google OAuth (@nysais.org) for staff — coming when auth is wired
- PM2 under
webappuser - Nginx + Let's Encrypt
Environment
- Staging droplet: nysais-staging (this box), port 3005,
staging.data.nysais.org - Prod droplet: prod-apps (not deployed yet), will be
data.nysais.orgwhen ready
Repo
nysais/data-site on GitHub (to be created when we're ready to push).
Deploy pattern matches sister apps: PR-based dev, tag-and-workflow-dispatch for prod, migrations auto-run in prod deploy script (following pl-site pattern).
Open items
- DASL API access (pending NAIS decision)
- Google OAuth credentials for this site (need to create in GCP console)
- CNAME for staging.data.nysais.org (Andrew handling)
- Confirm NYC borough drilldown list (need DASL member counts by borough)