DEV Community

ihddirmas
ihddirmas

Posted on

How We Built StyleSense: AI Virtual Try-On Powered by Amazon Aurora & Vercel

Online clothing returns cost the industry over $816 billion a year. The root cause is simple: shoppers can't see how clothes look on their body before buying. We built StyleSense to fix that — an AI-powered virtual wardrobe where you upload a selfie, add clothes from any product URL, and instantly see yourself wearing them.

Here's how we built it, and why Amazon Aurora PostgreSQL and Vercel were the right choices for a 72-hour hackathon build.


The Stack

  • Frontend: Next.js 14 App Router + TypeScript + Tailwind CSS, deployed on Vercel
  • Backend: FastAPI (Python 3.12) with 50+ REST endpoints
  • Primary database: Amazon Aurora PostgreSQL Serverless v2 (ap-south-1)
  • Auth + Realtime: Supabase (JWT, Storage, social features)
  • AI: Runway ML (try-on, video, voice avatar) + Anthropic Claude (stylist chat, vision)

Why Amazon Aurora PostgreSQL

We needed a database that could handle:

  1. Bursts of writes during a live demo (multiple judges hitting Generate simultaneously)
  2. Zero idle cost — we're not paying for credits when no one is testing
  3. No secrets in code — hackathon repos get shared, credentials shouldn't

Aurora Serverless v2 solved all three. It scales to zero between test runs, scales up instantly under load, and supports IAM authentication — meaning our FastAPI backend never stores a database password.

IAM Auth in FastAPI — the key pattern

Instead of a static DATABASE_URL with a password, we use boto3 to mint a short-lived token at connection time:

import boto3

def get_iam_token():
    client = boto3.client("rds", region_name="ap-south-1")
    return client.generate_db_auth_token(
        DBHostname="stylesense.cluster-c9cswq8kqykn.ap-south-1.rds.amazonaws.com",
        Port=5432,
        DBUsername="stylesense_app",
        Region="ap-south-1",
    )
Enter fullscreen mode Exit fullscreen mode

We wire this into SQLAlchemy's connection pool via a custom creator function that refreshes the token before each new connection — tokens expire in 15 minutes, so this is essential:

from sqlalchemy import create_engine

engine = create_engine(
    "postgresql+psycopg2://",
    creator=lambda: psycopg2.connect(
        host=AURORA_HOST,
        port=5432,
        dbname="stylesense",
        user="stylesense_app",
        password=get_iam_token(),
        sslmode="require",
    )
)
Enter fullscreen mode Exit fullscreen mode

No password in .env. No password in CI. No password in the repo. Just an IAM role.

Schema design

We kept it lean — 4 core tables in Aurora:

Table What it stores
users Selfie URLs, stylized avatar URLs, body analysis
wardrobe_items Clothing images, categories, colors, source URLs
try_on_results Generated try-on images, event scenes, video URLs
outfits Saved outfit combinations

Auth and social (friendships, chat threads) stay in Supabase, which already has Row-Level Security and Realtime built in. Aurora handles the data that benefits from SQL joins and full ACID transactions — like "show me all try-ons for items in category X that this user saved as outfits."


Vercel: Zero-Config Frontend Deploys

Our Next.js frontend deploys to Vercel with three environment variables and zero configuration files. The things that made the biggest difference:

Edge middleware for auth: Supabase session refresh runs at the edge on every request, so protected pages never flash unauthenticated content. This is one middleware.ts file:

// middleware.ts
import { createServerClient } from "@supabase/ssr";
import { NextResponse } from "next/server";

export async function middleware(request: NextRequest) {
  // Refreshes the Supabase session cookie on every request
  // Redirects to /login if the user is not authenticated
}
Enter fullscreen mode Exit fullscreen mode

Mumbai region: We deployed both the Vercel frontend (bom1) and Aurora (ap-south-1) in Mumbai, keeping API latency under 20ms for the database round-trip.

The one gotcha: Runway ML requires all image URLs to be public HTTPS. Localhost URLs fail silently. Every selfie and wardrobe image gets re-hosted to Supabase Storage before being passed to any Runway API call — Vercel's environment variables made switching between dev and prod URLs painless.


The AI Pipeline

The "wow moment" flow that we demoed:

  1. Upload selfie → Claude vision detects body type
  2. Paste Amazon URL → scraper extracts product image → Runway garment cleaner isolates the clothing
  3. Try-on: Runway gen4_image composites the garment onto your selfie (~10s, 5 credits)
  4. Event scene: Runway gen4_image places you in a "beach wedding" or any setting you describe
  5. Animate: Runway gen4.5 turns the still into a 5-second runway walk video (~60s, 60-100 credits)
  6. Voice stylist: Aria (a Runway Characters API avatar) answers questions about your wardrobe in real time — her knowledge base is synced from Aurora at every session start

The entire pipeline is async. FastAPI fires each Runway task and returns a task ID; the frontend polls via Zustand store state that survives page navigation.


Challenges

Aurora IAM token refresh in connection pools: SQLAlchemy's connection pool reuses connections, so a token minted at startup expires mid-session. The fix: use NullPool or override the creator so a fresh token is minted for every logical connection. We went with the creator approach and a short pool recycle time.

Runway image URL requirement: Every image URL sent to Runway must be a public HTTPS URL. During development this means all local uploads get re-hosted to Supabase Storage before the Runway call — an extra round-trip but essential.

Credit budget discipline: Runway gen4.5 video costs 60-100 credits per 5 seconds. With a 50,000-credit budget, we used gen4_image_turbo (2 credits) for all dev testing and reserved the full quality models for demo recordings.


What We'd Do Differently

  • Aurora DSQL would eliminate connection management entirely — it's a serverless SQL database with no instance to configure. For a pure read-heavy workload like wardrobe browsing, it would be a better fit.
  • DynamoDB for the task queue — our current in-memory task store resets on server restart. DynamoDB TTL would give us persistent background task history.

Try It

The full source is on GitHub. The live demo runs on Vercel at [https://style-sense-steel.vercel.app/].

Built in 72 hours for the H0: Hack the Zero Stack with Vercel v0 and AWS Databases hackathon.

#H0Hackathon


Top comments (0)