Under the hood
Technology & privacy approach
Lost&Found is built around a set of privacy decisions that are architectural, not cosmetic — enforced at the database level, not just in the app code.
Location privacy
Your location is never pinpointed
This was a founding constraint. Everything around location was designed to ensure the precise place where you lost or found something cannot be inferred by other users.
The device location is captured at submit time. It is a precise GPS coordinate at this point.
A server-side function rounds the coordinate to a grid cell and runs reverse geocoding to produce a neighbourhood-level label.
Discovery shows the coarse label — a neighbourhood, district, or city block. The precise coordinate is never returned by any public query.
After an item is returned or closed, a scheduled job nulls the precise coordinate after the retention window. The coarse label stays.
Privacy architecture
Four pillars
Two-tier location
Your precise coordinates are captured once — at the moment you submit a report — and stored server-side. What other users see is a coarse neighbourhood-level label, never a pinpoint. After the item is returned or closed, the precise coordinate is automatically deleted after a configurable retention window. The coarse label stays for reference.
Ownership verification, kept private
When you report a found item, you write a private description that only the true owner would know. When someone claims it, they answer your questions privately. Your "answer key" is never shown to the public, other claimants, or anyone except you. A claimant's answers are visible only to you, the reviewer.
Three data privacy tiers
Every item has three distinct layers of data. The first layer is public: category, approximate area, date, title, description, photos. The second layer is private: the detailed verification information. The third layer is private-to-owner: your contact details, precise location, and account info. Layers two and three are enforced at the database level, not just the application.
Chat only after acceptance
Private messages exist only once a claim is accepted. You cannot send an unsolicited message about any item. Once opened, the chat is visible only to the two participants, and it closes automatically once the return is confirmed.
Authorization is enforced at the database, not the app
Every table in the Lost&Found database has Row Level Security (RLS) enabled with a default-deny policy. The app code cannot bypass it. If the database rule says a user cannot read a row, no application path — regardless of whether it contains a bug — can return that row. Private verification details, exact coordinates, and private conversations each have their own narrowly scoped policies.
This approach, called "defense in depth," means we do not rely on the app never making a mistake. The database is the final, enforced gate.
Stack
What it's built with
| Layer | Technology | Note |
|---|---|---|
| App | React Native + Expo (iOS & Android) | TypeScript throughout, strict mode |
| Navigation | Expo Router — file-based routing | Typed deep links for claims and conversations |
| Backend | Supabase (Postgres + Auth + Storage + Realtime) | Single managed backend for V1 |
| Database | PostgreSQL + PostGIS | All authorization enforced via Row Level Security |
| Auth | Email OTP — no passwords, no phone | Session stored in device keychain / keystore |
| Geocoding | Mapbox (server-side only) | App never calls Mapbox; token is server-only |
| File storage | Supabase Storage, private buckets | Short-lived signed URLs; direct public links do not exist |
Map data attribution
Neighbourhood-level area labels are derived from Mapbox and OpenStreetMap data. Reverse geocoding runs server-side only — the app itself never calls Mapbox, and the Mapbox API key is never present in the client.