Back to home jacob@stephens.page
Case Study · Educational Travel Adventures

One engineer, a platform of production systems.

Four-plus years as lead engineering owner for a multi-million-dollar specialty-travel operator — modernizing an inherited PHP 5 / CentOS 7 / MySQL 5 monolith into a PHP 8 / Rocky 9 / MySQL 8 platform with Docker, a Python agent-orchestration layer, and multi-tenant AI assistants.

System overview

How the pieces connect. (Architecture shown at a deliberately high level; hostnames, addresses, and vendor specifics omitted.)

USERS Staff & managers · group leaders · parents/travelers · field tour guides EDGE Reverse proxy + TLS (Apache / Caddy / Traefik) TOURBOT PLATFORM  ·  PHP 8 / MySQL 8 Manager appoperations & reporting ERP REST APIshared services Customer portalregistration & payments Guide portal (PWA)offline field reporting DATA MySQL 8 — primaryreservations, payments, manifests Nightly mirrorfeeds sandboxes & analytics OPS & AI INFRASTRUCTURE Orchestration VMfleet status dashboard;scoped autonomous agent Manager Tourbotsper-manager sandboxedAI assistants (Docker) ProspectForgeFastAPI / Next.jscontact sourcing EXTERNAL SERVICES Transactional email · SMS Payment processors (ACH + card) Marketing / calendar integrations

The arc

Inherited legacy, modernized in production, then extended.

The business runs on Tourbot — a full-lifecycle group-travel ERP that handles the sales pipeline, itinerary building, reservations, passenger logistics, payments, communications, and 70-plus reports, plus three customer- and contractor-facing portals built on the same core. When I took ownership it was a PHP 5.6 / CentOS 7 / MySQL 5.7 system whose security and support runway was visibly running out, and every other part of the business depended on it staying up.

Over four years I led the modernization in production, without a freeze: an enterprise-wide migration to PHP 8, MySQL 8.4, and Rocky Linux 9 across the codebase and server fleet, while continuing to ship features. That baseline then unblocked a second wave of work that simply was not possible on the old stack — containerized per-manager AI sandboxes, a Python agent-orchestration VM, and an internal SaaS replacement — alongside the unglamorous habits that keep a single-engineer platform safe: a guarded server-side deploy pipeline, a PHPUnit/CI suite across four PHP versions, and a file-based cron registry with a drift monitor watching 100-plus scheduled jobs.

The throughline is an engineer who inherited a legacy system and systematically turned it into a platform — which is both more common and more credible than a string of greenfield builds.

Engineering highlights

Four representative pieces, each problem → approach → outcome.

Manifest performance: 2,650 → 183 SQL statements/request

Problem. The group-manifest page — printed before every trip — took 5–7s and fired ~2,650 SQL statements per render from per-row constructor fan-out. Approach. Six profile-driven rounds: batched in-request prefetch caches, one shared DB handle, and a targeted history-table column + composite index — each round verified byte-identical against the original HTML. Outcome. ~1s loads, statements per request down ~93%, validated to scale on a 244-sub-reservation outlier group.

PCI-conscious payments

Problem. Aging card integrations and bank-file workflows needed modernizing while customers kept paying every day. Approach. Rebuilt the card flow across merchant processors with bank-account encryption, and modernized the ACH/NACHA bank-file pipeline over SFTP — kept rock-steady through the platform migration. Outcome. Current PCI posture and reliable money movement, with continuity for in-flight registrations and payments.

Multi-tenant AI assistants for managers

Problem. Non-technical managers wanted to query business data and prototype changes without waiting on developer time — safely. Approach. Per-manager sandboxed Tourbot instances (Docker, Traefik) with isolated databases, nightly refresh from a production mirror, per-container resource limits, allowlist-constrained (default-deny) agent command execution, and AI work isolated on per-role branches with a manual promotion step. Outcome. Managers explore data and draft workflow changes through conversation; isolation and a human gate keep production safe.

Platform migration, no downtime

Problem. PHP 5.6, MySQL 5.7, and CentOS 7 were all past or near end-of-life under a live business. Approach. Codebase-wide PHP 5→8 migration, a MySQL 5.7→8.4 plan with dual-running databases during cutover, and a CentOS 7→Rocky 9 fleet migration with per-server runbooks. Outcome. A current, supported stack across the fleet — completed without an outage staff or customers noticed.

Stack & why

The reasoning, not just the list.

PHP 8 / MySQL 8 — the platform's core; modernized in place rather than rewritten, because a rewrite would have frozen a business that can't stop.
Docker + Traefik — per-manager AI sandboxes need hard filesystem and database isolation; containers give each tenant its own world cheaply.
Python / Flask + a scoped system user — the agent-orchestration VM runs an autonomous coding agent with least-privilege, auditable credentials it never handles directly.
FastAPI / Next.js / PostgreSQL — ProspectForge is greenfield, so it uses a typed, modern stack independent of the legacy MySQL core.
Server-side deploy script + PHPUnit/CI — for a single-server PHP app, a guarded shell pipeline (dirty-tree, flock, ancestor-only, healthcheck, one-command rollback) beats a hosted runner; CI runs the suite across PHP 8.1–8.4.
File-based cron registry + drift monitor — 100-plus scheduled jobs become legible and tamper-evident instead of a black box.

Confidentiality: the repositories behind this work are private per employer agreement. Architecture is described here at a high level, with permission, and omits hostnames, network addresses, credential mechanisms, and vendor specifics.

← Back to portfolio