Skip to content
All work

Case study. Next.js / GenAI.

Aether Wardrobe

Personal AI stylist with a deterministic outfit engine

Role
Solo: schema + RLS, candidate engine, AI call sites, UI, deployment
Status
Livev1.1.0MITinvitation-only
Context
2026, personal
AI-invented outfits
0
Score to keep a pairing
≥ 7.0
Vision cost per catalogued item
1–3¢
Vitest cases on the deterministic core
38

v1.1.0, October 2026; plus CI with type-check, build without secrets and a secret scan

Aether Wardrobe AI stylist interface
  • Onboarding page, Trust section: 'Deterministic first, one small AI call last' — you confirm every tag, code builds every pairing (one watch, one belt, matching metals), the AI only scores and explains
  • Onboarding page, The tabs: Wardrobe, Outfits, Today, Shop, Settings and Access, each with its one job
  • Onboarding page, How it works: six steps from a photo to today's outfit

The problem

'What should I wear today?' is a constraint problem — formality, season, color, the weather where you're actually going — but AI stylists typically answer it by hallucinating outfits from a text description of a wardrobe, inventing pieces you don't own and burning tokens on every request. The wardrobe data had to become the source of truth, with the model demoted to ranking and explaining.

Architecture

  1. 1.Catalog
    • Photo upload / camera
    • GPT-4o vision tags
    • Owner notes win
  2. 2.Candidate engine
    • Pure TS, deterministic
    • Formality · season · color
    • Metal tones matched
  3. 3.Score
    • gpt-4o-mini, batches of 12
    • Keep ≥ 7.0 only
  4. 4.Combinations table
    • Single source of truth
    • Postgres + RLS
  5. 5.Daily pick
    • Occasion + destination
    • Forecast → SQL filter
    • One call ranks 5–7, picks the watch, explains
Aether Wardrobe — photo to vetted outfitThe AI never invents outfits at recommendation time — it only ranks and explains what the table already vetted.

What it does

Photograph each piece once — gallery or phone camera — and GPT-4o vision reads cut, color, pattern and material, with the owner's notes always overriding what the model sees. Confirmed items feed a combination table, and each morning an occasion plus an optional destination produces ranked, weather-aware outfit picks with a 'why this outfit' rationale that uses actual item names.

  • Granular categories down to footwear types (loafers, drivers, sneakers)
  • Watches carry a style (dress, sports, diver, GMT, chronograph, field, pilot), a band and a hardware tone; belts, sunglasses and bags carry a metal tone — read from the photo, corrected with chips
  • City autocomplete resolves the exact forecast location
  • Outfits browser with boost/hide, 'resting' looks, filters by outerwear or accessory, and the most complete outfits first

Deterministic engine, AI referee

A pure-TypeScript candidate engine pairs every confirmed piece against the whole wardrobe through formality, season and color-clash filters; gpt-4o-mini then scores candidates in batches of 12, and only pairings scoring ≥ 7.0 enter the table. At recommendation time the AI never invents an outfit — it re-ranks and explains what the table already vetted. Same discipline as the enterprise work: the deterministic system computes, the model narrates.

v1.1.0 taught the engine about metals. It never pairs two accessories of the same type, and once the first metal piece is chosen it prefers the same hardware tone, so a silver watch gets a silver buckle; the scoring prompt rewards a watch whose formality fits the outfit and penalizes a diver with a suit. The benefit is outfits that look put together, not merely valid.

  • 'Build around a piece' filters the table to a single item
  • Background generation with an app-wide readiness banner
  • ~$0.01–0.03 per uploaded item; fractions of a cent per daily request

Daily recommendations

Pick one of ten occasions — work, indoors or conferences, lunch, dinner, the park — and optionally a destination and notes; the app pulls the OpenWeatherMap forecast at the resolved city, SQL-filters the combination table, and one AI call ranks five to seven picks from a pool of sixteen candidates (was three to five from twelve). The same call now chooses the day's watch, belt or sunglasses for each outfit — a GMT for travel, a dressier watch for dinner, sunglasses only when the day is bright — and the wear log records what was actually worn. One call per request, because the hard filtering already happened in the database.

Shopping gap analysis

Tick the categories you're shopping for and the app counts how many new outfits one good piece would unlock — computed against the actual wardrobe by the same candidate engine, not guessed — then suggests specific items to buy.

v1.1.0: tests, CI and a bug that mattered

The release added the first test suite: 38 Vitest cases on the deterministic core, including accessory picking, metal matching, readiness and the gap analysis, and a GitHub Actions workflow that type-checks, runs the suite, builds for production without secrets and scans the full git history for leaked credentials. It also fixed a real defect: the combinations uniqueness index ignored accessories, so a second watch or belt silently never entered any outfit; the index now covers the accessory set and inserts retry row by row instead of discarding a batch.

  • A public onboarding site at /welcome, a user guide and an architecture diagram ship with the app
  • The AI call sites are deliberately not unit-tested; the contract they must obey is

Security and cost control

  • Invitation-only — every AI endpoint verifies the access allowlist server-side before spending API credits, with in-app admin grant/revoke
  • Row-level security on every table
  • Wardrobe photos in a private bucket behind short-lived signed URLs
  • OpenAI and weather keys server-side only

Stack

  • Next.js 16
  • TypeScript
  • Tailwind v4
  • shadcn/ui
  • Supabase
  • OpenAI GPT-4o (vision)
  • Vercel AI SDK
  • OpenWeatherMap
  • React Three Fiber
  • Zustand

Related work