Skip to content

JOJOMRJ/NuraSpaceCode-Challenge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NuraSpace Weather

A full-stack real-time weather application with WebSocket-powered live updates and topic-based pub/sub messaging.

Architecture

Browser ──→ Nginx (static files + reverse proxy)
               │
               ├── /api/*       ──→ Express (REST API)
               └── /socket.io/* ──→ Socket.IO (WebSocket)
                                       │
                                       ├── Topic-based Pub/Sub
                                       └── Weather Polling ──→ OpenWeatherMap API

Tech Stack

Layer Technology
Frontend React 19, TypeScript, Tailwind CSS, Vite
Backend Express 5, TypeScript, Socket.IO, JWT
Realtime Socket.IO with topic-based pub/sub
Weather OpenWeatherMap API (free tier)
Deploy Docker, Docker Compose, Nginx

Features

  • User Authentication — JWT-based login with protected routes
  • City Weather Query — Real-time weather data from OpenWeatherMap (temperature, humidity, wind speed, icon)
  • Live Weather Updates — Backend polls weather every 60s, pushes changes via WebSocket
  • Topic-based Pub/Sub — Extensible messaging system with topic validation and subscription management
  • Real-time Message Push — Toast notifications delivered to subscribed clients
  • Socket Authentication — JWT verification on WebSocket connections
  • Health CheckGET /api/v1/health endpoint for monitoring
  • Docker Support — One-command startup with docker-compose

Quick Start

Docker (Recommended)

# 1. Clone the repository
git clone <repo-url> && cd NuraSpaceCode-Challenge

# 2. Create server/.env
cp server/.env.example server/.env
# Edit server/.env and add your OpenWeatherMap API key

# 3. Start everything
docker-compose up --build

# 4. Open http://localhost:3000

Local Development

# Backend
cd server
npm install
cp .env.example .env  # Add your API key
npm run dev            # Starts on port 3001

# Frontend (in another terminal)
cd client
npm install
npm run dev            # Starts on port 5173 with proxy to 3001

Environment Variables

Variable Description Required
OPENWEATHER_API_KEY OpenWeatherMap API key Yes
JWT_SECRET Secret for signing JWT tokens Yes
PORT Server port (default: 3001) No

API Endpoints

Method Path Description Auth
POST /api/v1/auth/login User login No
GET /api/v1/weather/:city Get weather data Yes
POST /api/v1/messages Push message to topic No
GET /api/v1/health Health check No

WebSocket Events

Event Direction Payload Description
subscribe Client → Server ['city:Sydney'] Subscribe to topics
message Server → Client { topic, message, timestamp } Live message notification
weather:update Server → Client { city, temp, humidity, ... } Real-time weather update

Project Structure

├── docker-compose.yml
├── client/                     # React frontend
│   ├── Dockerfile
│   ├── nginx.conf              # Production reverse proxy
│   └── src/
│       ├── pages/
│       │   ├── Login/          # Login page
│       │   └── Home/           # Weather dashboard
│       │       ├── components/ # CitySelector, WeatherCard, Toast
│       │       └── hooks/      # useSocket (WebSocket hook)
│       ├── services/           # API client, Socket.IO client
│       └── context/            # Auth state management
├── server/                     # Express backend
│   ├── Dockerfile
│   └── src/
│       ├── routes/v1/          # Versioned API routes
│       ├── controllers/        # Request handlers
│       ├── services/           # Weather API, Weather Poller
│       ├── infrastructure/     # Socket.IO setup (pub/sub + auth)
│       ├── middleware/         # JWT auth middleware
│       └── data/               # In-memory user store

Design Decisions

Real-time Weather Updates — Why Server-Side Polling?

The app automatically pushes weather updates to clients when data changes, without users having to refresh. This is implemented via server-side polling (every 60s) + WebSocket push.

Why not use a push-based weather API?

OpenWeatherMap (and most weather APIs) don't offer WebSocket or webhook-based real-time feeds on their free tier. Services like Xweather or WeatherFlow do provide streaming APIs, but they are paid, proprietary, and would tightly couple the app to a specific vendor.

Server-side polling is the standard approach because:

  • Vendor-agnostic — The poller wraps any HTTP-based weather API. Switching providers requires changing one service file, not the entire real-time architecture.
  • Efficient — Only polls cities with active subscribers. No subscribers = no API calls. Change detection (hasChanged) ensures we only push when data actually differs, avoiding unnecessary WebSocket traffic.
  • Scalable — In production, the polling interval and concurrency can be tuned. The same pattern works with Redis pub/sub for multi-instance deployments.

Topic-based Pub/Sub — Why Not Just Socket.IO Rooms?

The messaging layer uses a topic-based pub/sub model (city:Sydney, city:Melbourne) instead of raw Socket.IO rooms.

  • Extensible — Adding new topic types (e.g. alert:storm, region:oceania) requires only adding a prefix to the whitelist, no structural changes.
  • Secure — Topic validation (prefix whitelist, max count, max length) prevents abuse. Raw rooms accept any string.
  • Observable — Dual-map tracking (topicSubscribers + connTopics) makes it easy to inspect who is listening to what, and ensures clean disconnection handling.

Demo Accounts

Username Password
admin admin
user 123456

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors