Back to home jacob@stephens.page
Portfolio

Real systems, real results.

Booking engines, contractor tools, payment flows, subscription infrastructure, and client sites built to last beyond launch day.

Professional Work

Production systems with operational and revenue impact.

Tourbot

The core operations platform at Educational Travel Adventures — a full-lifecycle group travel ERP handling sales pipeline and lead qualification, itinerary building, reservations, vendor management, passenger logistics, payment processing, communications, and 70+ reports across finance, sales, marketing, and operations.

Problem A 40-person travel company needed a single system to run the entire business — from lead inquiry through post-trip reporting — covering sales, finance, operations, vendor coordination, and customer-facing portals without things falling through the cracks.
What I Built A sales pipeline with lead qualification and agency management. An itinerary and quote builder with vendor pricing. Full reservation lifecycle management with passenger manifests, rooming lists, and multi-stage payment schedules. A vendor portal for self-service. A communications center with email, SMS, and document generation. Credit card processing, accounts receivable/payable, and QuickBooks integration. Customer and group leader portals. Employee tools including timeclock and expense management. Insurance and waiver workflows. 70+ reports and integrations with Google Workspace, Slack, and Twilio.
Result An operational backbone that runs every part of the business daily — sales, booking, finance, logistics, and communications — still in production after years of continuous development.
PHP MySQL JavaScript jQuery Monetra Twilio QuickBooks Operations

ETA Guides Portal

A mobile-first PWA for tour guide contractors at Educational Travel Adventures — itinerary and medical info access, document workflows, daily and summary reporting with live auto-save, expense tracking with receipt uploads, SMS messaging to travelers, calendar scheduling, and manager-side administration.

Problem Independent contractor tour guides — with no access to the main system — needed a reliable mobile interface to view trip details, access passenger medical and dietary information, file reports and expenses, and communicate with travelers while in the field.
What I Built A full PWA with offline support and service worker caching. Tentative and final itinerary views, passenger manifests, medical conditions, allergies, and dietary reports. Daily reports and post-tour summary questionnaires with live auto-save. An expense system with categorization, receipt attachments, and driver gratuity forms. Twilio-powered SMS messaging to travelers and billing contacts. A calendar with unavailability scheduling. Tour confirmation and ride-along workflows. Manager admin tools for document management and report reassignment.
Result Guides in the field can view trip details, check passenger medical needs, text travelers, file reports as they go, and submit expenses with receipts — all from their phone, online or offline. Managers can administer documents and review reports without developer involvement.
PHP MySQL Bootstrap Twilio Service Workers PWA

Tourbot Chat

An AI-powered chat system built with OpenClaw and Claude, giving managers at Educational Travel Adventures natural-language access to business intelligence and the ability to safely prototype platform changes themselves — each in an isolated, sandboxed copy of Tourbot.

Problem Managers needed to answer complex business questions — revenue breakdowns, booking trends, vendor performance — without waiting on developer time. They also wanted to experiment with reports and workflows on their own terms, without risking the production system.
What I Built A multi-tenant infrastructure where each manager gets an isolated Tourbot instance — its own Docker container fronted by Traefik — with a dedicated Claude-powered OpenClaw agent. Agents query a nightly-synced replica of the production database, run analysis, generate reports, and even modify PHP code, all sandboxed per-manager: allowlist-controlled command execution, dedicated least-privilege database users, and a git-based review gate so nothing reaches production unreviewed. Each container is provisioned from a shared compose definition, so standing up a new manager sandbox is a one-command operation.
Result Non-technical managers can independently explore business data, generate custom reports, and prototype workflow changes through plain conversation — no developer in the loop for routine questions — while the system enforces per-manager isolation, read-only data access, and code-review boundaries that keep the production platform safe from accidental or unreviewed change.
OpenClaw Claude Docker PHP MySQL Traefik AI Agents

ETA Orchestration & Status

A Python and Flask service running at status.etadventures.com that probes Educational Travel Adventures' fleet of web, database, and cron servers and renders a single-page health view — paired with a hardened Linux host that lets a Claude Code agent operate safely across that infrastructure.

Problem A dozen production and supporting servers — MySQL 8 and 5.7, Apache, ACH cron processing, Docker-hosted manager sandboxes, an asset host — with no single place to see what was reachable, green, or degrading, and no clean way to give an AI agent multi-server access without leaking credentials or muddying audit logs.
What I Built A Flask app behind Caddy and gunicorn that sweeps TCP, HTTP, and MySQL probes every 60 seconds across the fleet, with deploy controls, fleet-wide tmux management, and a web terminal — all gated by single-use magic-link tokens. The same VM runs a hardened service-account pipeline: 1Password secrets injected at launch via op inject, MySQL grants pinned to the host's IP, and a sudo-elevated wrapper so engineers trigger the agent without ever handling its credentials. Auditing reads as "the orchestrator did X," not "Engineer Y did X via it."
Result One URL to check fleet health, refreshed in the background so page loads never block on a probe — and a controlled launchpad from which an AI agent can coordinate work between web and database servers with credentials it never sees on disk.
Python Flask SQLite gunicorn Caddy systemd Linux 1Password Claude Code

ETA Customer Portal

The customer-facing side of Educational Travel Adventures — group leaders, parents, and travelers self-serve account creation, trip registration, payment plans, and communication. Inherited from a previous IT team and substantially rebuilt by me and the team I lead.

Problem The original portal — built years earlier — had drifted out of step with the rest of the platform: payment integrations were aging, the UI looked dated next to the modern Tourbot interface, and security and PCI posture needed real work as ETA shifted between merchant processors. It needed to keep running every day for paying customers while we modernized it underneath.
What I Built Led the rebuild while keeping the existing portal in production. Migrated the credit-card flow across processors (TranSafe, Monetra, NMI) with bank-account encryption and PCI-conscious handling. Re-engineered registration, payment-plan, and refund flows. Modernized the front-end with a Tailwind-based component layer alongside legacy markup. Added in-portal chat, conference-call hooks, and customer-account export/import for cross-database migration. Tightened the API surface and aligned auth with the broader Tourbot platform.
Result A portal that customers actually trust to take their money — clearer flows, modernized payments, current PCI posture — with continuity for the thousands of registrations and payments already in flight when the rebuild started.
PHP MySQL JavaScript Tailwind NMI TranSafe Monetra PCI

ACH & NACHA Bank-File Automation

The cron-driven pipeline that turns scheduled customer payments into NACHA-formatted batch files and submits them to M&T Bank for ACH processing — the system that actually moves the money. Inherited the original implementation; took ownership, modernized the runtime, and kept it running through platform migrations.

Problem The ACH side of the business depends on producing correctly-formatted NACHA files, uploading them to the bank on a schedule, and reconciling return files when entries fail. The original cron host was stuck on CentOS 7 and PHP 5.6, the code had drifted from the rest of the platform, and the bank doesn't tolerate malformed batches — a bad file is a failed payment day.
What I Built Took over the bank-file generator and the surrounding cron fleet (`nacha_files_to_upload`, `nacha_returnfiles`, vendor ACH batches, and recurring-payment crons). Modernized the code paths against current PHP, migrated the MySQL backend across versions, added monitoring around the daily cron schedule, and integrated NMI as a routing target for recurring card payments alongside the ACH flow. Kept the bank-facing format and submission cadence rock-steady the entire time.
Result Customer ACH payments and refunds clear the bank on schedule, return files are processed back into the system, and the pipeline is now legible and modifiable instead of a black box only the original author understood.
PHP MySQL NACHA ACH Cron M&T Bank Linux

Tourbot Manifest Performance Tuning

A six-round, profile-driven performance pass on Tourbot's group manifest page — the document staff print before every trip — taking page loads from 5–7 seconds to about 1 second by eliminating N+1 queries, batching in-request prefetches, and adding a targeted history-table index.

Problem The manifest page renders everything operations needs about a group reservation in one shot — passengers, payments, waivers, schedules, cancellation history. Each load fired ~2,650 SQL statements and opened 118 fresh MySQL connections, because the Booking, Price_statement, and ReturnPaySked constructors each ran helper queries per row of a 50-passenger group — almost all of it avoidable repeat work.
What I Built Six rounds, each starting from an xdebug cachegrind capture and ending with a byte-identical HTML diff. Collapsed 118 per-request MySQL connections into one via the shared PDO handle. Made Booking::__construct skippable so 50 passengers hydrate from a single batched IN(…) query, and added a Price_statement::prefetch() layer — static caches and batched queries warmed once per request, with per-instance fallbacks for other callers. Replaced a leading-wildcard LIKE in the cancellation-history query with an Action_Type column and composite index, cutting EXPLAIN's rows-examined from 4,165 to 1.
Result Production page load dropped from 5–7s to about 1s, SQL statements per request from ~2,650 to 183 (−93%), with rendered HTML byte-identical at every step. Re-validated on a 244-sub-reservation outlier group: ~10s → ~3s and ~11,800 statements → ~2,400, still byte-identical — so the wins scale to worst-case data.
PHP MySQL xdebug Profiling Query Optimization Schema & Indexing Performance

Tourbot Alert Performance Tuning

A performance pass on Tourbot's internal alerts page — a heavily-trafficked screen that staff hit repeatedly throughout the day — taking load times from 5–10 seconds down to under 1 second by replacing per-request query fan-out with a pre-computed cache table.

Problem The alerts page recalculated every alert from scratch on each request, fanning out into 100+ MySQL queries against the same booking, item, and product-alert tables with no reuse across users. With staff hitting it many times a day, 5–10 second loads were normal and the slowness was eroding trust in the rest of Tourbot.
What I Built Profiled the request path and hit the worst offenders first: composite indexes on the booking / item / product-alert joins, and per-reservation loops rewritten as batched IN (…) queries to kill the N+1 pattern. Then went further — pre-computed the alerts into a dedicated MySQL cache table populated by a background PHP daemon, so the page just reads pre-shaped rows. Invalidation is layered: writes trigger per-reservation recomputes, page loads refresh stale caches against a one-hour window, and a nightly cron rebuilds fully. Visible behavior didn't change.
Result Page loads dropped from 5–10 seconds to under 1 second and per-page queries from 100+ to a handful, with most of the work now off the request path. The same cache table later became the read source for the SPM group page and the sales dashboard, so the win rippled outward.
PHP MySQL Caching Query Optimization Performance

Legacy Modernization: PHP 5 → 8, MySQL 5.7 → 8.4, CentOS → Rocky

A multi-year, codebase-wide modernization of Educational Travel Adventures' platform — PHP 5.6 to PHP 8, MySQL 5.7 to MySQL 8.4 LTS, and CentOS 7 to Rocky Linux 9 — done in production, without freezing the company.

Problem A 40-person travel business was running on a stack whose support runway was visibly running out: PHP 5.6 long past EOL, MySQL 5.7 past its window, CentOS 7 aging out. Every other piece of the platform — payments, ACH, the customer portal, internal Tourbot, the guides PWA — had to keep shipping throughout.
What I Built Executed an enterprise-wide PHP 5 → 8 migration across the codebase: removed magic quotes and deprecated mysql_* calls, declared properties on long-lived models, tightened type signatures. Shipped the MySQL 5.7 → 8.4 migration plan and the CentOS 7 → Rocky Linux 9 cutover, with deployment notes, schema-compatibility audits, and per-server runbooks. Coordinated cross-database export/import for customer accounts, dual-running old and new database servers during transition. Mentored the developer working alongside me on the same codebase.
Result A current, supported stack — PHP 8, MySQL 8.4 LTS, Rocky Linux 9 — across the production fleet, completed without an outage that customers or staff would have noticed. The same migration also unblocked downstream work: containerized manager sandboxes, an AI-agent orchestrator, and the modernized customer portal all assume the new baseline.
PHP 8 MySQL 8.4 Rocky Linux CentOS Migration Refactoring Production Ops

Client Work

Focused builds for payments, publishing, and straightforward business visibility.

Chester County Life

A subscription payment system with Stripe integration for recurring revenue and secure transaction handling.

Problem The site needed reliable recurring billing, not just a brochure.
What I Built PCI-conscious subscription flows and payment infrastructure tied into Stripe.
Result A site that collects and manages recurring revenue, not just describes the offering.
PHP Stripe Subscriptions

Wadadli Flare Catering

A marketing site for a catering business — clear presentation, service visibility, and lead generation.

Problem The business needed a web presence that communicated the offering quickly and drove customer inquiries.
What I Built A polished service site with clear structure, strong visual presentation, and direct paths for interested customers.
Result A credible online front door and a better platform for discovery and inquiries.
Frontend Brand Presence Lead Generation

Personal Projects

A curated set of personal builds. The broader archive lives at blog.stephens.page/projects/.

Creighton Cycle Tracker

A fertility tracking PWA built around the Creighton Model — offline support, auto-computed charting, syncing, and provider sharing.

Why it matters Product thinking around a sensitive, real-world workflow where accuracy, offline access, and long-term usability are non-negotiable. Found organically through search and used by real people beyond me.
What stands out Local-first architecture, server sync, and domain-specific interface logic — not generic CRUD.
TypeScript Vite Express SQLite PWA

Cascade

A waterfall white-noise player for focus and sleep — one headless Rust core driving six native shells: web (PWA), Android, macOS, Windows, iOS, and watchOS.

Why it matters A daily-use focus/sleep sound app, and an architecture kata: prove a single Rust core can power genuinely native UIs across every major platform without a web wrapper. The core owns all behavior — state, pomodoro/sleep timers, custom durations, volume, persisted settings, and time via explicit tick events — and never touches an audio API.
What stands out A coarse dispatch(command) → {snapshot, effects} boundary serialized as one JSON wire shape across four binding mechanisms — wasm-bindgen (web), UniFFI (Kotlin & Swift), and a hand-rolled C ABI + P/Invoke (C#). GitHub Actions compiles the Windows and Apple shells in CI; the watch is a thin WatchConnectivity remote. Native media integration per platform (Web Audio, Media3, AVAudioEngine, SMTC) plus an installable, offline PWA.
Rust WebAssembly React UniFFI Jetpack Compose SwiftUI WinUI 3 PWA

Clowder & Crest

A medieval cat guild management game — 14 minigame types, an explorable town map, a 7-chapter narrative arc, and Fire Emblem-style bond conversations between cats.

Why it matters A complete game shipped from concept to native Android — game design, pixel art, audio composition, minigame variety, narrative writing, and deployment all in one project.
What stands out 14 distinct minigame types each authored against the design pillars of its genre; resilient Playwright playtest harness for every scene; AI-assisted asset pipeline (PixelLab sprites, ElevenLabs SFX, Suno music); Capacitor wrapper with native haptics, notifications, and lifecycle hooks.
Phaser 3 TypeScript Capacitor Matter.js Playwright PixelLab

Magisterium MCP Server

An MCP server that gives AI assistants access to the Magisterium API, returning Church teaching with source citations.

Why it matters Bridges a meaningful content domain with emerging AI tooling in a practical, technically current way.
What stands out MCP integration, source-aware responses, and a clean bridge between authoritative data and assistant workflows.
TypeScript Node.js MCP AI Tooling

Macros Tracker

A self-hosted nutrition tracker built as a MyFitnessPal replacement — barcode scanning, recipe management, API-backed food search, charts, and offline support.

Why it matters Replaced a mainstream SaaS workflow with a personal tool shaped by actual daily use.
What stands out Multi-source food data integration, practical daily-use UX, exports, and a product scope driven by firsthand usage.
TypeScript Express SQLite Chart.js PWA

Daily Dozen Tracker

A progressive web app for tracking Dr. Greger's Daily Dozen food recommendations — offline support, progress visualization, and a Catholic stewardship framing of daily nutrition.

Why it matters Turns an evidence-based nutrition checklist into a sustained daily habit with the right cadence and a gratitude framing that fits a faith context.
What stands out Node.js / Express backend with JWT auth and transactional email; PWA frontend with offline-first persistence and installable shortcut on mobile.
JavaScript Node.js Express PWA

Exodus 40 Lite

A PWA for a parish men's group — tracking prayer, fasting, almsgiving, and fraternity through a shared Lenten rule of life.

Why it matters Turns a niche communal practice into a usable digital workflow for a real small-group context.
What stands out Progress tracking, offline support, and a product scope built for sustained participation, not one-time visits.
PHP JavaScript PWA Android (Capacitor)

Artifact Manager

A multi-tenant possessions tracker that operationalizes the Minimalists' 90/90 Rule — log when you use the things you own, see what's due to be used next, and decide what to declutter.

Why it matters Translates a specific philosophy ("if you haven't used something in 90 days and won't use it in 90, let it go") into a working personal-informatics tool. Domain-aware UX — sweet spots, playgroups, candidate exploration, aversions — instead of generic CRUD over a "things I own" table.
What stands out Multi-tenant PWA with offline support; REST API with JWT auth, rate limiting, cursor pagination, and structured request logging; PHPUnit test suite; daily cron emails users their "due to use" items; OOP data layer with per-domain query modules.
PHP MySQL REST API JWT PWA PHPUnit

Wedding Platform

A full-stack wedding site — invite-based RSVPs, guest management, registry tracking, photo uploads, travel details, and admin tooling.

Why it matters What is usually a brochure site becomes a real application with workflows, data, and event operations behind it.
What stands out Group lookup logic, admin views, cron-backed monitoring, and an operationally complete personal project.
PHP MySQL JavaScript Operations