← Back to Work iOS app

FreshKeeper

A fridge and pantry tracker that warns you before food expires, suggests what to cook, and builds your grocery list for you.

Role: Design + iOS development Swift ยท SwiftUI ยท SwiftData Built Sep 2026 Runs on iPhone iOS 27
GroceryApp icon: a white fridge with a green leaf on a green gradient
designed by me in Figma
Genesis

From a sketch to an app on my phone

I started with a product idea and a set of lo-fi wireframes: a mobile app for managing what's in the kitchen, paired with a small display that sits on the fridge. Then I built the mobile app natively for iPhone in Xcode with SwiftUI, learning Swift as I went. The app tracks fridge and pantry items, reminds you before food expires, suggests a recipe that uses what you have, and builds your grocery list automatically.

Early lo-fi sketches
Core home dashboard & quick-add flows.
App icon paper drawings
Paper drawings of the app icon.
FreshKeeper in action Live Demo

Running natively on iOS with real-time expiry tracking and inventory management.

The Problem

Food gets forgotten

Things expire at the back of the fridge, and staples run out without anyone noticing. At the store you don't remember what's already at home. And when it's time to cook, it's hard to think of a meal that uses what you have.

The Solution

One place that keeps track for you

FreshKeeper tracks fridge and pantry items with their expiry dates, reminds you before food goes bad, suggests a meal that uses up what's expiring, and turns running-low items into a grocery list that restocks your inventory when you shop.

What matters today At a glance

The home dashboard shows what's expiring and what's running low, with the most urgent items in red and the next-most urgent in orange.

๐Ÿฅฌ Spinach 2 days
๐Ÿ“ Berries 3 days
๐Ÿฅ› Milk 4 days
Glanceability

Designed for quick daily checks

By surfacing expiry dates on the first screen, users know straight away which ingredients to use up before they spoil.

Capabilities

Features

Home dashboard

Expiring soon, a recipe idea that uses up expiring food, and a quick list of items running low.

Inventory

Fridge / Pantry / All filters, sorted soonest-expiring first, with swipe to delete.

Add & edit items

A quick form with emoji picker, units, expiry date and a "running low" threshold. Edits save as you type.

Barcode scanning

Scan a package to fill in its name, emoji and whether it goes in the fridge or pantry.

Expiry reminders

A notification at 9 AM, a set number of days before each item expires. Adjustable for every item.

Smart grocery list

Suggests running-low items with amounts to buy. Checking one off restocks the inventory.

Key Interaction

The restock loop

The part I'm proudest of is how the screens connect. Each item can have a "running low" level. When the quantity drops to that level, the item appears on the dashboard and is suggested on the grocery list with an amount to buy. Checking it off at the store adds that amount back to the inventory, and it drops off the list.

๐Ÿฅš Eggs: 2 left
โ†’
๐Ÿ›’ Running low
โ†’
๐Ÿ“ Grocery list: buy 4
โ†’
โœ… Checked off
โ†’
๐Ÿ“ฆ Inventory: 6
Execution

How the build unfolded

I built the app one screen at a time, running it after every step and committing each working version to Git.

Architecture

A small, readable data model

@Model
final class Item {
    var name: String
    var location: StorageLocation   // fridge or pantry
    var quantity: Double
    var expiresOn: Date?           // pantry staples may not have one
    var lowThreshold: Double?      // at or below this = "running low"
    var remindDaysBefore: Int = 2
}
Problem Solving

Challenges & solutions

Camera scanner black screen

Challenge
The barcode scanner opened but never showed an image.
Solution
Switched from VisionKit to AVFoundation's barcode reader, then added on-screen messages that report why the camera is interrupted. The cause turned out to be iPhone Mirroring, which blocks the camera.

Moving to saved data

Challenge
Switching the model to SwiftData touched almost every file and broke the previews.
Solution
Converted the model to an @Model class, replaced the shared store with @Query, and made an in-memory database for previews.
Engineering

Tech stack

I created and assembled every file in Xcode myself, debugged the build errors, and tested each feature on the simulator and on my iPhone.

#Swift #SwiftUI #SwiftData #Xcode #UserNotifications #AVFoundation #Git #Figma #UserResearch #InformationArchitecture #UIUX #DataFlow
Takeaways

What I learned

Future Vision

Roadmap