Skip to content

WorkAcademic

Lost and found tracking system

BRAC University · 2025

A Flask application for reporting lost and found items on campus, built by a team of four for CSE471, System Analysis and Design. My part was reporting, the engine that matches lost reports with found ones, and sharing a report to social media. Teammates built login and the admin panel, the chat, and ownership verification.

PythonFlaskSQLAlchemyPostgreSQLGemini embeddingsscikit-learnSocket.IOBootstrap
01

The problem

Campus lost and found runs on noticeboards and group chats, so the two halves rarely meet: the person who lost a bag and the person who found it post in different places, days apart, in different words. A lost “brown wallet” and a found “brown leather wallet” are the same item to a person and two different strings to a database.

02

The system

  1. Report

    lost or found, one table

  2. Embed

    Gemini, cached on disk

  3. Compare

    cosine similarity

  4. Score

    same category +0.2

  5. Notify

    0.5 or above

Every new report is compared with every report of the opposite type. Nothing is resolved automatically: the owner is told the score and decides.

Reporting

Lost and found reports are one model with a type, so matching is a query across one table. A report carries a category, name, description, place, date, preferred contact method and an optional image.

Matching by meaning

Each report's name, description, category and location become one Gemini embedding, compared with every report of the opposite type by cosine similarity. A shared category adds 0.2, and anything scoring 0.5 or above appears under Potential Matches, with a notification that states the score.

Embeddings cached on disk

The text is hashed and its embedding stored locally, so the same text is only ever sent to the API once, however many comparisons it takes part in.

Sharing a report

A report can be posted to Facebook, X, WhatsApp or Telegram through each platform's share link, prefilled with the item's details. No API keys and no accounts to connect.

Built by teammates

Login and roles, the admin panel, real-time chat over Socket.IO, and ownership verification, where a claimant has to supply details the public listing leaves out.

The user dashboard: profile, counts of posts and lost and found items, a Potential Matches section, recent lost and found reports as cards, and a top contributors list.
The dashboard: posts, potential matches, recent activity and top contributors.
The Report Lost Item form with category, name, description, date, place, preferred contact method and image fields.
Reporting a lost item.
The My Conversations page, empty.
Conversations, where the two sides of a match talk.
The Admin Control Panel with totals for users, active users, pending reports and posts, and buttons to manage users, posts and reports.
The admin control panel, with test data.
The login page with email and password fields.
Login.
03

Technical decisions

What was chosen, what was chosen against, and what the trade cost.

01
Chose
Embeddings compared by cosine similarity.
Instead of
Matching on category, location and date with a database query.
Why
People describe the same object in different words, and a query only matches words. Embeddings match meaning. The cost is an external API call for each new piece of text, and a score that needs a threshold somebody has to choose.
02
Chose
A disk cache keyed by a hash of the text.
Instead of
Calling the embedding API on every comparison.
Why
Each new report is compared with every report of the other type, so without a cache the same descriptions would be embedded again with every post. A repeat costs nothing, and an edited report hashes differently and gets a fresh embedding.
03
Chose
A category bonus on top of the similarity score.
Instead of
Similarity alone.
Why
Descriptions of different kinds of object can read alike. A shared category is cheap, reliable evidence that two reports are about the same kind of thing, so it lifts like with like above the threshold.
04
Chose
Notifying with a score, never resolving a match automatically.
Instead of
Closing a pair above a confidence threshold.
Why
The two failure directions are not symmetric. A missed match wastes a little time; a wrong automatic match hands someone else's property away and the system was the one that decided it. Keeping a person in the loop costs a click.
04

The result

A working platform, deployed on Render for the course. The part I would talk about is the matching: pairing reports by what they mean rather than by the words they share, with a person confirming every match.