# Platform Architecture

## Purpose

This project begins as the production engine for NW AL Scanner News and is being shaped into a reusable live-information platform for digital newsrooms, weather operations, emergency managers, scanner pages, and other local media entities.

NW AL Scanner News is the first production tenant and proving ground. The platform itself must not hardcode Shoals-specific branding, geography, feeds, or wording inside reusable renderers.

## Core Layers

1. **Providers** ingest external or manual data.
2. **Normalization** converts source-specific data into internal event objects.
3. **Rules and safety** handle priority, privacy, expiration, confidence, and publishing eligibility.
4. **Products** render events into broadcast-ready visuals.
5. **Playlist** schedules normal products and handles interruptions.
6. **Outputs** publish to OBS, social graphics, websites, push systems, and archives.

```text
DATA SOURCES
NWS · Forecast · Radar · CAD · Outages · Traffic · Manual Input
                         ↓
NORMALIZATION LAYER
                         ↓
RULES + SAFETY
                         ↓
PRODUCT ENGINE
                         ↓
PLAYLIST ENGINE
                         ↓
OUTPUTS
OBS · Social · Website · Push · Archive
```

## Universal Event Object

All incoming information should normalize to a shared shape.

```json
{
  "id": "evt_20260711_001",
  "tenantId": "nwals",
  "category": "weather_alert",
  "type": "Tornado Warning",
  "severity": "critical",
  "status": "active",
  "headline": "Tornado Warning",
  "location": "Lauderdale County",
  "areas": ["Lauderdale County, AL"],
  "summary": "A severe storm capable of producing a tornado is moving east.",
  "instruction": "Take shelter now.",
  "startsAt": "2026-07-11T15:20:00-05:00",
  "expiresAt": "2026-07-11T16:00:00-05:00",
  "source": "NWS",
  "sourceId": "urn:oid:example",
  "priority": 100,
  "tags": ["tornado", "warning", "local"],
  "geometry": null,
  "raw": null
}
```

## Product Contract

Each visual product should be self-contained and expose a simple contract:

- which event categories it accepts
- which output profiles it supports
- default duration
- whether it can interrupt the playlist
- renderer entry point
- styles and assets

Suggested product structure:

```text
app/products/alert-card/
├── manifest.json
├── renderer.js
├── styles.css
├── template.html
└── defaults.json
```

## Tenant Configuration

A tenant supplies brand, coverage, feeds, playlist, and assets.

```text
app/tenants/nwals/
├── tenant.json
├── theme.json
├── coverage.json
├── feeds.json
├── playlist.json
└── assets/
```

Reusable products must read values such as `coverageName`, colors, fonts, logo, radar center, and enabled feeds from configuration rather than hardcoding them.

## Playlist and Interruptions

Normal products run in configured order. Alerts can interrupt according to priority.

```text
Tornado Warning
↓
Full-screen alert card
↓
Existing warning radar stop
↓
Resume playlist
```

Lower-priority products should insert at the next safe break instead of tearing down an active critical product.

## Reliability Rules

- The current production broadcast remains operational while new modules are built beside it.
- Existing map warning behavior remains the fallback until alert cards are proven stable.
- Every product must fail closed and allow the playlist to continue.
- Network fetches require timeouts and graceful fallback.
- Long-running playlist functions require watchdog protection.
- Manual test fixtures must exist for every alert family.
- No source token or secret belongs in browser-side code.

## First Platform Module

The first reusable module is **P-003 Full-Screen Weather Alert Cards**.

It will normalize existing NWS alert data, render a reusable themed title card, then hand control to the existing warning-map stop.
