DEV Community

Cover image for Building Fridge AI Health: An AI-Native Full-Stack App with Vercel and Amazon Aurora
Yuuki Yamashita
Yuuki Yamashita

Posted on

Building Fridge AI Health: An AI-Native Full-Stack App with Vercel and Amazon Aurora

Snap a photo of your fridge, and an AI plans meals around your health goals, tracks your nutrition, and coaches you every week — in 7 languages.

🔗 Live demo: https://fridge-ai-app.vercel.app
💻 Source: https://github.com/yama3133/fridge-ai-menu


What I built

Fridge AI Health turns a single photo of your fridge into a personalized, health-aware meal plan.

The flow is simple:

  1. Take a photo of the inside of your fridge.
  2. The app recognizes the ingredients (OCR + vision).
  3. An AI proposes menus tailored to your health goals (calories, protein, sodium limit, fiber), each with a nutrition breakdown.
  4. You tap "Ate this" to log a meal.
  5. A nutrition dashboard visualizes your daily progress and a 7-day trend.
  6. The AI Health Coach analyzes your accumulated logs and gives concrete weekly advice.

It started as a simple "what can I cook with this?" demo, and grew into a continuous health-management tool — which is exactly where a real database earns its keep.

The stack

  • Frontend / hosting: Next.js (Pages Router) on Vercel
  • Database: Amazon Aurora PostgreSQL, provisioned through the Vercel Marketplace AWS integration
  • AI: Amazon Bedrock — Claude Sonnet 4.5 (us-east-1) for both menu generation and the weekly coach
  • Vision: Google Cloud Vision (TEXT_DETECTION) for reading product labels
  • ORM / auth: Drizzle ORM + NextAuth (Google OAuth) with the Drizzle adapter
  • Charts / i18n: Recharts, plus a small homemade i18n layer (7 languages)

The data model is intentionally relational: users, accounts, sessions, health_profiles, meal_logs, and coach_advices. The coach feature is the whole reason a database matters — it reads back what you've eaten over the last 7 days, aggregates it, and feeds that to the model. The value isn't in storing data; it's in what the AI does with the accumulated data.

Why this fits "frontend in minutes, scalable backend"

The hackathon's pitch is "build a frontend in minutes and a scalable backend." That mapped almost perfectly to how this came together:

  • The UI (camera capture, menu cards, dashboard, coach) is plain Next.js + Recharts.
  • The backend scalability comes for free from Aurora PostgreSQL behind Vercel serverless functions.
  • The "AI-native" part is Bedrock doing the heavy lifting on both the menu and the coaching side.

The hard parts (where I actually spent my time)

The happy path is boring to read about. Here's what actually cost me hours.

1. Aurora DSQL looked perfect — until foreign keys

My first instinct was Aurora DSQL: serverless, PostgreSQL-compatible, scales to zero. Great fit for a hackathon.

Then I checked the compatibility docs. DSQL does not support foreign key constraints (along with triggers, views, sequences at the time, etc.). My schema leans heavily on ON DELETE CASCADE foreign keys — every app table references users. Migrating would have meant ripping out referential integrity and re-implementing it in the application layer.

For a one-week build, that was too much risk. I switched to Aurora PostgreSQL, kept my schema as-is, and moved on. Lesson: "PostgreSQL-compatible" is a spectrum — always check the unsupported-features list before you commit your schema.

2. Passwordless DB access with Vercel OIDC + RDS IAM

The Vercel Marketplace Aurora integration doesn't hand you a DATABASE_URL with a password. Instead it sets up RDS IAM authentication via Vercel's OIDC federation — your serverless function assumes an AWS role and generates a short-lived token that acts as the DB password. No secrets hardcoded anywhere. Very nice... once it works.

My lib/db ended up supporting both modes — a connection string for local Docker, and IAM tokens for production:

import { Signer } from '@aws-sdk/rds-signer'
import { awsCredentialsProvider } from '@vercel/functions/oidc'

const signer = new Signer({
  hostname: process.env.DATABASE_PGHOST,
  port: Number(process.env.DATABASE_PGPORT),
  username: process.env.DATABASE_PGUSER,
  region: process.env.DATABASE_AWS_REGION,
  credentials: awsCredentialsProvider({
    roleArn: process.env.DATABASE_AWS_ROLE_ARN,
    clientConfig: { region: process.env.DATABASE_AWS_REGION },
  }),
})

const pool = new Pool({
  host: process.env.DATABASE_PGHOST,
  user: process.env.DATABASE_PGUSER,
  database: process.env.DATABASE_PGDATABASE,
  port: Number(process.env.DATABASE_PGPORT),
  password: () => signer.getAuthToken(), // fresh token per connection
  ssl: { rejectUnauthorized: false },
})
Enter fullscreen mode Exit fullscreen mode

3. "No OpenIDConnect provider found"

First production connection attempt:

No OpenIDConnect provider found in your account for
https://oidc.vercel.com/<team>
Enter fullscreen mode Exit fullscreen mode

The IAM role existed (the integration created it), but the OIDC identity provider it trusts did not. The role's trust policy pointed at oidc.vercel.com/<team> as a federated principal — and that provider simply wasn't registered in my AWS account.

The fix was one command:

aws iam create-open-id-connect-provider \
  --url "https://oidc.vercel.com/<team>" \
  --client-id-list "https://vercel.com/<team>"
Enter fullscreen mode Exit fullscreen mode

Right after that, my migration endpoint reported current_user: postgres, can_create: true, and the tables went in. There's also a subtle gotcha worth flagging: the Aurora instance is not publicly accessible, so you can't just psql into it from your laptop — the Vercel-function-over-OIDC path is the way in. I ran migrations through a tiny, secret-protected /api/admin/migrate endpoint (and deleted it once the schema was applied).

4. Bigger model ≠ better product

For the AI, I assumed "use the most powerful model available." So I tried swapping Claude Sonnet 4.5 for an Opus model.

The result was instructive: Opus over-engineered the recipes. It happily designed elaborate dishes that required konjac, burdock root, daikon — ingredients that weren't in the fridge — which blew up the shopping list and quietly broke the app's core premise of cook with what you already have. It was also slower.

Sonnet 4.5 stayed closer to the detected ingredients, ran faster, and matched the product's intent better. I reverted. The "best" model is the one that fits the job, not the one with the highest benchmark.

Features I'm happy with

  • Health-aware generation. The user's profile (target calories, protein, sodium cap, fiber, goal) is injected straight into the prompt, so the menus actually respect "I'm cutting" vs "I'm bulking."
  • Structured shopping list. Each menu splits ingredients into in your fridge (blue) vs to buy (orange), and the page aggregates every "to buy" item into one shopping list. This also fixed an earlier inconsistency where the model would sometimes tag missing items and sometimes not — structuring the output removed the ambiguity.
  • The AI Health Coach. This is the centerpiece. It pulls the last 7 days from meal_logs, computes daily averages vs targets, and asks Claude for a summary, what's going well, what to improve, and concrete suggestions for tomorrow — returned as JSON and stored in coach_advices. Watching it say "your protein is great but you're ~340 kcal short and low on fiber — add whole grains tomorrow," grounded in real logged data, is the moment the whole app clicks.
  • 7 languages. UI strings and the AI-generated menu text both switch between Japanese, English, Chinese, Korean, French, Spanish, and Portuguese — the language code is passed into the Bedrock prompt so the recipe names and descriptions come back localized.

What I'd do next

  • Move nutrition numbers from model estimates to a real nutrition API for accuracy.
  • Persist and chart the coach's weekly advice history as a trend.
  • Add household/shared fridges — a natural multi-user extension now that the relational schema and auth are in place.

Takeaways

  1. Check the database's unsupported features before designing your schema. It saved me from a painful DSQL migration mid-build.
  2. Passwordless IAM + OIDC is worth the setup. Once the OIDC provider is registered, you get short-lived credentials with zero secrets in your env.
  3. Let the product pick the model. A more powerful model made the experience worse here.
  4. A database becomes interesting when AI reads it back. Logging meals is mundane; an AI coach reasoning over a week of logs is the feature people remember.

Vercel handled the frontend and serverless glue, Aurora PostgreSQL handled the durable, relational core, and Bedrock turned stored data into advice. That combination is exactly the "AI-native full-stack" loop this hackathon is about.

Built for the H0 Hackathon (Vercel × AWS Databases).

Top comments (1)

Collapse
 
richard_smith_154156d471ef profile image
Richard Smith

The "PostgreSQL-compatible" gotcha is so real. Spent time on this myself — always read the unsupported features list before you build your schema around it.