Climb Intel — System Architecture
AI Kilter-board grading + movement coaching · PWA + Flask + PostgreSQL + ML ensemble

Climb Intel is a three-tier web application: a multi-page progressive web app (PWA) front end, a Flask REST API, and a data/ML layer that grades climbing routes and coaches movement from video. This document maps the structure top-down — the tiers, the front-end component tree, the API surface, the data model, and the machine-learning pipeline.

01System Overview

Every request flows browser → API → data. The front end is static HTML/CSS/JS served by Flask; all dynamic data comes from JSON endpoints. Deployed on Railway; the live site is climbintel.com.

Tier 1 — Client (PWA)
23 HTML pagesshared shell.js 31 JS modulesstyles.css (themes) Service Worker / offlineMediaPipe-fed pose UI
▼   HTTPS · JSON / multipart (video)   ▼
Tier 2 — Flask API (api/app.py)
13 blueprints authsocialclimber routesboardpredict posestatsbilling admintelemetry
▼   SQL · model inference · pose extraction   ▼
Tier 3 — Data & ML
PostgreSQL SQLite (board geometry) XGBoost + LightGBM ensemble MediaPipe pose Stripe (billing)

Tech at a glance

Front end
Vanilla JS (no framework), one shared shell, theme system, PWA + service worker. Pages are real navigations, not a SPA.
API
Flask + blueprints, psycopg2 connection pool, bcrypt auth, Google OAuth, Stripe checkout.
ML
Stacked XGBoost + LightGBM → Ridge meta-learner → isotonic calibration. 72.8% within-1 grade.

02Front-End Architecture

The app was split from one monolith (index.html, still served at /app as a fallback) into focused pages that all share one shell. js/shell.js injects the intro loader, top nav, mobile bottom tab bar, auth modal, command palette (⌘K), and cross-page navigation into every page — so a page only supplies its own content + a bootstrap.

Component nesting

shell.js (shared on every app page) ├─ intro loader (once per session) ├─ top nav → tabs + "More ▾" dropdown + account ├─ mobile bottom tab bar (phones, ≤720px) ├─ auth modal (login / signup / Google) ├─ command palette (⌘K) + keyboard shortcuts └─ switchTab() → real page navigation PAGES (each = HTML content + a *-page.js bootstrap) ├─ home · explore · create · profile · friends ├─ video-analysis (Coach) · train · circuits ├─ discover · for-you · insights · leaderboard ├─ settings · welcome · climber (public) · route └─ landing · process (marketing, own CSS) FEATURE MODULES (js/, loaded as needed) ├─ board.js · explore.js · creator.js board + grading UI ├─ pose-player/animator · physics-animator beta playback ├─ profile.js · session.js · friends.js user data + social ├─ auth.js · billing.js · themes.js account + theme └─ board-zoom · config · telemetry shared utilities

State & portability

Working state lives in localStorage (the synchronous UI cache); when signed in it mirrors to the server so a profile follows the account across devices. On login the full profile (body stats, onsight, theme, saved routes, circuits) hydrates from the API; on signup the guest's local data is pushed up.

guest localStoragesign inhydrate from APImirror changes backportable

03Back-End Architecture

api/app.py creates the Flask app, opens a PostgreSQL connection pool (api/db.py), and registers 13 blueprints. A catch-all route serves the static HTML pages, so new pages need no routing changes.

Blueprints (API surface)

BlueprintOwnsRepresentative endpoints
authAccounts, OAuth, profile/api/auth/signup · /login · /oauth · /profile/<id>
socialFriends, feed, collections/api/social/* · /api/profile/collections/<id>
climberBody profile, recs/api/climber/profile · /recommendations · /benchmarks
routesRoute list + detail/api/routes · /api/route/<id>
boardBoard geometry (holds)/api/boards · /api/board
predictLive grade prediction/api/predict · /api/auto_generate
poseVideo upload + coaching/api/pose/upload · /session/<id> · /my-videos
statsCorpus stats, config/api/stats · /api/config
billingStripe checkout (gated)/api/billing/checkout · /webhook · /status
admin · telemetrySignups dashboard, events/api/admin/signups · /api/telemetry

Request flow — predict a grade

Create boardPOST /api/predict {holds, angle, profile}ml_engine.compute_features()ensemble inferenceisotonic calibration{grade, confidence, DNA, style tags}UI

Request flow — coach a video

Upload clip (multipart)background workerMediaPipe pose framesvideo_coach.analyse_attempt()insights + predicted gradepoll /session/<id>UI

04Data Model

PostgreSQL holds all user + route + pose data; a slim SQLite DB holds the physical Kilter board layout (hold positions per size). Key tables and how they nest:

climber_profiles (account root)
id (uuid) · email · password_hash · display_name · username · bio · height_cm · wingspan_cm · weight_kg · experience_yrs · onsight_grade · color_profile · oauth_* · plan
route_sends
climber_id → route_id · attempts · route_grade · sent_at (feeds the feed + pyramid)
user_collections
climber_id · saved_routes (jsonb) · circuits (jsonb) (portable)
friendships
requester_id · addressee_id · status (pending/accepted)
board_routes / route_holds
route + its lit holds (position, role, hold_type, sequence) · community_grade · difficulty_score
video_upload_sessions / pose_frames
upload → extracted per-frame pose metrics (tension, hip angle, reach, COM) → coaching_insights

Nested object — a climber profile as the app sees it

climber { id, display_name, email, body: { height_cm, wingspan_cm, weight_kg, ape_index, bmi }, climbing: { onsight_grade, experience_yrs, move_affinities[] }, settings: { color_profile, units }, collections: { saved_routes[], circuits[] }, social: { friends[], pending_requests[], feed[] }, activity: { sessions[] (local), route_sends[] (server) } }

05Machine-Learning Pipeline

Grading is a stacked, calibrated ensemble trained on ~137K graded routes (357K augmented rows) with 86 geometric + interaction + hold-quality + pose features. The pipeline both trains offline and serves the identical feature computation at request time.

route holds + anglefeature_extraction (86 feats)XGBoost + LightGBMRidge meta-learnerisotonic calibrationgrade + q10/q90 bands
Top features (XGBoost gain)
board angle · angle × reach · hold density · angle × dyno · total holds · avg reach. Angle and its interactions dominate.
Accuracy (frozen holdout)
72.8% within ±1 V-grade · ~90% within ±2 · 28.9% exact. Strongest at core grades V4–V6; V9+ is the data-scarce frontier.
Pose / video coaching
MediaPipe → per-frame body metrics → benchmarked against per-grade medians → tension / hip / reach / footwork insights + drills.
Personalization (PDScore)
Body dims + logged sends adjust difficulty to the individual — the same route is graded differently for different bodies.
Climb Intel · system architectureclimbintel.com