Files
SixFlagsSuperCalendar/docs/API.md
T
josh a53e3ffa9f
Build and Deploy / Build & Push (push) Successful in 1m31s
docs: add comprehensive project documentation
Add docs/ folder with architecture, operations, API reference, and
development guides covering system design, deployment, troubleshooting,
all backend endpoints, and contributor workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 22:15:02 -04:00

12 KiB
Raw Blame History

API Reference

See also: Architecture | Operations | Development

Base URL

Context URL
Local development http://localhost:3001
Docker internal (web → backend) http://backend:3001
External access (via host port) http://<host>:3001

Authentication

None. All endpoints are public and unauthenticated. The scrape trigger endpoint is also unprotected -- restrict access at the network/proxy level if needed.


Endpoints

GET /api/calendar/week

Returns a 7-day calendar for all parks, starting from the given Sunday.

Query Parameters:

Param Required Format Description
start Yes YYYY-MM-DD Week start date (should be a Sunday)

Cache: Cache-Control: public, max-age=120, stale-while-revalidate=300

Response:

{
    "weekStart": "2026-04-19",
    "weekDates": ["2026-04-19", "2026-04-20", "2026-04-21", "2026-04-22", "2026-04-23", "2026-04-24", "2026-04-25"],
    "today": "2026-04-23",
    "isCurrentWeek": true,
    "data": {
        "cedarpoint": {
            "2026-04-23": {
                "isOpen": true,
                "hoursLabel": "10am  8pm",
                "specialType": null
            },
            "2026-04-24": {
                "isOpen": false,
                "hoursLabel": null,
                "specialType": null
            }
        }
    },
    "rideCounts": {
        "cedarpoint": 42,
        "greatadventure": 38
    },
    "coasterCounts": {
        "cedarpoint": 12,
        "greatadventure": 9
    },
    "openParkIds": ["cedarpoint", "greatadventure"],
    "closingParkIds": [],
    "weatherDelayParkIds": [],
    "hasCoasterData": true,
    "scrapedCount": 168
}

Response fields:

Field Type Description
weekStart string Echo of the start parameter
weekDates string[] Array of 7 date strings (Sun-Sat)
today string Current date (with 3 AM switchover)
isCurrentWeek boolean Whether this week contains today
data Record<parkId, Record<date, DayData>> Schedule data keyed by park ID and date
rideCounts Record<parkId, number> Number of open rides per park (only for currently operating parks with rides reporting)
coasterCounts Record<parkId, number> Number of open coasters per park
openParkIds string[] Parks currently within their operating window
closingParkIds string[] Parks past close but within 1-hour wind-down
weatherDelayParkIds string[] Parks within window but all rides closed
hasCoasterData boolean Always true (coaster data is static)
scrapedCount number Total day records returned (sanity check for empty database)

Errors:

Status Body Condition
400 { "error": "Missing or invalid ?start=YYYY-MM-DD" } Missing or malformed start parameter

GET /api/calendar/:parkId/month

Returns a month calendar for a single park.

Path Parameters:

Param Description
parkId Park identifier (e.g. cedarpoint, greatadventure)

Query Parameters:

Param Required Format Description
month Yes YYYY-MM Month to fetch

Cache: Cache-Control: public, max-age=300, stale-while-revalidate=600

Response:

{
    "parkId": "cedarpoint",
    "year": 2026,
    "month": 6,
    "monthData": {
        "2026-06-01": {
            "isOpen": true,
            "hoursLabel": "10am  10pm",
            "specialType": null
        },
        "2026-06-02": {
            "isOpen": true,
            "hoursLabel": "10am  8pm",
            "specialType": null
        }
    },
    "today": "2026-04-23"
}

If viewing the current month, today's data is fetched live from the Six Flags API and merged into the response.

Errors:

Status Body Condition
400 { "error": "Missing or invalid ?month=YYYY-MM" } Missing or malformed month parameter
400 { "error": "Month must be 1-12" } Month value out of range

GET /api/parks

Returns metadata for all 24 parks.

Cache: Cache-Control: public, max-age=3600

Response:

{
    "parks": [
        {
            "id": "cedarpoint",
            "apiId": 70,
            "name": "Cedar Point",
            "shortName": "Cedar Point",
            "chain": "sixflags",
            "slug": "cedarpoint",
            "region": "Midwest",
            "location": {
                "lat": 41.4784,
                "lng": -82.6834,
                "city": "Sandusky",
                "state": "OH"
            },
            "timezone": "America/New_York",
            "website": "https://www.sixflags.com"
        }
    ]
}

GET /api/parks/:id

Returns metadata for a single park.

Path Parameters:

Param Description
id Park identifier

Cache: Cache-Control: public, max-age=3600

Response: A single Park object (same shape as one element of the /api/parks array).

Errors:

Status Body Condition
404 { "error": "Park not found" } Unknown park ID

GET /api/parks/:id/rides

Returns live ride status or schedule fallback for a park.

Path Parameters:

Param Description
id Park identifier

Cache: Cache-Control: public, max-age=60, stale-while-revalidate=120

Response:

{
    "parkId": "cedarpoint",
    "today": "2026-04-23",
    "parkOpenToday": true,
    "withinWindow": true,
    "isWeatherDelay": false,
    "liveRides": {
        "rides": [
            {
                "name": "Steel Vengeance",
                "isOpen": true,
                "waitMinutes": 45,
                "lastUpdated": "2026-04-23T18:30:00.000Z",
                "isCoaster": true
            },
            {
                "name": "Millennium Force",
                "isOpen": false,
                "waitMinutes": 0,
                "lastUpdated": "2026-04-23T18:30:00.000Z",
                "isCoaster": true
            }
        ],
        "fetchedAt": "2026-04-23T18:35:00.000Z"
    },
    "scheduleFallback": null
}

Response fields:

Field Type Description
parkId string Echo of the park ID
today string Current date (with 3 AM switchover)
parkOpenToday boolean Whether the park has hours scheduled today
withinWindow boolean Whether current time is within operating hours
isWeatherDelay boolean Park is open but all rides are closed
liveRides LiveRidesResult | null Queue-Times live data (null if park has no mapping or is outside window)
scheduleFallback RidesFetchResult | null Six Flags schedule data (only populated when liveRides is null)

Data priority:

  1. If a Queue-Times mapping exists and the park is tracked, liveRides is populated.
  2. If outside the operating window, all rides in liveRides are forced to isOpen: false.
  3. If no live data is available, scheduleFallback is fetched from the Six Flags schedule API for the nearest open date.

Errors:

Status Body Condition
404 { "error": "Park not found" } Unknown park ID

GET /api/status

Health check endpoint with database statistics.

Response:

{
    "status": "ok",
    "uptime": 86400,
    "parks": 24,
    "database": {
        "totalDays": 8760,
        "lastScrape": "2026-04-23T14:00:12.000Z"
    },
    "lastScrapeResult": {
        "scope": "today",
        "fetched": 24,
        "skipped": 0,
        "errors": 0,
        "updated": 3,
        "startedAt": "2026-04-23T14:00:00.000Z",
        "finishedAt": "2026-04-23T14:00:12.000Z"
    }
}
Field Type Description
status string Always "ok"
uptime number Process uptime in seconds
parks number Number of tracked parks (24)
database.totalDays number Total rows in park_days table
database.lastScrape string | null ISO timestamp of the most recent scraped_at value
lastScrapeResult ScrapeResult | null Result of the last completed scrape (null if none has run yet)

POST /api/scrape/trigger

Manually triggers a data scrape. See Operations > Manual Scraping for detailed usage.

Query Parameters:

Param Required Default Values Description
scope No today today, month, upcoming, full, force What to scrape

Scope details:

Scope What it scrapes Staleness check Inter-park delay
today Today's hours only No (uses diff-before-write) 500ms
month Current month Yes (skips if fresh) 1000ms
upcoming Current + next month Yes 1000ms
full All 12 months Yes 1000ms
force All 12 months No (ignores staleness) 1000ms

Response:

{
    "scope": "today",
    "fetched": 24,
    "skipped": 0,
    "errors": 0,
    "updated": 3,
    "startedAt": "2026-04-23T14:00:00.000Z",
    "finishedAt": "2026-04-23T14:00:12.000Z"
}

Errors:

Status Body Condition
400 { "error": "Invalid scope. Use: today, month, upcoming, full, force" } Unknown scope value

Data Types

DayData

Core schedule data for a single park on a single day.

interface DayData {
    isOpen: boolean;           // Whether the park is open
    hoursLabel: string | null; // e.g. "10am  6pm", null when closed
    specialType: string | null; // "passholder_preview" or null
}

Park

Park metadata (static, defined in lib/parks.ts).

interface Park {
    id: string;            // Unique identifier (e.g. "cedarpoint")
    apiId: number;         // Six Flags CloudFront API park ID
    name: string;          // Full display name
    shortName: string;     // Abbreviated name
    chain: string;         // "sixflags"
    slug: string;          // URL-safe slug
    region: string;        // Geographic region
    location: {
        lat: number;
        lng: number;
        city: string;
        state: string;
    };
    timezone: string;      // IANA timezone (e.g. "America/New_York")
    website: string;       // Park website URL
}

LiveRide

A single ride from the Queue-Times.com API.

interface LiveRide {
    name: string;          // Ride display name
    isOpen: boolean;       // Currently operating
    waitMinutes: number;   // Current wait time (0 if closed)
    lastUpdated: string;   // ISO 8601 timestamp from Queue-Times
    isCoaster: boolean;    // Classified as a roller coaster via RCDB data
}

LiveRidesResult

Container for live ride data.

interface LiveRidesResult {
    rides: LiveRide[];     // All rides, sorted: open first, then alphabetical
    fetchedAt: string;     // ISO timestamp of when we fetched from Queue-Times
}

RidesFetchResult

Schedule-based ride data (fallback when live data is unavailable).

interface RidesFetchResult {
    rides: RideStatus[];   // Rides with scheduled open/close times
    dataDate: string;      // YYYY-MM-DD the data came from (may differ from requested date)
    isExact: boolean;      // true if dataDate matches requested date
    parkHoursLabel?: string; // Park-level hours for the data date
}

interface RideStatus {
    name: string;
    isOpen: boolean;       // Has scheduled operating hours
    hoursLabel?: string;   // e.g. "10am  10pm"
}

ScrapeResult

Result of a scraping operation.

interface ScrapeResult {
    scope: string;         // What was scraped (e.g. "today", "months(2026-04)")
    fetched: number;       // API calls made successfully
    skipped: number;       // Skipped due to staleness or null response
    errors: number;        // Failed API calls
    updated: number;       // Database rows written
    startedAt: string;     // ISO timestamp
    finishedAt: string;    // ISO timestamp
}