High-Level Design
GPUForge · System Architecture · v1.2 · 2026-06-14
HLD Architecture v1.2

System Overview

GPUForge is a GPU fleet orchestration platform for operators managing GPU clusters at scale. It provides real-time fleet visibility, multi-tenant job scheduling, usage metering, and billing — in a single deployable Express/PostgreSQL stack.

What GPUForge Does

GPUForge solves the operational complexity of running shared GPU infrastructure for AI/ML workloads. Operators provision clusters, tenants consume GPU capacity, and the platform handles scheduling, quota enforcement, and billing — all from a real-time dashboard.

Three core services unified in one deploy:

  • GPU-as-a-Service (GPUaaS) — Cluster/node/GPU registry, metrics ingestion, fleet health monitoring
  • Inference as a Service — GPU allocation tracking, inference endpoint assignment, SLA monitoring
  • Agentic AI Workflow Orchestration — Job submission, priority scheduling, tenant quota enforcement, multi-job pipelines

Target Users

Primary audience: GPU cloud operators — platform engineers, MLOps leads, and CTOs at companies running shared GPU infrastructure (cloud providers, research institutions, enterprise AI platforms).

Two dashboard planes serve distinct personas:

PlaneURLPersonaCapabilities
Admin Dashboard/adminFleet operatorFleet visibility, tenant management, cluster config, scheduling controls, revenue analytics, alert management
Customer Dashboard/dashboard / /customerGPU tenantGPU allocations, notebook sessions, AI pod management, inference endpoints, workflow overview, billing history

Target Workloads

Workload TypeDescriptionScheduling Priority
Training JobsLarge distributed ML training — high GPU count, long durationP1 Batch / interactive
Inference EndpointsLow-latency serving — persistent GPU allocation, SLA-boundP2 Always-on
Agentic WorkflowsMulti-step AI pipelines — chains, loops, tool callsP3 Flexible
Interactive NotebooksJupyter-style sessions — on-demand, short-livedP4 Interactive

3-Service Architecture

GPUForge consolidates three distinct service types into one Express application. Each service has its own API surface, data model, and operator workflow.

Service 1 — GPU-as-a-Service (GPUaaS)

The foundation layer. Manages the physical GPU fleet lifecycle from node registration through real-time health monitoring.

Scope: cluster creation, node provisioning, GPU registration, metrics ingestion (utilization, memory, temperature, power), fleet health scoring, node status (online/offline/error), cluster-level capacity tracking.

Not owned: job scheduling logic, billing, tenant management.

Service 2 — Inference as a Service

GPU allocation and lifecycle for inference workloads. Tracks per-GPU assignment, inference endpoint status, and SLA metrics.

Scope: inference endpoint registry, GPU assignment to endpoints, endpoint health checks, per-endpoint resource usage, throughput metrics, latency tracking.

Not owned: model serving infrastructure (handled externally), job scheduling (delegated to GPUaaS scheduler).

Service 3 — Agentic AI Workflow Orchestration

The highest-level service. Coordinates multi-step AI workflows across GPU tenants — chain, loop, tool call patterns for autonomous agents.

Scope: job submission and lifecycle management, priority-based scheduling, tenant quota enforcement, multi-job pipeline tracking, workflow state machine (pending/running/completed/failed), retry logic, workflow logging.

Not owned: cluster/node management (GPUaaS), billing aggregation.

3-Service Stack

┌─────────────────────────────────────────────────────────────┐
│                      GPUForge Platform                       │
│                                                              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │         Agentic AI Workflow Orchestration             │   │
│  │  Job Submission · Priority Scheduling · Pipelines    │   │
│  │  State Machines · Retry Logic · Multi-Step Chains    │   │
│  └──────────────────────────┬───────────────────────────┘   │
│                             │                                │
│  ┌──────────────────────────┼───────────────────────────┐   │
│  │         Inference as a Service                       │   │
│  │  Endpoint Registry · GPU Assignment · SLA Tracking   │   │
│  └──────────────────────────┼───────────────────────────┘   │
│                             │                                │
│  ┌──────────────────────────┼───────────────────────────┐   │
│  │         GPU-as-a-Service (GPUaaS)                     │   │
│  │  Cluster Registry · Node Provisioning · Metrics       │   │
│  │  Fleet Health · GPU Status · Capacity Tracking       │   │
│  └──────────────────────────┬───────────────────────────┘   │
│                             │                                │
│  ┌──────────────────────────┴───────────────────────────┐  │
│  │              PostgreSQL (Neon) — Shared Data Layer    │  │
│  │  clusters · nodes · gpus · jobs · tenants · billing   │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Core Components

3a. Landing Page & SEO Pages

File: public/index.html (landing), public/use-cases/*.html, public/blog/*.html

The public-facing marketing surface. Landing page drives early-access signups and demo requests. SEO pages target specific use-case keywords (GPU cluster management, AI infrastructure monitoring, multi-tenant GPU platform). Client-side GA4 integration tracks page views, signup events, and scroll depth.

Key routes: GET /, GET /use-cases/*, GET /blog/*

Sub-components: hero with demo request modal, feature cards, contact sales section, request demo modal (POST /api/demo-requestsdemo_requests table → Polsia email notification)

3b. Admin Dashboard

File: public/admin.html — Single-page app (SPA) served as static HTML, client-side JS fetches from /api/dashboard, /api/clusters, /api/alerts, /api/billing.

Fleet operator's command center. Key panels:

PanelData SourceUpdate Frequency
Fleet OverviewGET /api/dashboardReal-time (polled)
Cluster ManagementGET /api/clusters, POST /api/clustersOn-demand
Node & GPU RegistryGET /api/clusters/nodes, POST /api/clusters/gpusOn-demand
Tenant ManagementGET /api/tenants, PUT /api/tenants/:idOn-demand
Job SchedulingGET /api/jobs, scheduler daemon30s cycle
Alert ManagementGET /api/alerts/rules, GET /api/alerts/events30s cycle
Revenue & BillingGET /api/billing/summary, GET /api/tenants/:id/usageOn-demand
AnalyticsGET /api/analytics, GET /api/dashboard/revenueOn-demand

3c. Customer Dashboard

File: public/tenant.html — SPA served at /dashboard and /customer, auth-gated via localStorage session token. Tenants see only their own GPU allocations, jobs, and billing.

Key panels:

PanelData SourceDescription
GPU AllocationsGET /api/dashboard/gpu-allocationMy allocated GPUs across all jobs
Notebook SessionsGET /api/jobs (filtered)Interactive sessions I've started
AI PodsGET /api/dashboardMy pod instances and status
Inference EndpointsGET /api/clusters/gpusMy inference endpoint assignments
WorkflowsGET /api/jobsMy submitted jobs and pipeline status
BillingGET /api/billing/invoices, GET /api/tenants/:id/invoicesMy invoices and payment history

3d. REST API Layer (25+ Endpoints)

Location: routes/*.js — one Router per domain group. Entry point server.js mounts all at /api.

All endpoints are RESTful, JSON-only, and support API key authentication via Authorization: Bearer <key> header. Demo mode allows unauthenticated access for testing.

Endpoint groups:

RouterEndpointsDescription
routes/clusters.js6Cluster CRUD, node/GPU registration, metrics ingestion
routes/jobs.js3Job submission, status update, listing
routes/tenants.js5Tenant CRUD, usage queries
routes/billing.js4Invoice creation, status updates, billing KPIs
routes/alerts.js4Rule management, event queries, enable/disable
routes/dashboard.js7KPI aggregates, revenue analytics, utilization, leakage
routes/api-keys.js4Generate, list, revoke API keys
routes/scheduler.js3Scheduler cycle trigger, status, logs
routes/analytics.js2Page view stats, signup/demorequest counts
routes/demo.js2Demo mode provisioning and status
routes/demo-requests.js1Demo request form submission
routes/misc.js2GPU rates, early access signup

See LLD for complete endpoint specs with request/response schemas.

3e. Job Scheduling Daemon

Location: jobs/scheduler-cycle.js + routes/scheduler.js

Runs every 30 seconds. Priority-based scheduler with tenant quota enforcement. Key behaviors:

  • Selects idle GPUs (status = 'idle') across all active clusters
  • Orders queued jobs by priority ascending (1 = highest)
  • For each job: checks tenant quota (gpu_in_use + gpu_count ≤ gpu_quota)
  • Assigns idle GPUs to eligible jobs with FOR UPDATE SKIP LOCKED (prevents double-assignment)
  • Jobs that fail quota checks stay queued or flip to blocked if the reason is quota
  • Emits usage_events for newly-completed jobs (GPU-hours consumed)
  • Logs every cycle to scheduler_logs — audit trail of decisions

Deployment model: In-process setInterval guarded by POLSIA_IN_PROCESS_CRONS_ENABLED=true on Render. Blaxel shadow sets this to false; Blaxel triggers the same script via polsia.toml [[crons]].

// Guard pattern (server.js)
if (process.env.POLSIA_IN_PROCESS_CRONS_ENABLED === 'true') {
  setInterval(runSchedulerCycle, 30000);
  // Also runs on startup after 5s delay
}

3f. Fleet Alert System

Location: routes/alerts.js + db/alerts.js

Configurable threshold rules evaluated every 30s. Three built-in rule types:

Rule TypeConditionSeverity
idle_gpu>60% of cluster GPUs idle for 5+ minutesWarning
quota_breach>90% of any tenant's GPU quota in useWarning
health_degradedNode unreachable OR >20% GPUs in error stateCritical

Alert events stored in alert_events with JSONB details. Notification via Polsia email proxy when rule has notification_enabled = true.

3g. Demo Mode & Mock Auth

Location: routes/demo.js, db/auth.js

Demo mode provisions a complete GPU cluster environment for evaluation without operator setup. The operator dashboard (/admin) runs in demo mode by default when no live clusters exist.

Mock auth: session tokens stored in localStorage. Admin role = any login to /admin. Tenant role = login to /dashboard. API key auth uses SHA-256 hashed keys stored in api_keys table — only the 12-char prefix shown in UI; full key shown once at creation.


Architecture Diagram

System Architecture

                                    ┌────────────────────────────────────────────────────┐
                                    │              GPUForge Platform                       │
                                    │              (Render Web Service)                   │
                                    │                                                    │
  ┌──────────────┐                  │  ┌──────────────────────────────────────────────┐   │
  │ GPU Cluster  │  POST /api/clusters/nodes   ┌──────────────────────────────────────┐   │
  │ Agent/Node   │────────────────────────────│           Express.js API              │   │
  │              │  POST /api/clusters/gpus    │                                      │   │
  │  H100/A100   │  POST /api/clusters/metrics │  /api/clusters   → routes/clusters.js│   │
  │  GPU Node    │                            │  /api/jobs       → routes/jobs.js    │   │
  └──────┬───────┘                            │  /api/tenants    → routes/tenants.js   │   │
         │ Metrics                            │  /api/billing    → routes/billing.js   │   │
         │ (util/temp/power)                   │  /api/alerts    → routes/alerts.js    │   │
         └────────────────────────────────────│  /api/dashboard → routes/dashboard.js│   │
                                             │  /api/scheduler → routes/scheduler.js│   │
  ┌──────────────┐                            │  /api/api-keys  → routes/api-keys.js   │   │
  │ Browser /   │  GET /admin  → admin.html   │  /api/demo      → routes/demo.js     │   │
  │ Web Client  │  GET /dashboard → tenant.html│  /api/analytics → routes/analytics.js│  │
  │              │  GET /login  → login.html  │                                       │   │
  └──────┬───────┘  REST API calls            └───────────────────────────────────────┘   │
         │                                    │            │                             │
         │                                    │            │                             │
         │                             ┌──────▼──────┐  ┌───▼──────────────────────────┐
         │                             │ PostgreSQL  │  │  Job Scheduling Daemon        │
         │                             │   (Neon)    │  │  (30s polling, guarded cron)  │
         │                             │             │  │  jobs/scheduler-cycle.js      │
         │                             │  clusters   │  └─────────────────────────────┘
         │                             │  nodes      │
         │                             │  gpus       │
         │                             │  gpu_metrics│
         │                             │  jobs       │
         │                             │  tenants    │
         │                             │  usage_events│
         │                             │  invoices   │
         │                             │  alert_rules│
         │                             │  alert_events│
         │                             │  api_keys   │
         │                             │  scheduler_logs│
         │                             └─────────────┘
         │
         │  External Integrations:
         │  ├─ Stripe (payment links via Polsia Stripe proxy)
         │  ├─ Polsia Email (alert notifications)
         │  └─ Google Analytics 4 (client-side page views)

  ┌──────────────┐                            ┌──────────────────────────────────────┐
  │ Admin Plane │                            │  Customer Plane                       │
  │   /admin    │                            │     /dashboard  /customer             │
  │ Fleet View  │                            │  My GPU Allocations                   │
  │ Tenant Mgmt │                            │  My Notebooks                         │
  │ Scheduling  │                            │  My AI Pods                           │
  │ Alerts      │                            │  My Billing                           │
  └─────────────┘                            └──────────────────────────────────────┘

Two Dashboard Planes

┌─────────────────────────────────────────────────────┐
│              GPUForge Deployment                     │
│                                                     │
│  ┌───────────────────────────────────────────────┐  │
│  │          Admin Dashboard  (/admin)            │  │
│  │                                               │  │
│  │  [Fleet Overview]                             │  │
│  │  [Cluster Config]   ← Operator sees          │  │
│  │  [Tenant Mgmt]         everything             │  │
│  │  [Scheduling Ctrl]                            │  │
│  │  [Revenue/Billing]                             │  │
│  │  [Alert Mgmt]                                 │  │
│  └───────────────────────────────────────────────┘  │
│                       │                             │
│          ┌────────────┼────────────┐                │
│          ▼            ▼            ▼                │
│  ┌──────────────┐ ┌──────────┐ ┌────────────┐      │
│  │ Tenant A     │ │ Tenant B │ │ Tenant C   │      │
│  │ /dashboard   │ │ /dashboard│ │ /dashboard │      │
│  │              │ │          │ │            │      │
│  │ My GPUs      │ │ My GPUs  │ │ My GPUs    │      │
│  │ My Jobs      │ │ My Jobs  │ │ My Jobs    │      │
│  │ My Billing   │ │ My Billing│ │ My Billing │      │
│  └──────────────┘ └──────────┘ └────────────┘      │
└─────────────────────────────────────────────────────┘

Data Flow Diagrams

Login Flow → Role Routing → Dashboard

User navigates to /admin or /dashboard
         │
         ▼
   [Login Page]  /login
         │
         ├─ Admin login → session set (localStorage) → redirect /admin
         └─ Tenant login → session set (localStorage) → redirect /dashboard
         │
         ▼
   SPA loads, reads localStorage session token
         │
         ▼
   SPA calls GET /api/dashboard
         │
         ▼
   Express middleware (apiKeyAuth)
         │
         ├─ No Authorization header → Demo mode: serves all data (no auth gate)
         ├─ Valid Bearer key → lookupApiKey() → attach req.apiKey → next()
         └─ Invalid/revoked → 401 error response
         │
         ▼
   Route handler executes (e.g. GET /api/dashboard)
         │
         ▼
   db/ query functions (db/dashboard.js, db/clusters.js, etc.)
         │
         ▼
   pool.query() against Neon PostgreSQL
         │
         ▼
   JSON response returned to SPA
         │
         ▼
   SPA updates DOM (charts, tables, status cards)

Job Lifecycle Flow

1. SUBMIT
   POST /api/jobs { cluster_id, name, gpu_count, gpu_type, priority, tenant_id }
        │
        ▼
   Inline quota check (routes/jobs.js):
     SELECT gpu_quota FROM tenants WHERE id = tenant_id
     SELECT SUM(gpu_count) FROM jobs WHERE tenant_id = X AND status = 'running'
        │
        ├─ If current + requested > quota → job status = 'blocked', block_reason set
        ├─ If cluster idle_gpus < requested → job status = 'blocked', block_reason set
        └─ Otherwise → job status = 'queued'
        │
        ▼
   INSERT INTO jobs (...)

2. SCHEDULE (every 30s)
   Scheduler daemon runs runSchedulerCycle()
        │
        ▼
   SELECT idle GPUs: SELECT * FROM gpus WHERE status = 'idle' FOR UPDATE SKIP LOCKED
        │
        ▼
   SELECT queued jobs: SELECT * FROM jobs WHERE status = 'queued' ORDER BY priority ASC
        │
        ▼
   For each job:
     Check: tenant.gpu_in_use + job.gpu_count <= tenant.gpu_quota
        │
        ├─ YES → Assign N idle GPUs (set gpus.job_id, gpus.status = 'active')
                   Update job.status = 'running'
        └─ NO  → Leave as queued (or 'blocked' if quota was reason)
        │
        ▼
   INSERT INTO scheduler_logs (cycle_summary)
   INSERT INTO usage_events (for completed jobs: gpu_hours × rate)

3. COMPLETE
   PATCH /api/jobs/:id { status: 'completed' }
        │
        ▼
   Free allocated GPUs: UPDATE gpus SET job_id = NULL, status = 'idle'
   Emit usage_event: INSERT INTO usage_events (tenant, gpu_type, gpu_hours, cost)

Metrics Ingestion Flow

GPU Node agent runs on hardware, posts metrics every 60s:

   POST /api/clusters/metrics
   Authorization: Bearer gf_<cluster_api_key>
   Body: { metrics: [{ gpu_id, utilization_pct, memory_used_mb,
                       memory_total_mb, temperature_c, power_draw_w }, ...] }
        │
        ▼
   apiKeyAuth middleware validates cluster API key
        │
        ▼
   Bulk INSERT INTO gpu_metrics (recorded_at = NOW())
        │
        ▼
   For each GPU in payload:
     UPDATE gpus SET status =
       CASE WHEN utilization_pct > 10 THEN 'active' ELSE 'idle' END
       WHERE id = gpu_id
        │
        ▼
   Alert engine evaluates rules (every 30s):
     idle_gpu rule: COUNT(idle gpus) / total_gpus > threshold?
     health_degraded rule: temperature_c > 90 OR node unreachable?
        │
        ├─ Threshold crossed → INSERT INTO alert_events
        └─ notification_enabled → Polsia email proxy fires alert email

Billing Flow

1. USAGE CAPTURE (scheduler emits on job completion)
   INSERT INTO usage_events (tenant_id, gpu_type, gpu_hours, cost)
        │
        ▼
2. INVOICE GENERATION
   POST /api/tenants/:id/invoice  (or POST /api/billing/invoice/:tenantId)
        │
        ▼
   Aggregate usage_events for tenant (last billing period)
   Calculate: SUM(gpu_hours × rate) = total_amount
        │
        ▼
   Polsia Stripe proxy → create Stripe payment link
   INSERT INTO invoices (tenant_id, amount, status = 'pending', stripe_payment_url)
        │
        ▼
3. PAYMENT
   Tenant clicks Stripe payment link → pays on Stripe.com
   Polsia Stripe proxy → webhook / confirmation
   UPDATE invoices SET status = 'paid' WHERE id = invoice_id
        │
        ▼
4. RECONCILIATION
   GET /api/billing/summary → operator sees: revenue, outstanding, paid invoices
   GET /api/tenants/:id/invoices → tenant sees payment history

Database Schema

Neon PostgreSQL. All DDL in migrations/. Named query functions in db/<entity>.js. Only db/index.js constructs new Pool().

Entity-Relationship Summary

clusters ────────── 1:N ────────── nodes
   │                                  │
   │                                  1:N
   │                                  │
   └──── 1:N ────────── gpus ◄────────┘
                             │
                             │ N:1
                             │
                ┌────────────┼────────────┐
                ▼            ▼            ▼
             jobs         gpu_metrics   api_keys
                │                           │
                │ N:1                       │ N:1
                ▼                           ▼
             tenants ◄────────────────── tenants
                │
                │ 1:N
                ▼
           usage_events ──N:1── invoices
                │
                │ 1:N (via tenant)
                ▼
            alert_events ◄──N:1── alert_rules

Supporting: scheduler_logs, early_access_signups,
             page_views, demo_requests

Core Tables

TableKey ColumnsPurpose
clustersid, name, region, api_key, status, created_atGPU cluster registry
nodesid, cluster_id, hostname, ip_address, total_gpus, status, cpu_cores, ram_gbCompute nodes within clusters
gpusid, node_id, gpu_index, model, vram_mb, status, job_idIndividual GPUs; job_id tracks current assignment
gpu_metricsid, gpu_id, utilization_pct, memory_used_mb, memory_total_mb, temperature_c, power_draw_w, recorded_atTime-series GPU telemetry
jobsid, cluster_id, tenant_id, name, gpu_count, gpu_type, priority, status, block_reason, submitted_at, started_at, completed_atGPU workload queue
tenantsid, name, contact_email, plan_tier, gpu_quota, statusMulti-tenant orgs with GPU quota limits
gpu_ratesid, gpu_type, rate_per_hourRate card for billing (e.g. H100 = $3.50/hr)
usage_eventsid, tenant_id, gpu_type, gpu_hours, cost, recorded_atImmutable billing log
invoicesid, tenant_id, amount, status, stripe_payment_url, created_at, paid_atStripe-linked billing records
alert_rulesid, rule_type, threshold, enabled, notification_enabled, created_atConfigurable fleet alert thresholds
alert_eventsid, rule_id, cluster_id, details (JSONB), fired_at, resolved_atFired alert instances
api_keysid, key_hash (SHA-256), key_prefix, tenant_id, permissions, created_at, revoked_atAPI key registry with SHA-256 hashed storage
scheduler_logsid, cycle_at, jobs_evaluated, jobs_started, jobs_blocked, gpu_assigned_countScheduler cycle audit trail

See LLD for full schema with all columns, types, constraints, and indexes.


Technology Stack

Backend

ComponentTechnologyVersionPurpose
RuntimeNode.js18.x (.nvmrc)JavaScript runtime
FrameworkExpress.js4.xHTTP server, routing, middleware
DatabasePostgreSQL (Neon)15+Primary data store
DB Clientpg (node-postgres)8.xPostgreSQL driver with connection pooling
Migrationsnode-pg-migrate6.xDeclarative SQL migrations
SchedulersetInterval (built-in)30s job scheduler (guarded)

Frontend

ComponentTechnologyPurpose
TemplatesEJSServer-rendered HTML pages
Static SPAVanilla JS + HTML/CSSDashboard: admin.html, tenant.html, login.html
StylingCustom CSS (Space Grotesk + JetBrains Mono fonts)Dark-theme GPU operator aesthetic
ChartsChart.js (CDN)Revenue, utilization, allocation charts
AnalyticsGA4 (client-side)Page views, signup events, scroll depth

Infrastructure & Deployment

ComponentTechnologyPurpose
HostingRenderWeb service (Node.js), auto-deploy from GitHub
DatabaseNeon (Managed PostgreSQL)Branched dev DB, production DB, connection pooling
CI/CDGitHub + Render auto-deployPush to main → deploy to Render
File StoragePolsia R2Image assets, generated files
PaymentsPolsia Stripe ProxyPayment links without key management
EmailPolsia Email ProxyAlert notifications, demo request emails

Project Structure

gpuforge/
├── server.js              # Entry point (172 lines — wiring only)
├── routes/
│   ├── clusters.js        # Cluster, node, GPU registry + metrics
│   ├── jobs.js            # Job submission + status update
│   ├── tenants.js         # Tenant CRUD + usage queries
│   ├── billing.js         # Invoice management + billing KPIs
│   ├── alerts.js          # Alert rules + event queries
│   ├── dashboard.js       # KPI aggregates, analytics
│   ├── api-keys.js        # Key generation + revocation
│   ├── scheduler.js       # Scheduler cycle trigger + logs
│   ├── analytics.js       # Page view stats
│   ├── demo.js            # Demo mode provisioning
│   ├── demo-requests.js   # Demo request form handler
│   └── misc.js            # GPU rates, early access signup
├── db/
│   ├── index.js           # new Pool() — only DB access point
│   ├── clusters.js        # Named query functions
│   ├── jobs.js
│   ├── tenants.js
│   ├── billing.js
│   ├── alerts.js
│   ├── dashboard.js
│   ├── api-keys.js        # SHA-256 key hashing + lookup
│   ├── analytics.js
│   ├── auth.js            # API key lookup + touchLastUsed
│   └── demo-requests.js
├── public/
│   ├── index.html         # Landing page
│   ├── admin.html         # Admin SPA
│   ├── tenant.html        # Customer SPA
│   ├── login.html         # Auth page
│   ├── pitch.html         # Pitch one-pager
│   ├── docs-hld.html      # This document
│   ├── docs-lld.html      # Low-Level Design
│   ├── docs-arch.html     # Architecture deep-dive
│   ├── docs.html          # API reference
│   ├── docs-hub.html      # Docs hub page
│   └── use-cases/         # SEO landing pages
├── migrations/             # node-pg-migrate SQL files
├── jobs/
│   └── scheduler-cycle.js  # Standalone scheduler runner
├── migrate.js             # Migration runner (npm run migrate)
├── polsia.toml            # Cron declarations for Blaxel
└── render.yaml            # Render service config

Non-Functional Requirements

Performance Targets

MetricTargetCurrentMeasurement
API Response Time (p95)< 200ms~80ms avgRender latency logs
Dashboard Load< 1.5s~900msBrowser performance
Scheduler Cycle Duration< 2s for 500 jobs~400ms for 50 jobsscheduler_logs.cycle_duration_ms
DB Query Time (p99)< 100ms~25ms avgNeon console
Concurrent Connections50+ simultaneousPool limit: 10pg Pool config
Metrics Ingestion1,000 GPU metrics/minTested at 500/minLoad test

Security Model

Current (v1): Mock auth with localStorage session tokens. API keys stored as SHA-256 hashes (bcrypt-ready). No production auth integration yet.

Production auth roadmap: SSO/SAML for operator accounts, JWT-based tenant auth, RBAC with per-tenant permission scoping, OAuth2 integration for cloud provider credentials.

SurfaceCurrentTarget
Dashboard authlocalStorage session (mock)JWT + SSO / SAML
API key storageSHA-256 hashed (bcrypt-ready)Argon2 / bcrypt
SQL injectionParameterized queries onlyContinue — no inline SQL
XSSEJS auto-escapes; client JS sanitizesContinue + CSP headers
Rate limitingNone (v1)per-tenant rate limits
Audit logsscheduler_logs + page_viewsFull access log per entity

Scalability Approach

Single-web-service architecture on Render. Scales horizontally via Render auto-scaling (CPU-based). Key design decisions for scale:

  • Connection pooling: pg Pool (10 connections) shared across all route handlers. Neon handles branching and pooling at the DB layer.
  • Scheduler distribution: The 30s scheduler runs in-process. For multi-instance deployment, FOR UPDATE SKIP LOCKED prevents duplicate GPU assignments. Blaxel will handle cron distribution.
  • Metrics ingestion: Bulk INSERT (INSERT ... ON CONFLICT DO UPDATE) for GPU metrics — single round-trip per batch.
  • Read scaling: Neon read replica endpoint available for read-heavy dashboards.
  • Horizontal scale ceiling: Current architecture supports ~50 concurrent operators, ~200 tenants, ~10,000 GPUs per instance before needing a service split.

Availability & Reliability

ConcernMitigation
Render instance crashAuto-restart via Render; stateless Express app recovers cleanly
Database connection droppg Pool auto-reconnect; Neon connection pooler handles transient failures
Scheduler missed cycleEach cycle logs to scheduler_logs; Blaxel cron ensures no missed cycles
Alert notification failureAlert events stored in DB regardless; notification is best-effort
Stripe webhook missInvoice status update on payment link open; webhook confirmation on return

Deployment Architecture

Deploy Pipeline

Developer pushes to GitHub (Polsia-Inc/gpuforge)
         │
         ▼
   GitHub webhook → Render auto-deploy trigger
         │
         ▼
   Render Build:
     1. npm install
     2. npm run migrate   ← runs migrate.js against Neon DB
     3. npm start         ← starts server.js
         │
         ▼
   Render starts Express on PORT (set by Render)
   Health check: GET /health → { status: 'ok' }
         │
         ▼
   Blaxel shadow receives same deploy
   Blaxel sets POLSIA_IN_PROCESS_CRONS_ENABLED = false
   Blaxel syncs [[crons]] from polsia.toml
         │
         ▼
   Live at https://gpuforge.polsia.app
         │
         ▼
   Ongoing: every push to main triggers re-deploy

Render Web Service

SettingValueNotes
Start Commandnpm run migrate && npm startRuns migrations before starting server
Health CheckGET /healthReturns { status: 'ok' } — Render probes this every 30s
EnvironmentDATABASE_URL, PORT, POLSIA_IN_PROCESS_CRONS_ENABLED=trueNeon connection string + cron guard
Instance TypeRender Starter (can upgrade)512MB RAM, shared CPU

Neon Managed PostgreSQL

FeatureValueNotes
ConnectionDATABASE_URL env varConnection pooler included — no manual pooling needed
BranchingDev branches from mainSafe dev testing without touching production data
Schema managementnode-pg-migrate migrationsAll DDL in migrations/ directory, named timestamp files
Connection limit60 (Neon Pro plan)pg Pool uses 10; sufficient headroom for concurrent requests

CI/CD via Polsia

Polsia's infra pipeline manages the full delivery flow:

  • GitHub integration: Repo provisioned and connected to Render auto-deploy
  • Render management: Service creation, env var management, log access via polsia_infra MCP
  • Database provisioning: Neon database created and linked on first provision
  • Shadow deployment: Blaxel shadow receives every deploy for pre-production validation
  • Cron sync: polsia.toml [[crons]] entries synced to Blaxel as disabled triggers

Integration Points

Stripe Billing

Integration: Polsia Stripe proxy — no Stripe keys on GPUForge. All payment link creation goes through https://polsia.com/api/proxy/stripe/payment-link.

Flow: POST /api/tenants/:id/invoice → aggregates usage events → calls Polsia Stripe proxy → receives payment URL → stores in invoices.stripe_payment_url → tenant receives link, pays on Stripe → webhook confirms → invoice marked paid.

Future: Subscription billing (monthly plans), usage-based billing (auto-invoice monthly), webhook retry handling.

API Key Management

Storage: Full key hashed with SHA-256 before storage. Only 12-char prefix shown in UI. Full key shown once at creation, stored by user.

Endpoints: POST /api/api-keys (generate), GET /api/api-keys (list), DELETE /api/api-keys/:id (revoke), GET /api/api-keys/demo (get demo key for testing).

Auth middleware: Validates Authorization: Bearer <key> header against api_keys.key_hash. Revoked keys (revoked_at IS NOT NULL) return 401. Last used timestamp updated on every valid call.

Kubernetes / SLURM Integration (Future)

Integration point 1 — Kubernetes: GPU operators running k8s clusters can deploy a GPUForge node agent as a DaemonSet. The agent registers nodes and posts metrics via POST /api/clusters/nodes and POST /api/clusters/metrics. The scheduler daemon then orchestrates GPU allocation across the k8s cluster via the same job assignment API.

Integration point 2 — SLURM: On-premise HPC clusters running SLURM can integrate via a GPUForge SLURM plugin that translates SLURM job events into GPUForge job records. GPU allocation data flows back to SLURM via the node agent.

Integration point 3 — Ray / vLLM: Ray clusters and vLLM inference servers can register with GPUForge as special cluster types. GPUForge treats them as managed GPU pools with pre-assigned capacity.

Polsia Platform Integrations

ServicePolsia EndpointUsage in GPUForge
Stripepolsia.com/api/proxy/stripe/payment-linkInvoice payment links
Emailpolsia.com/api/proxy/email/sendAlert notifications, demo request emails
R2 StoragePOLSIA_R2_BASE_URLImage uploads, generated assets
Twitter/XShared @polsia accountMarketing posts (2/day limit)
Agent SDK.claude/skills/agent-sdk/SKILL.mdAutonomous agent features (agentic workflows)

Glossary

TermDefinition
GPU QuotaMaximum GPUs a tenant can consume simultaneously across all their running jobs.
GPU AllocationThe specific GPUs assigned to a running job. Tracked in gpus.job_id.
Blocked JobA queued job that cannot start because capacity or quota is insufficient. Shows block_reason.
Revenue LeakageGPU time consumed but not billed — either idle allocated GPUs or unmetered compute. Detected via GET /api/dashboard/leakage.
Scheduler CycleOne iteration of the 30-second scheduler — evaluates all queued jobs and assigns available GPUs. Logged to scheduler_logs.
MIGMulti-Instance GPU — NVIDIA A100 GPU virtualization allowing fractional GPU slices per tenant.
API Key PrefixFirst 12 characters of an API key shown in the UI. The full key is shown once at creation and never stored in plaintext.
FOR UPDATE SKIP LOCKEDPostgreSQL row-level locking option that makes concurrent scheduler runs skip already-assigned GPUs instead of waiting.
GPUaaSGPU-as-a-Service — the core infrastructure layer managing GPU fleet lifecycle.
Blaxel ShadowGPUForge's shadow deployment on Blaxel. Receives every deploy for pre-production validation. Scheduler disabled via POLSIA_IN_PROCESS_CRONS_ENABLED=false.
NeonManaged PostgreSQL cloud database with serverless branching and built-in connection pooling.

Related Documents

DocumentURLScope
Low-Level Design (LLD)/docs/lldFull database schema (16 tables), ER diagram, state machines, all API endpoint specs with request/response schemas, module-level design, security model
Architecture Deep-Dive/docs/architectureSystem-level architecture decisions, scaling considerations, technology choices with rationale
API Reference/docsInteractive endpoint documentation with curl examples and response schemas
Docs Hub/docs/hubCard-based navigation to all documentation pages
CLAUDE.md/gpuforge/CLAUDE.mdInternal developer reference: stack, directory map, database tables, external integrations, recent changes