Product engineering, automation and data

Vi Nguyen

I run Homads, a subscription-based listing site for mid-term rentals, live in 700+ US cities. I design it, build it and keep it running. During the day I build internal automations and AI agents for an enterprise automation team. A lot of my work sits in the middle layer: billing, data pipelines, and the process around them.

Available for freelance and consulting work.

Building products

Marketplace app, marketing site, billing, search, content pipeline — through to deploying it.

Automating operations

Requirements from non-technical stakeholders, then the flows, agents and reporting that follow from them.

Working with data

Analytics collection, reconciliation between systems, and reporting people can act on.

Selected work

Homads is my own company, so those projects are open — live links and real numbers. The employer work is described without internal detail.

Homads — a subscription listing site for mid-term rentals

Founder & builder

A listing site for mid-term rentals — furnished stays of 30 days or more. Hosts list free and pay a subscription to reply to renters, with no commission taken on a booking. I build and operate the stack: the application, the marketing site and blog, subscription billing, search, analytics and content.

700+ US cities  ·  1,000+ listing owners  ·  41,000-member host community  ·  2,826 indexed URLs

Next.jsReactVercel Bubble.ioPostgresStripe MixpanelNode
More detail

The stack

  • Marketplace app on Bubble — listings, search, messaging, host dashboard, subscriptions.
  • Marketing site and blog on Next.js / Vercel, with the app acting as the CMS behind the blog.
  • Search infrastructure — a Postgres read-mirror of the listing data, so city and map search doesn't run against the app database.
  • Billing — Stripe subscriptions across three portfolio-sized plan tiers, plus the sync layer that keeps the app and Stripe consistent.
  • Analytics — Mixpanel behind a first-party proxy, reconciled daily against Stripe.

Recent platform work

  • A framework upgrade across two major versions, including the middleware-to-proxy migration and the runtime change that came with it.
  • SEO migration: canonical and OG-image fixes, a 301 map off the legacy URL scheme, and a sitemap rebuilt to 2,826 URLs including 602 city pages.
  • A crawler gate that was returning 503s to link unfurlers — diagnosed, exempted, and covered with a unit test.

Rebuilding self-serve subscription billing

Diagnosis & build

Subscribers couldn't reliably manage or cancel their own plans. It turned out to be three separate problems in three different layers, which is part of why it had been hard to pin down.

Stripe APINext.js API routes Bubble workflowsWebhooks
Read the case study

The problem

The account page had a cancel control and a Manage Billing button. Neither worked for most people, and the code looked correct when read in isolation.

What was happening

  • The cancel control was gated on a status string with a capital letter, while the sync job writes the payment provider's own lowercase value. The condition was never true, so the button never rendered.
  • The billing portal resolved the customer from a field that most accounts had never been given. Legacy accounts carried an older identifier format entirely, from a migration years earlier.
  • Cancelling an annual plan that was already past due scheduled the cancellation for the end of the term, which gave that account another year.

What I built

  • Rewrote the visibility conditions to normalise case, and widened them to cover past-due accounts rather than only active ones.
  • Rewrote the portal endpoint to resolve the customer from the subscription record rather than a stored customer ID, so it works regardless of when an account was created.
  • Added an immediate-cancellation path for past-due subscriptions.
  • Wired the API connector and the app-side workflows, deployed, and tested against a live account.

Result. Subscribers can cancel and manage billing without contacting support, and the renewal path that was costing revenue is closed.

Looking back

The case-sensitivity typo was the easy part. The underlying issue was that three systems each had their own reasonable-looking definition of "this customer," and nothing forced them to agree. Picking one identifier that always exists, and resolving everything from it, is what actually closed it.

A data-grounded city content programme

Research, pipeline & publishing

23 city guides, each built from our own listing data and the city's short-term-rental tax law. The harder question was which cities deserved a page at all.

23 guides published  ·  602 city pages in the sitemap  ·  29 cities with real depth, of 700+

Next.jsData APINode PlaywrightProgrammatic SEO
Read the case study

Why not 700 pages

700+ cities looks like a programmatic-SEO opportunity: generate a page each. I ran the numbers first. The median city on the platform has one listing, and only 29 have ten or more. Generating all of them would have produced around 670 thin pages, which is a site-quality problem rather than traffic.

Counting the listings correctly

Working out how many listings a city actually has turned into its own piece of work. Listings are filed under several different location strings for the same metro, so grouping on any one of them undercounts — in some cities by more than 30%. Separately, grouping by the record's creator attributes half a city to a data-migration account rather than to real hosts. Both errors put wrong numbers into a draft before I caught them, so the pipeline now merges on a key set and groups on the actual owner.

What each guide contains

  • Price, supply and ownership-concentration figures computed from live data at publish time.
  • The city's tax threshold, cited to statute. The question hosts have is how long a stay has to be before it stops being taxed as a hotel, and the answers vary a lot — one city exempts you based on how you're billed rather than how long you stay, and another taxes 31 nights but not 32.
  • A neighbourhood angle from clustering listings by street address, which was the most reliable way to find something specific to say about a city.

The pipeline

  • A query that pulls merged per-city stats from the app's data layer.
  • A Node and Playwright generator that renders a branded header image per city from a JSON input.
  • A slug-to-article map, so publishing a new city is a one-line change.

Result. 23 of 23 published and verified, each with original data and a header image, with all city-page link-backs live.

Group Watch — an AI listening pipeline

Design & build

Homads runs a 41,000-member host community. It contains useful signals and occasional reputation risk, and reading it manually doesn't scale. This watches it, classifies what matters, and drafts a reply.

NodeClaude APIApify RenderSlack APIWebhooks
Read the case study

The constraint that shaped it

The obvious approach — automating a logged-in account — would have put the company's community account at risk, so it was out. That decided the architecture: everything reads the group's public surface, with no session and no account of ours involved. A few hours of latency is an acceptable trade for that.

How it works

  • A scheduled collector reads the public group three times a day and posts to an ingest webhook.
  • A small service classifies each post as buying intent, pain point, competitor mention, reputation risk or direct mention. Generic property-management requests are dropped rather than surfaced, since they weren't producing useful leads.
  • Results route to Slack channels by urgency, each with a drafted reply in the appropriate register — customer-service tone for reputation risk and direct mentions, peer tone for buying intent and pain points.

Result. Runs for a few dollars a month inside free tiers. A vendor quoted around $1,000/month for comparable custom coverage.

What's still unproven

The strategy rests on an assumption I hadn't tested: that the valuable conversations happen in comment threads rather than top-level posts. Rather than buy the more expensive tier on a hunch, I set up a one-week keyword measurement to size the comment share, with the decision rule written down before the data came in.

Making the analytics reliable

Audit & build

Product analytics and the payment system disagreed about revenue, which meant neither could be used to decide anything. I fixed the collection, then built a job that checks it daily.

MixpanelStripe First-party proxyScheduled jobs
Read the case study

Three separate problems

  • Collection. Analytics calls to a third-party domain were being blocked by ad-blockers. Moved behind a first-party proxy so events arrive.
  • Identity. The marketing site and the app were creating separate identities for the same person, so no funnel crossing the two could be read correctly.
  • Coverage. Purchase tracking wasn't firing on every path, so the revenue picture was incomplete rather than just noisy.

What I built

A daily reconciliation job comparing tracked purchases against the payment provider's record and surfacing any divergence, so a tracking regression shows up the next morning rather than a quarter later, when the historical data can't be recovered.

Result. One rule now covers it: the payment system is the source of truth for money, analytics for behaviour, and a daily job checks they still agree.

A habit that came out of this

I now check the base rate before treating a number as a problem. A channel averaging a quarter of a signup a day will show a week of zeroes as ordinary variation. A few of my own confident diagnoses didn't survive that check, so it became a standing step rather than something I did when I remembered to.

Hexis — automotive dealership CRM platform

Ethos Group · prior team

Hexis is Ethos Group's dealership platform — showroom CRM, desking, inventory management and a BDC sales lead portal behind one sign-on. I worked full-stack on it: third-party data integrations on the backend, and a share of the platform's second-generation rebuild across both ends. It's licensed software, so I can't hand out a login; the company markets it publicly and their site is the best look at it.

Full-stackAPI integration Bubble.ioCRM Enterprise / B2BAutomotive
My role

What I worked on

  • Third-party data integrations. I built the API integrations against an external automotive data and valuation provider, including the feed behind the platform's automatic OEM incentives.
  • The second-generation rebuild. I rebuilt portions of the platform's next major version, working across the frontend and the backend.

The incentives integration

Rebates and manufacturer offers depend on the exact trim of a specific vehicle, and the figure goes onto a deal sheet the customer sees, so it needs to be exact rather than close.

Ours weren't. The provider's payload was a deeply nested structure carrying several hundred nested items, and the incentives the platform surfaced didn't reliably match the make and model they belonged to.

I mapped the whole payload — every level of nesting, rather than only the fields that looked relevant — and rebuilt the mapping from that. Once the shape of the data was fully understood, the cases that had been landing on the wrong vehicle were identifiable.

Result. Incentives display correctly for each make and model.

Why it's here

Integration work makes up a good part of what I do. Two systems that each make sense on their own have to be made to agree about what a record is — the same underlying problem as the billing work above, in a different industry.

Internal automation and AI agents

Ethos Group · current

I'm on an automation team that builds bots and AI agents for other departments. The systems are internal, so this describes the shape of the work rather than the systems themselves.

Power AutomateCopilot Studio Power BISharePoint Azure DevOpsProcess design
What this work involves

Where I sit

Business analyst and builder both — I run the stakeholder discovery, write the process flows, then build. The discovery half is usually where the value is. Departments tend to ask for a solution they've already pictured, and the work is finding the problem underneath it. One project started as "standardise this recurring meeting agenda" and, after a stakeholder session, became "the data for that meeting lives in eleven places and nobody can see it by region, team or individual" — a different and more useful build.

What I do

  • Discovery and process design — requirements from non-technical stakeholders, mapped as capability-level process flows in a shared diagramming convention.
  • Automation — multi-connector flows across task systems, document stores, directory services and chat, with the operational parts handled properly: service-account ownership, shared connections so teammates don't each need their own, and run-only access so a team can self-serve.
  • AI agents — agents that ingest a user's own data, validate it, generate a structured document from it, capture what happened afterwards, and produce the follow-up artifact.
  • Reporting — multi-page reports over the team's delivery data, built to a designed spec, with the semantic model, theme, scheduled refresh and workspace governance set up behind them.

A few decisions from this work

  • Replaced a report-triggered flow with a link into the system that already had a working control, because the platform's refresh ceiling meant the more complex version could never have stayed current.
  • Moved a scheduled data refresh so it runs after the upstream job that feeds it, rather than alongside it.
  • Held off migrating a flow's connections onto a service account until that account had the right licence, rather than doing a partial move that would leave it in two states.

Stack

Tools I've used on production work.

Product & web

  • Next.js / React
  • TypeScript
  • Node
  • Vercel
  • Bubble.io
  • Playwright

Data

  • Postgres
  • Power BI / DAX
  • Mixpanel
  • REST & webhooks
  • Python

Automation & AI

  • Power Automate
  • Copilot Studio
  • Claude API
  • Agent design
  • Apify

Operations

  • Stripe
  • Slack API
  • SharePoint
  • Azure DevOps
  • Git / GitHub
  • Render

Get in touch

I'm available for freelance and consulting work — marketplace and subscription products, billing and payments, process automation, and analytics.