Skip to content

bkunat/platinum-pulse

Repository files navigation

Platinum Pulse

A Dockerized web application that aggregates live occupancy data for Fitness Platinium clubs.

Screenshot 2025-11-01 at 19 34 50

⚠️ DISCLAIMERS

  • This project is entirely unaffiliated with Fitness Platinum. It is not authorized, endorsed, sponsored, or approved by Fitness Platinum in any form. All related trademarks are the property of their respective owners.
  • This software is provided for educational and research purposes only. It may be incomplete, unreliable, or non-functional. By using it, you accept full responsibility for any consequences and agree to indemnify the creator, contributors, and all other involved parties from any and all liability.
  • This project relies on unofficial and private APIs that may change, break, or be withdrawn at any time without notice. Use is entirely at your own risk.

Features

  • Real-time occupancy tracking
  • Historical data analysis and predictions
  • Interactive dashboard with charts
  • Geolocation-based club sorting
  • SQLite persistence
  • Automated polling every 10 minutes
  • RESTful API

Quick Start

Prerequisites

  • Node.js 20+
  • npm or pnpm

Installation

# Install dependencies for both frontend and backend
cd backend && npm install
cd ../frontend && npm install

Development

# Build the project
npm run build

# Start the server (from backend directory)
cd backend
npm start

The server will start on http://localhost:8080

Docker

# Build image
docker build -t platinum-pulse .

# Run container
docker run -p 8080:8080 -v $(pwd)/data:/data --env-file .env platinum-pulse

Or use docker-compose:

docker-compose up

Visit http://localhost:8080

Configuration

Copy .env.example to .env and configure:

PG_API_BASE_URL=https://goapi2.perfectgym.com
PG_API_TOKEN=your-bearer-token-here
COMPANY_ID=302
POLL_INTERVAL_MINUTES=10
CLUB_REFRESH_CRON=0 3 * * *
PORT=8080
DATABASE_URL=file:../data/platinum-pulse.sqlite

Project Structure

platinum-pulse/
├── backend/              # Fastify API server
│   ├── src/
│   │   ├── routes/      # API routes
│   │   ├── services/    # Business logic
│   │   ├── config/      # Configuration
│   │   └── main.ts      # Entry point
│   └── prisma/          # Database schema
├── frontend/            # React + Vite frontend
│   └── src/
│       ├── components/  # UI components
│       ├── pages/       # Page components
│       ├── hooks/       # Custom hooks
│       └── api/         # API client
├── data/                # SQLite database (volume mount)
└── Dockerfile           # Production container

API Endpoints

  • GET /api/health - Health check with database status
  • GET /api/stats - System statistics (clubs, snapshots, last poll)
  • GET /api/clubs?lat=X&lng=Y - List all clubs with current occupancy (optional geolocation)
  • GET /api/clubs/:id - Get specific club details
  • GET /api/occupancy/:clubId - Get occupancy data with predictions
  • GET /api/occupancy/:clubId/history?days=7 - Get historical occupancy
  • POST /api/poll - Manually trigger occupancy poll
  • POST /api/sync-clubs - Manually trigger club metadata sync

Technologies

  • Backend: Node.js, Fastify, Prisma, SQLite
  • Frontend: React 18, TypeScript, Vite, TanStack Query, Recharts, Tailwind CSS
  • Scheduling: node-cron
  • HTTP Client: axios with retry logic
  • Logging: pino

Development

# Build everything
npm run build

# Lint code
npm run lint

# Run tests
npm run test

# Development mode (backend with watch)
cd backend
npm run dev

Database Migrations

cd backend
npx prisma migrate dev --name migration_name
npx prisma generate

Deployment

The application is designed to run in a single Docker container suitable for Synology NAS or similar environments.

  1. Build the Docker image
  2. Mount a volume to /data for database persistence
  3. Provide environment variables via .env or docker-compose
  4. Expose port 8080

Notes

  • The application polls the PerfectGym API every 10 minutes by default
  • Club metadata is refreshed nightly at 3 AM (configurable via cron)
  • Historical predictions use a 7-day rolling average
  • The frontend requests geolocation once per session for distance-based sorting
  • All data is stored locally in SQLite - no external services required

About

Aggregate live occupancy data for Fitness Platinium clubs

Resources

License

Stars

Watchers

Forks

Packages

No packages published