Skip to content

demo-assignment/fullstack-game-analytics-dashboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Game Analytics Dashboard (Internal MVP)

Mini internal dashboard that shows near real-time game analytics with basic CRUD-ish behavior (create + list + summary). Uses an in-memory backend store with a periodic mock data mutator so the UI changes without manual input.

Frontend features

  • Short polling (~4s) for list + summary
  • Debounced filters (~350ms) so typing doesn’t trigger request-per-keystroke
  • Chart demo (Recharts): value-over-time line chart (last ~30 events)
  • Nice-to-have: drag-and-drop reorder for chart cards within the Analytics Charts section (dnd-kit)
  • Light/Dark mode: system + manual toggle (persisted)

Prerequisites

  • Node.js: latest LTS (Node 22+ recommended)
  • npm: comes with Node

How to run (dev)

Backend (Express + TypeScript) - first-trial and alternative

cd backend-express
npm install
npm run dev

Backend starts on http://localhost:4000.

Backend (NestJS + TypeScript) - official backend

cd backend
npm install
npm run dev
  • Defaults to http://localhost:4000 (same as Express).
  • If backend/ is already running, either stop it or run Nest on another port:
cd backend
PORT=4001 npm run dev
Nest API docs
  • Swagger UI: http://localhost:<PORT>/api-docs
  • OpenAPI JSON: http://localhost:<PORT>/api-json
  • Scalar UI: http://localhost:<PORT>/api-reference

Frontend (React + Vite + TypeScript + Tailwind)

cd frontend
npm install
npm run dev

Frontend starts on http://localhost:5173.

Environment variables (optional)

Backend (backend)

  • PORT: defaults to 4000
  • CORS_ORIGIN: defaults to *
  • MUTATE_EVERY_MS: defaults to 3500 (randomly appends/mutates data for polling demo)

Frontend (frontend)

  • VITE_API_URL: defaults to http://localhost:4000

Example:

# frontend/.env
VITE_API_URL=http://localhost:4000

API endpoints

GET /analytics

Returns analytics entries (newest first). Supports simple filtering:

  • game: exact match
  • eventType: exact match
  • q: substring search over game, eventType, userId
  • page: 1-based page index (default 1)
  • pageSize: items per page (default 25, max 100)

Examples:

  • GET /analytics?game=SpaceRacer
  • GET /analytics?eventType=purchase
  • GET /analytics?q=u_042

Response:

{
  "data": [ { "id": "...", "timestamp": "...", "game": "...", "eventType": "...", "value": 123.45 } ],
  "meta": { "page": 1, "pageSize": 25, "total": 123, "totalPages": 5 }
}

POST /analytics

Creates a new analytics entry. Backend auto-generates id + timestamp.

Body:

{ "game": "SpaceRacer", "eventType": "level_complete", "value": 100, "userId": "u_042" }

Response:

{ "data": { "id": "...", "timestamp": "...", "game": "...", "eventType": "...", "value": 100, "userId": "u_042" } }

GET /analytics/summary

Aggregated stats over the in-memory store:

  • totalCount
  • averageValue

Response:

{ "data": { "totalCount": 123, "averageValue": 456.78 } }

GET /analytics/insights

Returns chart-ready datasets computed on the backend from the full in-memory store (so the frontend does not do aggregation).

Response (shape):

{
  "data": {
    "trend": { "points": [ { "timestamp": "...", "value": 12.34, "game": "...", "eventType": "..." } ] },
    "eventsByGame": [ { "game": "SpaceRacer", "count": 42 } ],
    "eventsByType": [ { "eventType": "purchase", "count": 10 } ],
    "avgValueByGame": [ { "game": "PixelWars", "avg": 123.45 } ]
  }
}

Video Youtube link (use FSCapture): https://youtu.be/rY-uYpipD_s

Screenshots (placeholders)

Dashboard - dark

Dashboard - dark

Dashboard - light

Dashboard - light

Filters + add entry

Filters + add entry

Swagger

Swagger

Scalar

Scalar

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors