How a Real Estate Startup Slashed Search Latency by 88% Using a Vietnamese AI-Augmented Team — A Full Stack Case Study
Late last year, a Series A real estate platform in Austin came to us with a problem that’s painfully common in property tech.
Their core search endpoint—the one their agents and homebuyers hit dozens of times per session—was averaging 4.2 seconds of response time. On heavy filter combinations (price range + square footage + school district + year built), it regularly drifted past 7 seconds.
When AI Coding Tools Meet Security Audits: How We Auto-Fixed 47 Vulnerabilities in a Weekend
When AI Coding Tools Meet Security Audits: How We Auto-Fixed 47 Vulnerabilities in a Weekend Your AI coding… ...
Users were bouncing. Organic traffic was dropping. And their VP of Engineering had already spent 4 months trying to optimize it in-house with zero meaningful improvement.
They needed help. Fast.
Vietnam Outsourcing: Why It’s the Smartest Move for Software Development in 2025
TL;DR: Vietnam outsourcing is rapidly becoming the go-to for software development in 2025. Lower costs than India, higher… ...
Here’s the story of how we deployed a 4-person Vietnamese engineering team, augmented by the ECOA AI Platform ACP (our agent orchestration framework), and cut that latency by 88% in 7 weeks.
—
The Problem: A Classic ORM Nightmare
Let’s be brutally honest about what we found.
The codebase was a standard Node.js + TypeScript backend using Sequelize ORM against a PostgreSQL 13 instance. The search query generated a single massive SQL statement with 11 JOIN clauses across listings, addresses, agents, office branches, open house schedules, photos, saved searches, user favorites, and two custom lookup tables for school data.
Here’s a simplified version of what the query looked like:
sql
SELECT listings.*, addresses.street, addresses.city,
agents.name AS agent_name, offices.name AS office_name,
COUNT(photos.id) AS photo_count,
bool_or(favorites.user_id IS NOT NULL) AS is_favorited
FROM listings
JOIN addresses ON addresses.listing_id = listings.id
JOIN agents ON agents.id = listings.agent_id
JOIN offices ON offices.id = agents.office_id
LEFT JOIN photos ON photos.listing_id = listings.id
LEFT JOIN favorites ON favorites.listing_id = listings.id AND favorites.user_id = $1
LEFT JOIN open_houses ON open_houses.listing_id = listings.id
WHERE listings.status = 'active'
AND listings.price BETWEEN $2 AND $3
AND listings.bedrooms >= $4
AND addresses.city ILIKE $5
GROUP BY listings.id, addresses.id, agents.id, offices.id
ORDER BY listings.price ASC
LIMIT 20 OFFSET $6;
11 joins. Two `LEFT JOIN`s on tables that had grown to 2+ million rows each. No materialized views. No read replicas. And Sequelize’s lazy loading was silently firing 40+ additional queries per search.
The database CPU was pegged at 92% during business hours.
Honestly, I’m surprised it worked at all.
—
The Team Structure: Why We Chose a Vietnamese Augmented Team
We’ve run dozens of offshore engagements. For this project, I knew we needed senior engineers who could make architectural decisions—not just follow tickets.
We staffed:
| Role | Level | Rate |
|---|---|---|
| Backend Engineer (Node.js/PostgreSQL) | Senior | $3,000/month |
| Full Stack Engineer (React + TypeScript) | Middle | $2,000/month |
| Database Reliability Engineer | Senior | $3,000/month |
| QA Engineer + Performance Tester | Middle | $2,000/month |
Total team cost: $10,000/month.
Compare that to a US-based team: you’re looking at $80,000–$120,000/month for equivalent talent. The Vietnamese team was physically located in Ho Chi Minh City and Can Tho—our two primary hubs. They overlapped 4 hours with Austin time, which turned out to be plenty.
But here’s the real game-changer: we equipped every engineer with the ECOA AI Platform ACP.
—
The AI Orchestration That Made 5x Output Possible
Let me explain how the ECOA AI Platform ACP (Agent Coordination Platform) worked here.
We didn’t just throw a generic coding assistant at them. We configured role-specific AI agents that understood the codebase’s conventions:
- SQL Optimization Agent: An agent trained on PostgreSQL execution plans, indexing strategies, and the client’s specific schema. It could take an EXPLAIN ANALYZE output and suggest 3 concrete index changes in under 2 minutes.
- Code Refactor Agent: A TypeScript-aware agent that could refactor the monolithic Sequelize models into smaller, focused query objects.
- Cache Strategy Agent: This one analyzed query frequency patterns from production logs and recommended Redis cache keys and TTL values.
Each agent had access to the full codebase context and the project’s convention rules. They didn’t hallucinate because we constrained them to output only validated changes.
The result: Our team of 4 engineers delivered what would normally require a 10-person team. They wrote more code, with fewer bugs, and zero regression in the parts we didn’t touch.
—
The Optimization Playbook: 4 Steps That Delivered the 88% Cut
Step 1: Attack the N+1 Problem First (Week 1–2)
The biggest culprit wasn’t the main query. It was the 40+ implicit queries Sequelize fired when serializing the response.
We did two things:
- Eager loaded everything using explicit `include` statements with `required: true` where possible.
- Wrote a custom serializer that used a single `Promise.all` batch after the main SQL finished, reducing roundtrips from 40 to 3.
Latency impact: 4.2s → 2.1s. That’s a 50% cut with zero database changes.
Step 2: Selective Denormalization with Materialized Views (Week 3–4)
Our DBE built a materialized view called `listing_search_view` that flattened the 11-join query into a single table scan.
sql
CREATE MATERIALIZED VIEW listing_search_view AS
SELECT listings.id, listings.price, listings.bedrooms, listings.bathrooms,
listings.status, listings.year_built, listings.square_feet,
addresses.street, addresses.city, addresses.state, addresses.zip,
agents.name AS agent_name, offices.name AS office_name,
COUNT(DISTINCT photos.id) AS photo_count,
COUNT(DISTINCT open_houses.id) AS open_house_count
FROM listings
JOIN addresses ON addresses.listing_id = listings.id
JOIN agents ON agents.id = listings.agent_id
JOIN offices ON offices.id = agents.office_id
LEFT JOIN photos ON photos.listing_id = photos.is_primary = true
LEFT JOIN open_houses ON open_houses.listing_id = listings.id
WHERE listings.status = 'active'
GROUP BY listings.id, addresses.id, agents.id, offices.id;
We refreshed this view every 5 minutes using PostgreSQL’s `pg_cron` extension. It added 2 seconds of write load every 5 minutes—negligible.
Latency impact: 2.1s → 0.9s. Sub-second. The client was ecstatic.
Step 3: Redis Response Caching (Week 5–6)
Search data is highly cacheable. The same 20 filters applied by 100 different users return identical results for at least a few minutes.
We implemented a two-tier Redis cache:
- Tier 1: Exact query hash → response (TTL: 120 seconds)
- Tier 2: Partial key prefix (city + price range) → stale response with background refresh (TTL: 600 seconds)
The hit rate on Tier 1 was around 45%. Tier 2 brought it to 78%.
Latency impact: 0.9s → 0.5s. Average.
Step 4: Frontend Debouncing + Optimistic UI (Week 7)
The frontend was firing a search request on every keystroke in the filter panel. We added a 300ms debounce. Users never noticed the delay—they were still typing.
We also added an optimistic UI that rendered the previous search results instantly while the new query ran in the background.
Perceived latency: 0.5s → instantaneous for 65% of interactions.
—
The Final Numbers
| Metric | Before | After | Improvement |
|---|---|---|---|
| Average search latency | 4,200 ms | 500 ms | 88% |
| P95 search latency | 7,100 ms | 1,200 ms | 83% |
| Database CPU usage | 92% | 34% | 63% reduction |
| Page load time (end-to-end) | 5.8 s | 1.1 s | 81% |
The client’s organic conversion rate went up 23% in the following quarter. They also saved $4,200/month on their RDS instance by downgrading from a db.r6g.large to a db.r6g.xlarge.
Wait—that’s a downgrade? Yes. The reduced query load meant they didn’t need the larger instance anymore.
—
Why This Model Works (And Why It Won’t If You Micromanage)
I’ve seen countless offshore engagements fail because the client treated the remote team like low-cost code monkeys.
We didn’t do that.
Our Vietnamese engineers—augmented by ECOA AI agents—were given ownership of specific optimization blocks. The DBE owned the materialized view. The backend guy owned the caching layer. They weren’t following tickets; they were solving problems.
The ECOA AI Platform ACP gave them the leverage to experiment fast. They could ask the SQL agent, “What index would help this query?” and get an answer in 60 seconds. No waiting for a DBA. No context switching.
That’s real productivity. Not just “lines of code.”
—
Frequently Asked Questions
How did you handle communication with a 4-hour time zone overlap?
We used a shared Slack channel with daily async standups and a 30-minute synchronous handoff at 9 AM Austin / 1 PM HCMC time. The key was writing detailed, structured tickets in Linear with acceptance criteria, not relying on real-time chat. The ECOA AI agents also generated daily progress summaries automatically.
What if the materialized view becomes stale for real-time price changes?
The client’s data freshness requirement was 5–10 minutes. For the rare case where a listing just got marked “pending” and still appeared in search, we added a Redis cache invalidation hook that fired whenever the listings table was updated. The view refresh frequency was more than adequate.
Did you consider GraphQL or a dedicated search service like Algolia?
We evaluated Algolia. The cost projection for their data volume (2 million listings, 12 million photos) was around $8,000/month. The total cost of our optimization—team + infrastructure—was under $15,000 one-time. Algolia would have been the right call if they needed full-text search across descriptions or real-time faceting. They didn’t.
How can I replicate this setup for my own codebase?
Start by running `EXPLAIN ANALYZE` on your top 10 slowest queries. If you see sequential scans on large tables or more than 6 JOINs, you’re a candidate for materialized views and caching. If you want the full AI-augmented approach, reach out to us at ECOA AI. We can spin up a similar team in under 2 weeks.
Related reading: Outsourcing Software in 2025: Why Smart CTOs Are Ditching Local Dev Teams for Vietnam
Related reading: Why Smart CTOs Hire Vietnamese Developers in 2025: Cost, Quality & Speed