Work
Fitness LIVE IN PRODUCTION AT TRAINWITHRUBICON.COM

A hybrid strength platform that puts Westside Conjugate and CrossFit on one screen

We built the athlete app and coach back office for Rubicon, then put it on a VPS we run. Daily training tracks, Conjugate strength tiers, courses, a movement library, and a logbook, all under one login.

2user worlds, one platform: athlete app + coach back office
Book a call Visit it live

The problem

Rubicon coaches Adam McAdams and Jesse Bifano run a hybrid method most platforms cannot model: Westside Barbell Conjugate strength work (Max Effort, Dynamic Effort, Repetition Effort) sitting next to CrossFit conditioning. Off-the-shelf gym apps treat a workout as one flat block of text, so the structure that makes Conjugate work (speed primers, primary and secondary strength tiers, hypertrophy, finishers, velocity targets, RPE) just disappears. Athletes got spreadsheets and SugarWOD exports. Coaches had no single place to publish daily programming, sell programs, teach the method, and talk to athletes. They needed a real product, not a stack of tools taped together.

What we built

The modules of the system.

01

Daily Training Tracks

Calendar-based programming that never ends. Athletes open the track calendar, see today's session, and log it. Each session carries a day type, time cap, intensity level, and week number so a coach can run structured cycles inside an ongoing track. Built on Track, TrackSession, and ExerciseBlock models with a subscription tied to each track.

02

Conjugate Strength Tiers

The method is modeled into the data, not pasted into a notes field. Every exercise block has a tier (Speed Primer, Tier 2 primary strength, Tier 3 secondary, Tier 4 hypertrophy, Tier 5 finisher, plus core, conditioning, metcon, skill) and a Conjugate type (Max Effort, Dynamic Effort, Repetition Effort). Blocks can carry velocity targets, stop thresholds, RPE, supersets, and total reps. That structure renders the same way the coach wrote it.

03

Fixed-Length Programs

Where tracks run forever, programs are finite cycles: Base GPP, Conjugate, and Competitor. Modeled as Program to ProgramWeek to ProgramDay to ExerciseBlock, with enrollment and per-day logs. Athletes enroll, work Week 1 to Week X, and the coach builds them in an admin program builder.

04

Movement Library

A searchable exercise database with categories, body parts, exercise type, and Conjugate classification. Each movement gets its own detail page with coaching cues and video, and program blocks link to it so an athlete can tap a lift and learn how to do it.

05

Courses

Educational video content modeled as Course to CourseModule to CourseLesson, with enrollment, per-lesson progress tracking, and a lesson player. This is how Rubicon teaches the why behind the method, not just the what of today's session.

06

Performance Logbook

Athletes log results against movements and benchmarks, mark PRs, and watch progress over time. Log entries are typed (workout, benchmark, PR, note) and a SugarWOD CSV importer pulls years of prior history in so nobody starts from an empty page.

07

Coach Back Office

A full admin side: athlete CRM with profiles and notes, content builders for tracks, programs, movements, courses, and the blog, a communication hub, email broadcasts, a subscriber list with a launch waitlist, analytics, and a reports hub. The coach runs the whole business from here.

How it fits together

Two front doors share one brain. The public marketing site (landing, programs, about, blog, sample week) and the authenticated app are one React 19 plus Vite plus TypeScript build with 80-plus routes, split by role into ATHLETE, COACH, and ADMIN views. Behind it is a NestJS plus Prisma plus PostgreSQL backend with around 20 feature modules: auth, athletes, tracks, programs, movements, courses, logbook, messages, subscriptions, subscribers, blog, notifications, reports, search, uploads, and admin. Auth is a custom dual-token JWT setup (short-lived access token, 7-day refresh, auto-refresh on 401) with email verification and password reset through SendGrid. Real-time coach-to-athlete chat runs over a Socket.io gateway that authenticates the socket with the same JWT. Billing is Stripe, with FREE, BASIC, PREMIUM, and ELITE tiers gating content. There is also an Admin API with key-based auth and a self-describing schema endpoint so content can be managed programmatically. The whole thing runs on a DigitalOcean VPS we operate: PostgreSQL 16, PM2 for process management, and Nginx as the reverse proxy, with separate production and dev instances on the same box. We build it, then we run it.

React 19TypeScriptViteTailwind CSSReact Router v6NestJSPrisma ORMPostgreSQL 16JWT authSocket.ioStripeSendGridDigitalOcean VPSPM2Nginx

Under the hood

The decisions that mattered.

We taught the database what Conjugate actually is

The hardest part was not the UI, it was refusing to flatten the method. A Conjugate session is not one block, it is a sequence of tiers with different intent: a speed primer to fire up the nervous system, a primary strength lift (Tier 2), secondary variations (Tier 3), hypertrophy volume (Tier 4), a finisher (Tier 5), then core and conditioning. So we put that vocabulary in the schema. The ExerciseBlock model carries a tier enum and a Conjugate type (Max, Dynamic, Repetition Effort), plus velocity targets, stop thresholds, RPE, superset groups, and total reps. A dedicated migration added all of it at once. The payoff: a coach writes a session the way they think about it, and it renders that way for the athlete, with structure intact instead of mashed into a paragraph.

Tracks and programs are different on purpose

A lot of platforms blur ongoing programming and fixed cycles. We kept them separate because they behave differently. Tracks are calendar-based and never-ending: athletes subscribe and get today's session forever, and TrackSession carries day type, time cap, intensity, and week number so a coach can still run cycles inside an open-ended track. Programs are finite: Program to ProgramWeek to ProgramDay, enrolled Week 1 to Week X with per-day logs and a clear finish line. Two data shapes, two builders, two athlete experiences. That distinction is written into the contributor guide so it never drifts.

Years of history imported, not abandoned

Rubicon athletes had a training past living in SugarWOD. Telling them to start over would have made the new platform feel worse than a spreadsheet. So we built a SugarWOD CSV importer that parses each row (date, title, score type, set details JSON, RX or scaled, PR flag) and maps loads, reps, rounds, times, and points into typed log entries. New athletes land in the logbook with their real PR history already there. The platform earns trust on day one instead of asking for patience.

A back office a coach can actually run a business from

The athlete app is the visible half; the coach side is where the work lives. Adam and Jesse get an athlete CRM with profiles and notes, builders for every content type (tracks, programs, movements, courses, blog), real-time messaging over a JWT-authenticated Socket.io gateway, branded transactional and broadcast email through SendGrid (verification, reset, waitlist, broadcasts) on an authenticated sending domain, a subscriber list that captured a pre-launch waitlist, plus analytics and reports. There is even an Admin API with a self-describing schema endpoint so content can be pushed in programmatically. They are not stitching five SaaS tools together; they run the whole operation from one login.

Release log

What we shipped.

Jan 2026

Backend stood up: NestJS plus Prisma initial schema migration, auth, and the core Program, Track, Movement, Course, and LogEntry models.

Jan 2026

Conjugate goes deep into the data: migration adds exercise tiers, Conjugate effort types, VBT velocity targets, stop thresholds, RPE, supersets, and metcon and skill tiers.

Jan 2026

SugarWOD CSV importer ships so athletes bring their full training history into the logbook.

Feb 2026

Soft-launch prep: new wordmark logo, content passes on landing, programs, and about, branded SendGrid email on an authenticated domain, and a launch waitlist with a reusable signup form.

2026

Live in production at trainwithrubicon.com on a DigitalOcean VPS we run (PostgreSQL 16, PM2, Nginx), with separate prod and dev instances.

The outcome

Rubicon went from spreadsheets and SugarWOD exports to a single platform that fits the way they actually coach. The Conjugate method renders with its real structure, athletes train from a daily calendar with their history already imported, and Adam and Jesse run programming, courses, the CRM, messaging, billing, and email from one back office. It is live at trainwithrubicon.com, and we operate the VPS it runs on so the coaches can focus on coaching instead of servers.

Put your business on autopilot