Re-scope note (2026-06-11): Original issue asked to add the Eastern Idaho Info Exchange. After /grill-me design session, this issue is re-scoped to deliver the platform-wide info-exchange support with EWYAIX as the first concrete onboarding (they're already registered with NAC and have a name + domain). Eastern Idaho onboarding is tracked in #1111 and is a one-line entry once their group is named.
Problem
We need to support "info exchange" centers on the platform. These centers that don't issue avalanche forecasts but do publish observations and host weather stations. The NAC API already models these (EWYAIX, SOAIX) but our codebase excludes them due to schema strictness and a "every tenant is a forecasting center" assumption baked into provisioning and routing.
The first concrete onboarding target is Eastern Wyoming Avalanche Info Exchange (EWYAIX, ewyoavalanche.org). The platform work here also unblocks #1111 (Eastern Idaho) the day their group is named.
Goals
- Treat info exchanges as a regular tenant flavor — no new entity type, no schema discriminator, no separate code path.
- Drive forecast / weather / stations / observations visibility from NAC's
platforms flags (already correctly populated for info exchanges).
- Seed
EWYAIX as a real tenant in our DB so we can verify the platform changes end-to-end against real NAC data.
Non-Goals (explicitly out of scope for this issue)
Approach
1. Tenant identity uses NAC platform flags, not a local discriminator
There is no kind field added to the Tenants collection. "Is this an info exchange" is identical to !platforms.forecasts && platforms.obs, which is also the operational definition of an info exchange (they don't forecast; they do publish obs).
2. Schema relaxation in src/services/nac/types/schemas.ts
avalancheCenterSchema currently rejects EWYAIX because:
| Field |
EWYAIX returns |
Change |
city |
null |
Make nullable |
config |
null |
Make nullable. No code reads metadata.config.* directly, so the inner schema is untouched. |
type |
\"other\" |
Add Other = 'other' to the AvalancheCenterType enum |
Sanity-check: this should now also parse SOAIX (which was excluded for the same reasons). Worth a fixture test against both centers.
3. Route-level gating on platform flags
- Homepage route (
src/app/(frontend)/[center]/page.tsx) unconditionally renders <NACWidget widget=\"warnings\" />. Gate on platforms.warnings so it doesn't render empty for info exchanges. (Also a correctness win for any future center without warnings.)
- The danger map widget stays as-is — info-exchange zones render as gray "no rating" polygons, which matches what EWYAIX shows today.
4. Provisioning changes in src/collections/Tenants/endpoints/provisionTenant.ts
BUILT_IN_PAGES: gate the "Weather Stations" entry on platforms.stations instead of including it unconditionally. EWYAIX has stations: true, so this is a no-op for them, but it's correctness for any future info exchange without stations.
resolveBuiltInPages: when platforms.forecasts === false, skip the AFP zones fetch entirely and produce zero forecast pages. Today the no-zones fallback creates a stale "All Forecasts" page; that fallback should also be gated on platforms.forecasts.
PAGES_TO_PROVISION stays as today for forecasting centers. For info exchanges (platforms.forecasts === false), provision a reduced set: About Us, Donate / Membership, Volunteer. (Other pages can be added by admins as needed.)
- HomePages provisioning: when
platforms.forecasts === false:
highlightedContent columns use info-exchange copy (drop "avalanche forecasts, mountain weather conditions" — phrase as "the latest avalanche observations and safety information from across our region").
layout contains a single observationsWidget block (see §5) instead of the EventList block.
5. New ObservationsWidget block
- Slug:
observationsWidget. Lives at src/blocks/ObservationsWidget/.
- No fields. The block renders the same content as the
/observations page: heading ("Observations"), Submit Observation button, <ObservationsDisclaimer />, <NACWidget widget=\"observations\" />.
- Add to
src/blocks/RenderBlocks.tsx.
- HomePages collection (
layout field) gains it via the existing blocks array.
- Generate types after the field is added.
6. Add EWYAIX to AVALANCHE_CENTERS
In src/utilities/tenancy/avalancheCenters.ts:
```ts
ewyaix: {
name: 'Eastern Wyoming Avalanche Info Exchange',
customDomain: 'ewyoavalanche.org',
},
```
Comment in the file should be updated — EWYAIX is no longer "excluded due to no config object"; it's now supported.
Note: customDomain is canonical/configurational. Adding the entry does not flip DNS — that's the work tracked in #1110.
7. Seed the EWYAIX tenant
Run provisionTenant for ewyaix against prod (and as part of pnpm seed for local dev). Smoke-verify:
- Homepage renders without the forecasts/weather tabs in nav.
- Homepage layout shows the observations widget.
/observations, /observations/submit, /weather/stations/map work.
/forecasts/avalanche, /weather/forecast 404 (existing platform-flag gate handles this).
- About Us, Donate / Membership, Volunteer pages exist in the admin Pages list.
Migrations
- One Payload migration for the new
observationsWidget block being available on HomePages. pnpm payload migrate:create add_observations_widget_block.
- No migration needed for the schema relaxation (it's runtime parsing, not DB schema).
Risks & mitigations
- Schema relaxation regresses forecasting tenants: mitigate with a fixture test parsing both NWAC (full data) and EWYAIX (nulls) responses.
- Provisioning over-creates for info exchanges: the gating is a single
platforms.forecasts branch — easy to unit-test on resolveBuiltInPages.
obs_view_url / obs_form_url in NAC widget config: verified unused by our integration. NWAC's value is a hash-routed URL and NWAC works fine. No action needed.
Follow-ups (tracked separately)
Problem
We need to support "info exchange" centers on the platform. These centers that don't issue avalanche forecasts but do publish observations and host weather stations. The NAC API already models these (EWYAIX, SOAIX) but our codebase excludes them due to schema strictness and a "every tenant is a forecasting center" assumption baked into provisioning and routing.
The first concrete onboarding target is Eastern Wyoming Avalanche Info Exchange (EWYAIX,
ewyoavalanche.org). The platform work here also unblocks #1111 (Eastern Idaho) the day their group is named.Goals
platformsflags (already correctly populated for info exchanges).EWYAIXas a real tenant in our DB so we can verify the platform changes end-to-end against real NAC data.Non-Goals (explicitly out of scope for this issue)
ewyoavalanche.org— generic DNS-flip work that uses the same playbook as any other tenant launch. Tracked in EWY production cutover to NWAC platform #1110, gated on EWY's consent.NACWidgetblock parameterized by widget type — YAGNI for now. We ship a single-purposeObservationsWidgetblock; a generic refactor lands its own issue if we need more widget blocks later.Approach
1. Tenant identity uses NAC platform flags, not a local discriminator
There is no
kindfield added to theTenantscollection. "Is this an info exchange" is identical to!platforms.forecasts && platforms.obs, which is also the operational definition of an info exchange (they don't forecast; they do publish obs).2. Schema relaxation in
src/services/nac/types/schemas.tsavalancheCenterSchemacurrently rejects EWYAIX because:citynullconfignullmetadata.config.*directly, so the inner schema is untouched.type\"other\"Other = 'other'to theAvalancheCenterTypeenumSanity-check: this should now also parse SOAIX (which was excluded for the same reasons). Worth a fixture test against both centers.
3. Route-level gating on platform flags
src/app/(frontend)/[center]/page.tsx) unconditionally renders<NACWidget widget=\"warnings\" />. Gate onplatforms.warningsso it doesn't render empty for info exchanges. (Also a correctness win for any future center without warnings.)4. Provisioning changes in
src/collections/Tenants/endpoints/provisionTenant.tsBUILT_IN_PAGES: gate the "Weather Stations" entry onplatforms.stationsinstead of including it unconditionally. EWYAIX hasstations: true, so this is a no-op for them, but it's correctness for any future info exchange without stations.resolveBuiltInPages: whenplatforms.forecasts === false, skip the AFP zones fetch entirely and produce zero forecast pages. Today the no-zones fallback creates a stale "All Forecasts" page; that fallback should also be gated onplatforms.forecasts.PAGES_TO_PROVISIONstays as today for forecasting centers. For info exchanges (platforms.forecasts === false), provision a reduced set: About Us, Donate / Membership, Volunteer. (Other pages can be added by admins as needed.)platforms.forecasts === false:highlightedContentcolumns use info-exchange copy (drop "avalanche forecasts, mountain weather conditions" — phrase as "the latest avalanche observations and safety information from across our region").layoutcontains a singleobservationsWidgetblock (see §5) instead of the EventList block.5. New
ObservationsWidgetblockobservationsWidget. Lives atsrc/blocks/ObservationsWidget/./observationspage: heading ("Observations"), Submit Observation button,<ObservationsDisclaimer />,<NACWidget widget=\"observations\" />.src/blocks/RenderBlocks.tsx.layoutfield) gains it via the existing blocks array.6. Add EWYAIX to
AVALANCHE_CENTERSIn
src/utilities/tenancy/avalancheCenters.ts:```ts
ewyaix: {
name: 'Eastern Wyoming Avalanche Info Exchange',
customDomain: 'ewyoavalanche.org',
},
```
Comment in the file should be updated — EWYAIX is no longer "excluded due to no config object"; it's now supported.
Note:
customDomainis canonical/configurational. Adding the entry does not flip DNS — that's the work tracked in #1110.7. Seed the EWYAIX tenant
Run
provisionTenantforewyaixagainst prod (and as part ofpnpm seedfor local dev). Smoke-verify:/observations,/observations/submit,/weather/stations/mapwork./forecasts/avalanche,/weather/forecast404 (existing platform-flag gate handles this).Migrations
observationsWidgetblock being available on HomePages.pnpm payload migrate:create add_observations_widget_block.Risks & mitigations
platforms.forecastsbranch — easy to unit-test onresolveBuiltInPages.obs_view_url/obs_form_urlin NAC widget config: verified unused by our integration. NWAC's value is a hash-routed URL and NWAC works fine. No action needed.Follow-ups (tracked separately)
ewyoavalanche.orgDNS to platform).