Skip to content

About

Full-stack network ops center — HTTP/TCP/DNS probing every 30s, WebSocket live push, JWT auth, AES-256-GCM at rest, P1–P4 auto-incidents, PostgreSQL pipeline.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

NOC Dashboard

Real-time Network Operations Center for monitoring cloud infrastructure. Services are checked every 30 seconds via HTTP/HTTPS/TCP/DNS probes. Failures open P1 incidents automatically, trigger email alerts, and push live updates to all connected clients over WebSocket.

Built as a portfolio project to demonstrate full-stack architecture: reactive frontend state machine, WebSocket with HTTP polling fallback, JWT auth with proactive refresh, and a PostgreSQL-backed event/incident pipeline.


Demo

NOC Dashboard Demo


Features

Monitoring

  • Multi-protocol health checks — HTTP, HTTPS, TCP, DNS probes with configurable timeout and retry logic
  • Uptime SLA — 24 h uptime % calculated per service from the checks table, shown in Services and Dashboard
  • Latency bar — visual indicator per service; configurable degraded threshold (LATENCY_THRESHOLD_MS)
  • Auto-incident on DOWN — worker detects UP→DOWN transitions and opens a P1 incident automatically if none is already open for that service
  • Recovery alerts — email sent when a service returns to UP after DOWN/DEGRADED; subject line shows "RECOVERED"

Incident management

  • Split-panel list + detail view
  • Status transitions: OPEN → INVESTIGATING → RESOLVED
  • Timeline with system and manual entries
  • Admin notes on active incidents

Alerts & event log

  • Full event history (DOWN / DEGRADED / UP) with email badge when an alert was sent
  • Paginated 25 events/page with filter-aware pagination

Real-time

  • WebSocket push from backend on every check cycle
  • Automatic fallback to HTTP polling on disconnect with reconnection indicator

Auth

  • JWT (8 h) with proactive refresh when < 30 min remain; reactive 401 retry with 2 h grace period
  • Role-based UI: admin can add/remove services and manage incidents; viewer is read-only
  • Session restored on page reload from localStorage
  • Audit trail — every login/refresh attempt recorded in auth_events (IP, user-agent, outcome)
  • Lockout — 5 failed logins in 10 minutes temporarily blocks the username (HTTP 429)
  • IP-mismatch detection — refresh from a different IP than the last successful login is logged as IP_MISMATCH (does not block; surfaces in GET /api/auth/events for admin review)

Security

  • Encryption at rest — services.host, services.port and checks.error_msg are encrypted with AES-256-GCM before reaching Postgres. Topology data is unreadable from a DB dump or compromised replica without DATA_ENCRYPTION_KEY. Aggregations on latency_ms / status remain plain so uptime % and dashboards keep working.
  • Encryption in transit — terminate TLS in front of the Node API (see TLS deployment) so HTTPS + WSS is enforced for every probe-result delivery.
  • Defense in depth — combined with disk-level encryption (LUKS / cloud KMS), an attacker needs the disk and the application key to read topology.

UX

  • Dark / light mode toggle — persisted in localStorage, transitions via CSS custom properties
  • Responsive layout — hamburger drawer sidebar on mobile, full sidebar on desktop
  • Confirmation dialog on destructive actions (remove service)
  • Empty states — contextual messages when incident/alert lists are empty
  • Toast notifications for live DOWN / DEGRADED events

Stack

Layer Tech
Frontend React 18 · TypeScript · Vite · Tailwind CSS v3
Backend Node.js · Express · PostgreSQL 16 · WebSocket (ws)
Auth JWT (8 h expiry) · bcryptjs
Alerts Nodemailer / SMTP
Deploy Docker Compose

Quick start

Option A — Full Docker (DB + backend)

cd project/backend
cp .env.example .env        # set JWT_SECRET and SMTP vars
docker compose up -d        # postgres:16 + node app on :3000

Option B — DB via Docker, backend + frontend local (recommended for dev)

# Terminal 1 — database
cd project/backend
cp .env.example .env
docker compose up db -d     # postgres on :5432

# Terminal 2 — backend
cd project/backend
npm install
npm run dev                 # nodemon → http://localhost:3000

# Terminal 3 — frontend
cd project/frontend
npm install
npm run dev                 # Vite → http://localhost:5173

Default credentials: admin / admin123 · viewer / viewer123


Project structure

project/
├── backend/
│   ├── src/
│   │   ├── app.js          # Express entry point, middleware, routes
│   │   ├── db.js           # pg Pool, seed users + services
│   │   ├── worker.js       # Check scheduler (setInterval), auto-incident logic
│   │   ├── ws.js           # WebSocket server, broadcasts check results
│   │   ├── logger.js       # Winston logger
│   │   ├── schema.sql      # PostgreSQL schema, indexes, triggers
│   │   └── routes/
│   │       ├── auth.js
│   │       ├── services.js
│   │       ├── checks.js
│   │       ├── incidents.js
│   │       └── monitoring.js
│   ├── Dockerfile
│   ├── docker-compose.yml
│   └── .env.example
│
├── frontend/
│   ├── src/
│   │   ├── engine/
│   │   │   └── engine.ts       # State machine, pub/sub, API client, WebSocket
│   │   ├── types/
│   │   │   └── noc.types.ts    # All shared TypeScript interfaces
│   │   ├── components/
│   │   │   ├── ui/             # StatusBadge, Btn, Modal, ConfirmDialog, EmptyState…
│   │   │   ├── Sidebar.tsx     # Nav + provider status, mobile drawer
│   │   │   ├── TopBar.tsx      # Title, WS indicator, theme toggle, hamburger
│   │   │   ├── LoginScreen.tsx
│   │   │   ├── ConnectionBanner.tsx
│   │   │   └── ToastContainer.tsx
│   │   ├── views/
│   │   │   ├── DashboardView.tsx
│   │   │   ├── ServicesView.tsx
│   │   │   ├── IncidentsView.tsx
│   │   │   └── AlertsView.tsx
│   │   ├── App.tsx
│   │   └── index.css           # CSS custom properties for theming
│   ├── tailwind.config.js
│   └── vite.config.ts
│
└── old-ver/                # Original CDN/JSX prototype (reference only)

Environment variables

Variable Default Description
PORT 3000 HTTP server port
DATABASE_URL — PostgreSQL connection string
JWT_SECRET — Change in production
JWT_EXPIRES_IN 8h Token lifetime
CHECK_INTERVAL_SECONDS 30 How often to run all checks
CHECK_TIMEOUT_MS 5000 Per-check HTTP/TCP timeout
CHECK_RETRIES 3 Consecutive failures before marking DOWN
LATENCY_THRESHOLD_MS 300 Response time above this → DEGRADED
SMTP_HOST / SMTP_USER / SMTP_PASS — Email alert config (Nodemailer)
CORS_ORIGIN * Allowed origin for CORS (set to frontend URL in production)
CHECKS_RETENTION_DAYS 7 Days to keep raw check records
EVENTS_RETENTION_DAYS 30 Days to keep event log entries
ALERTS_RETENTION_DAYS 90 Days to keep sent alert records
DATA_ENCRYPTION_KEY — Required. 32-byte key (hex or base64) used by AES-256-GCM for encryption at rest. Generate with openssl rand -base64 32.
AUTH_LOCKOUT_THRESHOLD 5 Failed logins in window before account is temporarily locked
AUTH_LOCKOUT_WINDOW_MIN 10 Lockout window in minutes
AUTH_EVENTS_RETENTION_DAYS 90 Days to keep auth audit trail

Migrating an existing database

If you upgraded from a version before encryption-at-rest was added:

# 1. Pick a key and persist it to .env (NEVER commit it).
openssl rand -base64 32   # copy output → DATA_ENCRYPTION_KEY=...

# 2. Widen sensitive columns and create the auth_events table.
docker exec -i noc_db psql -U noc -d nocdb < backend/src/migrations/002_encrypt_sensitive.sql
docker exec -i noc_db psql -U noc -d nocdb < backend/src/migrations/003_auth_events.sql

# 3. Encrypt existing rows in place. Idempotent — safe to re-run.
cd backend && node src/migrations/002_encrypt_existing.js

The decrypt path tolerates plaintext during the rollout, so step 3 can be deferred without breaking reads. Losing DATA_ENCRYPTION_KEY makes the encrypted columns unreadable — back it up alongside JWT_SECRET.


TLS deployment

Probe results expose network topology. In production, terminate TLS in front of the Node API so probe payloads, login credentials, and WebSocket frames travel encrypted end-to-end. Caddy is the simplest option (auto-renewed Let's Encrypt + automatic WS upgrade):

# /etc/caddy/Caddyfile
noc.example.com {
  encode zstd gzip

  # WebSocket upgrade is handled automatically by reverse_proxy.
  reverse_proxy localhost:3000

  header {
    Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    X-Content-Type-Options "nosniff"
    Referrer-Policy "no-referrer"
  }
}

Then point the frontend at https://noc.example.com/api and wss://noc.example.com/ws. The backend already calls app.set('trust proxy', 1) so req.ip resolves to the real client behind Caddy — required for the auth audit trail and IP-mismatch detection.

About

Full-stack network ops center — HTTP/TCP/DNS probing every 30s, WebSocket live push, JWT auth, AES-256-GCM at rest, P1–P4 auto-incidents, PostgreSQL pipeline.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages