Inspiration

Every move-out week, perfectly good furniture, lamps, and kitchen gear end up on the curb or in a dumpster, while a few blocks away a new renter is buying the same things. Resale apps don't fix this. Pricing, haggling, and shipping add friction, and anything that isn't worth selling still gets thrown away. We wanted an app that optimizes for one thing: does this help an item find its next use? The name comes from the Greek ανανέωση, "renewal." The tagline is *Give More. Waste Less. Keep It Moving.

What it does

Ananeo is an iOS app for giving away, swapping, and reusing items locally. There are no prices, no checkout, and no seller ratings tied to money.

  • Give. Post an item in under a minute with photos, category, condition, and an approximate pickup area.
  • Browse. See a feed of items near you, sorted by distance.
  • Pickups. Request an item, let the giver reserve it for you, and both sides confirm the handoff.
  • Chat. Message the giver or requester on each pickup request, with live unread counts.
  • Donate and repair. Find donation centers and repair spots for things nobody claims.
  • Impact. Track items given, items received, and kilograms kept out of landfill. Impact only counts once both people confirm a handoff.

How we built it

  • iOS: SwiftUI on iOS 18, with Sign in with Apple, MapKit, and PhotosPicker. Services are @Observable and views reload off a simple revision counter.
  • Backend: Supabase. Postgres with PostGIS answers "what's within 10 km of me" as a single indexed query. Supabase Auth, Storage, and Realtime handle sign-in, photos, and live chat.
  • Privacy by default: a database trigger fuzzes every listing's location by up to 400 meters before it is stored. The exact point is never persisted. Exact addresses are only shared in chat, by choice.
  • Security: Row Level Security on every table. Anything that touches more than one row, like reserving an item or confirming a handoff, goes through a security definer function so clients can never put an item into an invalid state.
  • Images: photos are resized on-device to 1600 px and uploaded as JPEG to keep storage and bandwidth cheap.
  • Tests: a pgTAP suite runs against a local Supabase stack and checks that users can't read other people's chats, backdate requests, spoof senders, or edit reserved items.

Challenges we ran into

  • Modeling a handoff without money. A marketplace has an order. We had nothing. We landed on a conversation doubling as a pickup request: the receiver opens one from a listing, the giver reserves the item for one requester, chat hangs off the same row, and withdrawing a request removes its chat.
  • Getting RLS right. Early policies let clients set their own message timestamps and senders. We moved those to server-side defaults and wrote tests that try to break every rule.
  • Live chat without a server. Supabase Realtime streams rows, but RLS decides who receives what, so one channel per signed-in user is enough for inbox counts.
  • No Xcode in the cloud. Our automation environment can't compile Swift, so we built database tests that run anywhere and kept iOS builds on a Mac.

Accomplishments that we're proud of

  • A complete give-to-handoff loop that works end to end. Post an item with photos, see it appear in a neighbor's nearby feed, request it, get reserved, chat about a pickup time, and confirm the handoff from both sides. Every step is real, backed by the database, not mocked.
  • Privacy that can't be bypassed. Listing locations are fuzzed by a database trigger before they are written, so the exact point never exists on the server. Even a bug in the app can't leak someone's address.
  • Rules that live in the database, not the app. Reserving, cancelling, confirming, and withdrawing all go through server-side functions guarded by Row Level Security. A client cannot reserve an item for someone who never asked, edit a reserved listing, backdate a request, or spoof a message sender.
  • Tests that try to break the security model. A pgTAP suite with dozens of assertions runs against a local Supabase stack and checks that users cannot read other people's chats or tamper with timestamps and senders. It caught two real holes before launch.
  • Live chat with almost no backend code. Supabase Realtime streams message rows, and Row Level Security decides who receives what, so one channel per signed-in user keeps inbox unread counts current.
  • An honest impact number. Kilograms diverted only count after both people confirm a handoff, and the totals come from a view that can't be edited directly.
  • A backend built for three platforms on day one. Nothing in the API depends on iOS, so the planned Android and web clients inherit the same guarantees for free.

What we learned

Putting the rules in the database instead of the app meant the Android and web clients we plan next get the same guarantees for free. We also learned that "measured in kilograms diverted" changes design decisions: every feature has to end in a confirmed handoff or it doesn't count.

What's next

Swap offers between listings, community challenges like "Move-out Week: 500 items kept moving," push notifications, a partner dashboard for campuses and cities, and an Android app on the same backend.

Built With

Share this project:

Updates

Submission history