Back to selected work

Case study · product / system

Revo — a recommerce platform built around the parts that fail.

A consumer recommerce flow shipped to production. The interesting engineering is not the storefront — it's the request shaping, valuation logic, state machine, and the operator console that absorbs every edge case.

  • Role Lead full-stack engineer
  • Period 2023 – 2024
  • Stack PHP · MySQL · JS · MQTT
  • Status Shipped
Context

A small operations team handling a high-variance intake.

The team running Revo was a handful of operators evaluating used consumer electronics at volume. Customers submitted devices through a public form and expected a quote within minutes. Each device was different — model, condition, accessories, regional pricing — and the team had no internal tooling to keep evaluations consistent across days, shifts, or operators.

The brief was: ship a public quote-to-fulfillment flow that operators could actually run, not a marketing page that generates leads for someone else to deal with.

Problem

Free-text intake, manual valuations, no audit trail.

  • Customers described devices in unstructured prose; intake quality varied per submission.
  • Every quote required a human review, even on routine models the team had priced 100 times before.
  • Once an order moved into payment / shipping, status updates were ad-hoc emails — operators couldn't reconstruct what happened when a buyer disputed a transaction.
  • Edge cases (locked devices, mismatched IMEIs, partial accessories) had no defined handling path; each one was solved from scratch.
My role

End-to-end engineering, from form schema to operator console.

  • Owned

    System architecture, database schema, request validation, valuation engine, order state machine, operator console, deployment.

  • Shared

    Pricing rules with the operations lead; UX flow with one designer; payment integration review with finance.

  • Reporting

    Direct line to the founder; weekly demo of operator console with real orders.

System design

One pipeline, four cooperating layers.

  1. Quote intake. Guided form turns a device + condition + accessories into a structured request before any payment or account is created. Schema is the contract every downstream layer reads from.
  2. Valuation engine. Rules + condition modifiers + regional pricing produce a quote band. A review_required flag short-circuits to operator review when the rules can't decide with confidence.
  3. Order state machine. Checkout, payment, label generation, in-transit tracking, received, inspected, settled — each transition is logged with actor, timestamp, and reason. Idempotent transitions; no "what state is this order in" ambiguity.
  4. Operator console. Lists exception orders first, then in-progress, then closed. Every action an operator takes (override valuation, request more info, cancel, settle) writes back into the same state log the customer sees.
Technical stack

Boring stack on purpose.

  • PHP 8
  • MySQL 8
  • Vanilla JS
  • MQTT (device telemetry)
  • Stripe (payments)
  • EasyPost (labels)
  • Apache + .htaccess routing

No SPA framework. No queue worker. No Redis. The traffic and team size didn't justify the complexity — and stripping operational surface area meant the operator team could read the codebase when they wanted to understand a behavior.

Key decisions

Trade-offs I'd make again.

  • Schema-first

    The intake schema was the first thing built and the last thing changed. Every layer downstream agreed on the same shape, which is why valuation, fulfillment, and reporting all read from one source.

  • State machine over status field

    Explicit transitions with allowed-from / allowed-to lists. Made dispute resolution provable instead of forensic.

  • Operator console = first-class

    Built the operator surface in the same sprint as the customer surface, not after. Forced edge cases out into the open early.

  • Manual review as a feature

    Treated review_required as a real outcome, not a fallback. The valuation engine is allowed to say "I don't know" — the alternative is bad quotes the team has to undo later.

Outcome / evidence

What the team could do after that they couldn't before.

Throughput

Routine quotes resolve without operator touch; only review_required orders enter the queue. The operator team's time shifts from typing quotes to handling exceptions.

Auditability

Every state transition is timestamped with an actor and reason. Disputes are resolvable from the order's own log instead of email threads.

Reuse

Reporting and dispute resolution read the same data the customer sees. One source of truth, three audiences.

Note

Specific volume and dollar figures are owned by the operator; happy to share under NDA on request.

What I'd improve next

Honest follow-ups, not future-proofing.

  • Replace the per-row pricing config with a versioned ruleset table so operators can roll back a bad pricing change in one query.
  • Move the valuation engine behind an internal API; right now the customer-facing PHP imports it directly. Same code, cleaner boundary.
  • Add structured event emission (order.transitioned, quote.flagged) — not because we need a queue today, but so we have the option later without rewriting the call sites.
  • Add deterministic seed data for the operator console so onboarding a new operator doesn't depend on production traffic that day.