Project Detail

Dish Today

Meal planning, listing & sharing app

Challenge: Browser storage limits for large planner state

Next.js, TypeScript, Prisma, PostgreSQL, Tailwind CSS

Dish Today app preview
Demo

Short walkthrough of the weekly planner, grocery list generation, and ingredient marketplace.

Problem

Most meal planning apps become slow or fragile when users build up large amounts of data such as recipes, images, and weekly plans. I wanted to create a planner that stays responsive, works smoothly in the browser, and remains usable even under storage constraints.

What I Built

I built Dish Today to keep daily interactions fast while supporting social features:

  • Personal recipe library with public and private recipes
  • Drag-and-drop weekly meal planner
  • Grocery list generation
  • Ingredient-based recipe suggestions
  • Community ingredient market with map support
Technical Highlight

Hybrid persistence for quota-safe local-first planning

The hardest part of this project was storing complex user-generated planner data reliably in the browser. Weekly boards, recipes, and images can grow quickly, which makes browser storage quotas a real constraint.

I solved this with a hybrid persistence system:

  • localStorage for fast access
  • IndexedDB fallback for larger payloads
  • Metadata markers to coordinate storage targets
  • Quota recovery through image recompression and cleanup
  • Generation-based saves so async recovery cannot overwrite newer state
Architecture & Decisions

The architecture separates highly interactive planner state from shared social data to preserve responsiveness and keep collaboration features scalable.

Client

Next.js App Router UI with interactive planner state and local persistence.

Server

Prisma + PostgreSQL for accounts, published recipes, follows, and market listings.

Data strategy

Planner state is local-first while shared and social data is stored on the server.

Key Engineering Decisions

Offline-first planner

Prioritized speed and responsiveness for planning sessions, with a more complex local persistence layer.

Client/server responsibility split

Kept heavy interactive state close to the UI while centralizing shared data, reducing server chatter during planning.

Graceful degradation under storage pressure

Preserved data integrity and continuity at the cost of extra recovery logic and state versioning.

Trade-offs & Next Steps

Current Limitations

  • Planner state is primarily device-local, not fully cloud-synced.
  • Browser storage limits still constrain rich media.
  • Local-first design adds persistence complexity.

Planned Improvements

  • Add multi-device sync.
  • Move image storage to object storage/CDN.
  • Improve ingredient matching.
  • Add conflict resolution for sync.