๐ŸŽข park.fan API v4

Real-time theme park intelligence powered by machine learning

NestJS TypeScript PostgreSQL Docker

Aggregating wait times, weather forecasts, park schedules, and ML-powered predictions for optimal theme park experiences worldwide.


๐Ÿ“– Quick Navigation


โœจ Features


๐Ÿ› ๏ธ Tech Stack

Category Technology
Backend NestJS 11 ยท TypeScript (strict mode)
Database PostgreSQL 16 ยท TimescaleDB
Cache & Queue Redis 7 ยท Bull Queue
ML Service Python 3.11 ยท CatBoost ยท FastAPI
DevOps Docker Compose ยท GitHub Actions
Testing Jest ยท Supertest ยท Testcontainers

๐Ÿ“… Special Logic: Schedules & Seasons

The API implements advanced logic to handle parks without official API schedules (e.g., Efteling, Hellendoorn) and seasonal closures.

1. hasOperatingSchedule Flag

All park objects include a hasOperatingSchedule boolean:

2. Historical Hour Reconstruction

For past days without official data, the system reconstructs opening hours from ride activity. See the Smart Gaps Documentation for technical details.

3. Seasonal Detection

The system automatically identifies "Seasonal Parks" (parks with winter gaps > 21 days).


๐Ÿš€ Quick Start

Prerequisites

Installation

# Clone the repository
git clone https://github.com/PArns/v4.api.park.fan.git
cd v4.api.park.fan

# Install dependencies
npm install

# Copy environment configuration
cp .env.example .env

# Start infrastructure (PostgreSQL + Redis)
npm run docker:up

# Start development server
npm run dev

Access Points

Once running, you can access:


๐Ÿ“š API Documentation

๐Ÿฅ Health & Monitoring

System health checks and monitoring endpoints.

GET /v1/health              # System health status
GET /v1/health/db           # Database connectivity

Response includes:


๐ŸŽก Parks

Core endpoints for park information, weather, schedules, and wait times. All routes use the full geographic path structure for consistency and SEO-friendly URLs.

Geographic Routes:

GET /v1/parks                                                      # List all parks (paginated)
GET /v1/parks/:continent                                          # Parks by continent
GET /v1/parks/:continent/:country                                 # Parks by country
GET /v1/parks/:continent/:country/:city                           # Parks by city
GET /v1/parks/:continent/:country/:city/:parkSlug                 # Get park by location
GET /v1/parks/:continent/:country/:city/:parkSlug/calendar        # Integrated calendar
GET /v1/parks/:continent/:country/:city/:parkSlug/weather         # Current weather & history
GET /v1/parks/:continent/:country/:city/:parkSlug/weather/forecast # 16-day forecast
GET /v1/parks/:continent/:country/:city/:parkSlug/schedule        # Operating hours
GET /v1/parks/:continent/:country/:city/:parkSlug/wait-times       # Live wait times
GET /v1/parks/:continent/:country/:city/:parkSlug/predictions/yearly # Yearly crowd predictions
GET /v1/parks/:continent/:country/:city/:parkSlug/attractions     # List park attractions
GET /v1/parks/:continent/:country/:city/:parkSlug/attractions/:attractionSlug # Get attraction

Query Parameters:

Example Geographic Route:

GET /v1/parks/north-america/united-states/orlando/magic-kingdom

Example Response:

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "Magic Kingdom",
  "slug": "magic-kingdom",
  "url": "/v1/parks/north-america/united-states/orlando/magic-kingdom",
  "continent": "North America",
  "country": "United States",
  "city": "Orlando",
  "timezone": "America/New_York",
  "currentStatus": "OPERATING",
  "currentLoad": {
    "crowdLevel": "moderate",
    "occupancy": 0.65
  },
  "coordinates": { "lat": 28.3772, "lng": -81.5707 },
  "attractions": [
    {
      "id": "...",
      "name": "Space Mountain",
      "slug": "space-mountain",
      "url": "/v1/parks/north-america/united-states/orlando/magic-kingdom/attractions/space-mountain"
    }
  ]
}

๐ŸŽข Attractions

Detailed attraction data with ML predictions and historical analytics. Access attractions through their park's geographic route.

Routes:

GET /v1/parks/:continent/:country/:city/:parkSlug/attractions              # List park attractions
GET /v1/parks/:continent/:country/:city/:parkSlug/attractions/:attractionSlug # Get attraction details

Query Parameters:

Response includes:

Example Response:

{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "Space Mountain",
  "slug": "space-mountain",
  "url": "/v1/parks/north-america/united-states/orlando/magic-kingdom/attractions/space-mountain",
  "park": {
    "id": "...",
    "name": "Magic Kingdom",
    "slug": "magic-kingdom"
  },
  "category": "RIDE",
  "currentWaitTime": 45,
  "status": "OPERATING",
  "lastUpdate": "2025-12-23T19:30:00Z",
  "forecast": [
    { "hour": "20:00", "predictedWaitTime": 50, "confidence": 0.87 },
    { "hour": "21:00", "predictedWaitTime": 35, "confidence": 0.82 }
  ],
  "stats": {
    "averageWaitTime": 42,
    "p50": 40,
    "p75": 55,
    "p90": 70
  }
}

๐ŸŒ Geographic Discovery

Navigate parks by geographic hierarchy for route generation and exploration.

GET /v1/discovery/geo                        # Full geo hierarchy
GET /v1/discovery/continents                 # List continents
GET /v1/discovery/continents/:continent      # Countries in continent

Response Structure:

{
  "continents": [
    {
      "continent": "North America",
      "countries": [
        {
          "country": "United States",
          "cities": [
            {
              "city": "Orlando",
              "parks": [
                {
                  "name": "Magic Kingdom",
                  "url": "/north-america/united-states/orlando/magic-kingdom",
                  "attractions": [...]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

๐Ÿฐ Destinations

Resort-level aggregation grouping multiple parks. Destinations are used internally for data organization but are not exposed as top-level API endpoints. Parks are accessed directly via their geographic routes.

Examples:


๐ŸŽญ Shows & Dining

Entertainment and dining options are available through the park endpoints. Shows and restaurants are not exposed as top-level API endpoints but are included in park responses and can be accessed via the search endpoint.


๐Ÿ” Intelligent Search

Global search with enriched results across parks and attractions.

GET /v1/search?q=disney                    # Search all types
GET /v1/search?q=thunder&type=attraction  # Filter by type
GET /v1/search?q=paris                   # Search by city

Search Features:

Response Structure:

{
  "query": "disney",
  "counts": {
    "park": {"returned": 5, "total": 13},
    "attraction": {"returned": 5, "total": 156}
  },
  "results": [
    {
      "type": "park",
      "name": "Disneyland Park",
      "status": "OPERATING",
      "load": "normal",
      "parkHours": {...},
      "coordinates": {...}
    },
    {
      "type": "attraction",
      "name": "Space Mountain",
      "waitTime": 45,
      "load": "higher",
      "parentPark": {...}
    }
  ]
}

๐ŸŽ‰ Holidays

Public holiday data affecting park crowds and operating hours. Holidays are used internally for ML predictions and analytics but are not exposed as top-level API endpoints.


๐Ÿ“ Project Structure

v4.api.park.fan/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ config/                    # App configuration & environment
โ”‚   โ”œโ”€โ”€ common/                    # Shared utilities, filters, interceptors
โ”‚   โ”œโ”€โ”€ database/                  # Database utilities & migrations
โ”‚   โ”œโ”€โ”€ queues/                    # Bull queue setup & processors
โ”‚   โ”œโ”€โ”€ health/                    # Health check endpoints
โ”‚   โ”œโ”€โ”€ destinations/              # Resort/destination grouping
โ”‚   โ”œโ”€โ”€ parks/                     # Parks, weather, schedules
โ”‚   โ”œโ”€โ”€ attractions/               # Attractions & data sources
โ”‚   โ”œโ”€โ”€ shows/                     # Entertainment shows
โ”‚   โ”œโ”€โ”€ restaurants/               # Dining locations
โ”‚   โ”œโ”€โ”€ queue-data/                # Wait time data & history
โ”‚   โ”œโ”€โ”€ ml/                        # ML prediction integration
โ”‚   โ”œโ”€โ”€ analytics/                 # Statistics & analytics
โ”‚   โ”œโ”€โ”€ holidays/                  # Public holiday data
โ”‚   โ”œโ”€โ”€ date-features/             # Date-based features for ML
โ”‚   โ”œโ”€โ”€ discovery/                 # Geographic discovery endpoints
โ”‚   โ””โ”€โ”€ search/                    # Global search functionality
โ”œโ”€โ”€ ml-service/                    # Python ML service (CatBoost)
โ”‚   โ”œโ”€โ”€ train.py                   # Model training script
โ”‚   โ”œโ”€โ”€ inference.py               # FastAPI prediction service
โ”‚   โ”œโ”€โ”€ features.py                # Feature engineering
โ”‚   โ””โ”€โ”€ db.py                      # Database connection
โ”œโ”€โ”€ docker/                        # Docker configurations
โ”œโ”€โ”€ scripts/                       # Utility & debug scripts
โ”œโ”€โ”€ migrations/                    # Database migrations
โ””โ”€โ”€ test/                          # E2E tests

๐Ÿณ Docker Commands

# Start all services (PostgreSQL + Redis)
npm run docker:up

# Stop all services
npm run docker:down

# View logs
npm run docker:logs

# Restart services
npm run docker:restart

# Reset database (WARNING: deletes all data)
npm run db:reset

Production Deployment:

docker-compose -f docker-compose.production.yml up -d

๐Ÿงช Testing

# Run unit tests
npm run test

# Run e2e tests
npm run test:e2e

# Run all tests with coverage
npm run test:all:cov

# Watch mode for development
npm run test:watch

# Specific test file
npm run test -- wait-times.processor.spec.ts

Code Quality:

# Lint code
npm run lint

# Format code
npm run format

# Type check
npm run build

๐Ÿ”ง Environment Variables

Application Settings

NODE_ENV=development              # development | production | test
PORT=3000                         # API server port
API_PREFIX=v1                     # API version prefix

Database Configuration

# PostgreSQL with TimescaleDB
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=parkfan
DB_PASSWORD=your_secure_password
DB_DATABASE=parkfan
DB_SYNCHRONIZE=true               # โš ๏ธ Set to false in production!
DB_LOGGING=false                  # Enable for debugging
DB_SSL_ENABLED=false              # Enable for production

Caching & Queue

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=                   # Optional, recommended for production

# Bull Queue
BULL_PREFIX=parkfan

External APIs

# Google APIs (Geocoding, Places)
GOOGLE_API_KEY=your_google_api_key

# Weather Data
OPEN_WEATHER_API_KEY=your_openweather_key

# Data Sources (optional, for enhanced coverage)
QUEUE_TIMES_API_KEY=              # Queue-Times.com
THEMEPARKS_API_KEY=               # ThemeParks.wiki

ML Service

# ML Service Configuration
ML_SERVICE_URL=http://localhost:8000        # Development
# ML_SERVICE_URL=http://ml-service:8000     # Production (Docker)
MODEL_DIR=/app/models                       # Model storage directory
MODEL_VERSION=v1.1.0                        # Current model version

Sync & Processing

# Data Sync Intervals (cron expressions)
SYNC_WAIT_TIMES_CRON=*/5 * * * *           # Every 5 minutes
SYNC_PARK_METADATA_CRON=0 6 * * *          # Daily at 6 AM
SYNC_WEATHER_CRON=0 * * * *                # Hourly

๐Ÿค Contributing

This is a private project. For questions or collaboration inquiries, please contact the maintainer.


๐Ÿ“„ License

UNLICENSED โ€” Private project by Patrick Arns


๐Ÿ™ Powered By

This project aggregates data from multiple sources:

Special thanks to these services for making real-time theme park data accessible.


Made with โค๏ธ for theme park enthusiasts worldwide

API Documentation ยท Frontend