Personal · Since 2020 · Travel · AI
One catalog, checked replies
WDW Planner
A hobby app for planning a day at EPCOT's food festivals, with 30-plus booths and hundreds of dishes.

- My role
- Product Design, Brand & Design System, iOS and Android Engineering, AI Integration
- Team
- Solo: product, design, brand, iOS, Android, and AI backend
- When
- Since 2020 · Paused after 2021; updated after Meta
- Platforms
- iOS and Android
- sign-ups since 2020
- 675
- shipped to both stores
- iOS + Android
- catalog items backfilled with stable slugsProject scope
- ~560
The 30-second version
- Problem
- Festival information is scattered and changes each season. Re-imports give the same dishes new database IDs.
- What I did
- Built both native apps and the backend, with one catalog and a server check on every dish, drink and date Pyxi mentions.
- Result
- Live on both stores, with 675 sign-ups recorded in Firebase Auth since 2020 and no advertising.
Context and constraints
I built the first version in 2020 and stopped updating it after 2021, when I started at Meta. After leaving Meta, I redesigned the app and released an update.
WDW Planner is for EPCOT's four food festivals. Each one has thirty-plus booths and hundreds of dishes and drinks, plus concerts, seminars, scavenger hunts, and runDisney races. The info is scattered and changes every season, so it's hard to plan around once you're in the park. I designed and built the whole thing myself, on top of one live catalog. The app plans your day, and Pyxi, the AI concierge, can't make up facts, because everything it says comes from that catalog.
My role and the team
I did all of it: the data model, the UX, the brand, the iOS app in SwiftUI, the Android app in Kotlin, and the AI backend. The part I'm proudest of is how Pyxi is kept from making things up.
The problem
EPCOT runs four food festivals a year. Each one has 30-plus outdoor kitchens with their own small plates and drinks, plus concerts, seminars, scavenger hunts, and runDisney races. The official info is scattered and resets every season, so people plan with spreadsheets, screenshots, and a dozen browser tabs, and still miss the gluten-free dish or the booth that's only there this year.
There was a technical problem under that too. Every season the catalog gets re-imported with brand-new database IDs, so the same dish looks like a different dish from one year to the next. The app had to be easy to use and survive a full rebuild of its data every few months.
Key decisions
01 / 02
Check every recommendation
- Options
- Use Claude to write the conversation and the catalog to supply its facts.
- The call
- Look up every dish, drink and date by ID on the server. Drop anything not found in the catalog.
- Why
- Claude writes the replies, but a festival app cannot make up a dish or a price.
02 / 02
Keep the same dish key each season
- The call
- Backfill stable slugs across about 560 catalog items.
- Why
- Seasonal imports create new database IDs. A stable key keeps the same dish connected from year to year.
The work
How it scaled
The server checks Pyxi’s recommendations against the catalog before returning them. Stable slugs keep dishes connected through seasonal data imports.
Pyxi checks the catalog
01
You ask Pyxi
About dishes or a crawl.
02
Claude writes the reply
It names dishes, drinks and dates.
03 · Server check
In the catalog?
Look up every item by ID in the catalog.
Yes
What you see
The reply, with dish cards from the catalog.
No
Dropped
Anything not found never reaches you.
Results
Firebase Auth shows 675 sign-ups since 2020. I haven't advertised the app.
Live on the App Store and Google Play, with 560-plus dishes across all four festivals in one catalog. Pyxi, the AI concierge, can't invent a dish, a price, or a date, because every fact it mentions comes from that catalog.
- sign-ups since 2020
- 675
- Count from Firebase Auth. I haven't advertised the app.
- shipped to both stores
- iOS + Android
- catalog items backfilled with stable slugs
- ~560
Reflection
I had to ground Pyxi, because a festival app can't make up a dish or a price. That ended up being my favorite part of the project. Anything I build with AI now works the same way. The facts come from a database, and the model only writes around them.