james l@ngridge

👋 Hi.

I'm James, a full-stack software engineer with an unorthodox, self-taught background and over 5 years of experience, working at Orbit Software Laboratories since August 2023.

I've worked for established, multinational enterprises, and small, agile startups, in fully product-driven roles as well as client-focused roles, including:

I also run a lot, juggle (knives, fire, whatever), and skateboard.

You can browse some notable projects I've worked on below, view or download my full CV, and see all my open source work on GitHub.

Scalable serverless platform using webhooks and OAuth 2.0 to seamlessly integrate real-time weather data into Strava activities, built with TypeScript, Express, and React.

I built a full-stack application that automatically enriches Strava activities with real-time weather data using webhooks for immediate processing. The project features a TypeScript Express.js API with PostgreSQL/Prisma for data persistence, React SPA for user management, OAuth 2.0 authentication flow, and integrations with both Strava and OpenWeatherMap APIs. Deployed as a single Vercel application with the Express API running as a serverless function and React frontend as static assets, the system is architected for scale with stateless serverless architecture, PostgreSQL with optimized indexes, webhook-based processing, 30-minute weather data caching, graceful handling of external API rate limits, and automated token refresh - a design that would support thousands of concurrent users without architectural changes.

Strava Weather UI

Architecture & Technical Implementation

The application follows a microservices-inspired architecture with clear separation of concerns. The backend API is built with Express.js and structured into distinct service layers - each service handles a specific domain (Strava API, weather data, webhook management, authentication). I implemented a robust middleware pipeline including request logging with correlation IDs, and comprehensive error handling with custom error types. The Prisma ORM provides type-safe database access with automatic migrations, while the schema design supports future features through a preferences table and efficient indexing strategies.

Real-time Processing & Performance Optimization

The webhook handler implements retry logic with linear backoff (1.5s, 3s) rather than exponential, optimizing for Vercel's 10-second function limit while handling Strava's eventual consistency. This gives three full attempts within the time constraint, as activities typically become available within 2-3 seconds of creation, and always returns success to prevent Strava's retry queue from causing duplicates. I built a weather caching system with 30-minute TTLs and location-based keys rounded to 4 decimal places (~11m precision) to minimize API calls while maintaining accuracy.

Webhook sequence diagram

Security & Production Considerations

Security is implemented through JWT sessions with 30-day expiration stored in secure HTTP-only cookies, and OAuth tokens are encrypted at rest using AES-256-GCM with authenticated encryption. The system handles token refresh automatically with encrypted storage, maintaining service availability even when access tokens expire. I implemented comprehensive health check endpoints that verify database connectivity, external API availability, and migration status - crucial for production monitoring. The deployment includes automated webhook subscription setup, graceful shutdown handling, and comprehensive error tracking with correlation IDs for debugging.

Developer Experience & Maintainability

The project prioritizes developer experience through comprehensive tooling and documentation. A single setup script handles the entire local development environment, including database setup, environment configuration, and type generation. The codebase maintains strict TypeScript configurations with no implicit any types, uses ESLint and Prettier for consistent code style, and includes detailed inline documentation explaining complex business logic. The modular architecture allows for easy feature additions - for example, adding temperature unit preferences or custom weather formats requires minimal changes thanks to the extensible service design. Error messages throughout the application provide actionable feedback, making debugging straightforward for both development and production issues.

Strava Weather Integration
  • TypeScript
  • React 19
  • Express.js 5
  • Node.js 22
  • Tailwind CSS 4
  • shadcn/ui
  • PostgreSQL
  • Prisma
  • Vercel (serverless)
  • JWT
  • OAuth 2.0
  • Winston
May 2025 – Present
Production SaaS platform for personal training businesses with real-time scheduling and calendar sync, automated invoicing, and role-based authentication, built with Next.js, React, and TypeScript.

A production-ready SaaS platform enabling personal trainers to manage their business operations through a unified dashboard. Built with Next.js 15, React 19, and TypeScript, the application handles complex scheduling, client management, and automated invoicing for a real personal trainer's business.

I designed, built, and continue to maintain and develop new features for this product myself as a side project, since March 2023. The product idea came about because a personal trainer was using a variety of different apps to run her business, and wanted to consolidate them into one with only the features she wants. I continue to work closely with this user to understand her real problems and needs, and provide value by figuring out solutions and developing features that she wants and benefits from.

Personal Trainer Planner calendar view showing workouts and appointments

The core feature of the app are shared calendars between the personal trainer and each trainee. The trainer is able to view every trainee's calendar, and create, update, and delete appointments, workouts, and bootcamps. Trainees can only view their own calendar, including detailed information for workouts and appointments, check off workouts as completed, and check off bootcamps to confirm attendance if they have enough credits.

Other features include a mobile-friendly view for the trainees, tables where the trainer can view billing data and email invoices with a single click, and custom forms managed in Contentful CMS that get emailed to the trainer when a trainee fills the form out.

Data is prefetched in Server Components and cached, so it is immediately available on the client. Data for adjacent calendar months is then prefetched on the client and cached, so they load immediately when the user navigates to them in a Client Component. React Query is also used to invalidate cache when users update server state, and to synchronize other users' clients with the updated server state. This makes the user experience very snappy.

Personal Trainer Planner dashboard interface

Authentication is handled through Auth.js (NextAuth) with secure session management and role-based access control distinguishing between trainers and clients. I implemented a complete password reset flow with time-limited tokens and secure email delivery via Nodemailer. The production environment features automated daily backups through GitHub Actions, with a separate backup database ensuring business continuity. Error tracking via Sentry provides real-time monitoring of production issues.

The codebase maintains high quality standards with unit tests via Vitest for business logic and Playwright for critical user journeys like bootcamp enrollment. The CI/CD pipeline automates formatting checks, linting, and test execution on every pull request. Database migrations are version-controlled with Prisma and automatically deployed to production. The separation of environment-specific configurations enables seamless local development while maintaining production security.

Currently serving a single tenant effectively, the architecture is designed with multi-tenancy in mind for future scaling. The modular structure separates concerns cleanly—server actions for mutations, custom hooks for data fetching, and feature-based component organization. This foundational work positions the platform for evolution into a multi-tenant SaaS product while maintaining the performance and reliability required for business-critical operations.

Personal Trainer Business Management Platform
  • Next.js 15 (App Router)
  • React 19
  • React Query
  • Tailwind CSS
  • shadcn/ui
  • PostgreSQL
  • Prisma
  • Contentful CMS
  • GitHub Actions
  • Vercel
Mar 2023 – Present
Climate data dashboard transforming policy scenarios into interactive visualizations through custom D3.js charts and real-time emissions modeling, built with TypeScript, Next.js, and D3.js.

I developed a comprehensive climate emissions dashboard for GermanZero, a German climate policy platform that enables policymakers and citizens to explore the impact of various climate measures on national emissions targets. Built with Next.js 14, TypeScript, and D3.js, the dashboard transforms complex emissions data into interactive visualizations, allowing users to model different policy scenarios and track progress toward Germany's 1.5°C climate goals. A standout achievement was implementing a novel square-based bar chart visualization that elegantly displays 25 years of projected emissions data across multiple sectors.

Time series chart

The architecture centers on a sophisticated state management system using React Context API with computed state derivations for real-time emission calculations. When users select climate measures, the system recalculates emissions across multiple dimensions—sources, sectors, and timeline projections—while respecting physical constraints and policy interdependencies. I implemented an efficient caching layer using Map data structures for O(1) measure lookups and memoized expensive D3 calculations to prevent unnecessary re-renders. The state persistence mechanism uses LZ-String compression to encode selected measures into shareable URLs, reducing payload size by approximately 70% compared to raw JSON encoding.

MappingZero system architecture

One particularly interesting technical challenge involved building the custom square-grid bar chart visualization. Traditional bar charts couldn't effectively communicate both the magnitude of emissions and the granular impact of individual measures. The solution renders each 5-megaton emission unit as a discrete square, color-coded by reduction status, creating an intuitive visual metaphor that resonates with non-technical stakeholders. The implementation uses D3's data binding efficiently, updating only changed squares during interactions rather than re-rendering entire bars, achieving smooth animations even on mobile devices.

Search sequence diagram

On the data ingestion side, I built a type-safe CSV importer integrated with Payload CMS that handles six different data formats for emissions, sectors, and policy measures. The parser validates data integrity at multiple levels—from basic type checking to complex business rules.

Search sequence diagram

From a production-readiness perspective, the dashboard implements comprehensive error boundaries to prevent cascading failures, includes an 8-step interactive onboarding flow using Driver.js for new users, and maintains full accessibility compliance with ARIA labels and keyboard navigation. The search functionality leverages Orama's client-side full-text search engine with German language stemming, providing fast search results across thousands of climate measures.

Climate Data Visualization Dashboard
  • Next.js 14 (App Router)
  • React 18 (Server Components)
  • TypeScript
  • Node.js
  • D3.js
  • Chakra UI
  • Orama search
  • Payload CMS
  • Figma
Mar – Sep 2024
E-commerce platform modernization from Java monolith to event-driven Node.js microservices, featuring real-time inventory sync across 130+ stores via SOAP integration and Google Pub/Sub messaging.

I worked full stack in a cross-functional scrum team on the e-commerce site for this 1-billion-euro furniture retail business with over 130 shops in Germany. On the front end, I developed and maintained a scalable, reusable React component library and headless CMS content models. On the back end, I was on the core team tasked with migrating a legacy monolith Java back end to an event-driven Node.js microservices architecture.

Porta e-commerce website

I built a Node.js service to fetch stock levels from shops around the country everyday, via a SOAP API, and import them into the cloud-based headless commerce platform (commercetools). The SOAP API was legacy and undocumented, so I had to experiment with rate limits to optimise performance. Even at the fastest rate possible for the SOAP API, the import took about 4 hours everyday, due to the number of shops and the number of products.

As well as the daily import, my implementation allowed the front end and other services to request ad-hoc stock updates for an arbitrary number of products using an asynchronous messaging service (Google Pub/Sub).

E-commerce Platform
  • TypeScript
  • Next.js
  • Styled-JSX
  • Node.js
  • Contentful CMS
  • Commercetools
  • Google Cloud Platform
  • Microservices
  • Pub / Sub
  • Figma
  • Jira
Nov 2021 – Feb 2023

This was my first developer job. I developed a scalable white-label job and real estate portal, serving over 80,000 listings across 90 portals to over 3 million visitors per month.

Classmarkets portal interface
SaaS Product
  • PHP
  • Symfony
  • JavaScript
  • jQuery
  • Bootstrap
  • React
Sep 2019 – Sep 2021