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 modify the platform themselves.

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 (Docker container) with their own Claude-powered OpenClaw agent. Agents can query a nightly-synced replica of the production database, run analysis, and even modify PHP code — all sandboxed per-manager with allowlist-controlled command execution, dedicated database users, and a git-based review gate before any changes reach production.
Result Non-technical managers can independently explore business data, generate custom reports, and prototype workflow changes through conversation — while the system enforces isolation, read-only data access, and code review boundaries that keep production safe.
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 whether they were reachable, which probes were green, and what was 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 (TLS via Let's Encrypt) running under gunicorn and systemd, with a background thread sweeping TCP, HTTP, and MySQL probes every 60 seconds against an inventory mirrored from the company's infrastructure document. A two-step gate — bcrypt-hashed shared password plus single-use SQLite-backed magic-link tokens emailed only to whitelisted addresses — protects the dashboard. The same VM hosts a `conductor` service-account pipeline: 1Password service-account 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 picking up its credentials themselves. Auditing reads as "the orchestrator did X," not "Engineer Y did X via the orchestrator."
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 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 calculated every alert from scratch on every request. Each load fanned out into 100+ MySQL queries against the same booking, item, and product-alert tables, with no reuse across users. With every staff member hitting it many times a day, 5–10 second loads were normal, the database was carrying a lot of avoidable repeat work, and the slowness was eroding trust in the rest of Tourbot.
What I Built Started by profiling the request path and going after the worst offenders: added composite indexes covering the booking / item / product-alert joins, and rewrote per-reservation loops into batched IN (…) queries to kill the N+1 pattern. Then went further and pre-computed the alerts themselves into a dedicated MySQL cache table, populated by a background PHP daemon, so the page itself just reads pre-shaped rows. Invalidation is layered — writes in the relevant flows (booking uploads, item cancellations, alert state changes) kick off a per-reservation recompute in the background, page loads opportunistically refresh stale caches against a one-hour freshness window, and a nightly cron does a full rebuild. The visible behavior of the page didn't change, so nothing for users to relearn.
Result Page loads dropped from 5–10 seconds to under 1 second, and the per-page query count dropped from over 100 to a small handful — most of the work now happens 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 past the original page.
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 security and support runway was visibly running out: PHP 5.6 long past EOL, MySQL 5.7 past its window, and CentOS 7 about to age out. Every other piece of the platform — payments, ACH, the customer portal, internal Tourbot, the guides PWA — had to keep shipping the entire time.
What I Built Directed and executed an enterprise-wide PHP 5 → 8 migration across the codebase, removing magic quotes, deprecated `mysql_*` calls, and dynamic-property warnings; declaring properties on long-lived models; tightening type signatures. Wrote and shipped the MySQL 5.7 → 8.4 migration plan and the CentOS 7 → Rocky Linux 9 cutover, including production deployment notes, schema-compatibility audits, and per-server runbooks. Coordinated cross-database export/import for customer accounts, dual-running the old and new database servers during transition. Modernized server roles in step (db deprecation, ACH host migration, manager-tourbot Docker host). 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/.

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

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.
What stands out Local-first architecture, server sync, and domain-specific interface logic — not generic CRUD.
TypeScript Vite Express SQLite PWA

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