Skip to content

WorkAcademic

Lost and found tracking system

BRAC University · 2025

A Flask application for reporting lost and found items, with automated matching between the two, authentication, and role-based access. It looks like a straightforward CRUD project and mostly is, except for one part, which is that a system connecting owners to their property is also a system for handing property to whoever asks first.

PythonFlaskSQLAlchemyPostgreSQLSQLiteBootstrap
01

The problem

Campus lost-and-found runs on noticeboards and group chats, so the two halves never meet: the person who lost a bag and the person who found it are both posting, in different places, days apart. The obvious fix is a shared database with matching over it. The less obvious problem is what happens the moment a found item is listed in full detail, at which point the listing itself tells anyone reading exactly what to claim.

02

The system

  1. Report

    lost or found, one schema

  2. Match

    category, place, window

  3. Candidate

    a human confirms

  4. Challenge

    the claimant supplies it

  5. Release

    administrator resolves

Matching is the middle of this, not the end of it. The last two steps are where the design decision lives: a candidate match is a suggestion, and the detail withheld from the listing is what a claimant has to produce.

Two report types over one schema

Lost reports and found reports are the same entity with a direction, so matching is a query across one table rather than a reconciliation between two. The relational schema is normalised around items, users, reports, and claims.

Automated matching

New reports are matched against open reports of the opposite direction on category, location, and time window, producing candidate matches for a human to confirm rather than automatic resolutions.

Authentication and roles

Ordinary users report and claim; administrators moderate listings and resolve disputes. Role checks sit in the service layer rather than in templates, so hiding a button is a presentation detail and not the security boundary.

MVC structure

Routes, services, and models kept separate, with SQLAlchemy handling persistence, which is enough structure that the matching logic is testable without a request in flight.

03

Technical decisions

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

01
Chose
Withholding identifying details from public listings, and verifying a claim by asking the claimant to supply them.
Instead of
Listing found items in full and resolving claims first-come.
Why
A complete public listing is a script for stealing the item: anyone can read the description back. Inverting it makes the unpublished detail the proof: the finder records everything, the listing shows only enough to be recognisable, and the claimant has to produce the rest. It is worse UX and it is the only version that works.
02
Chose
Matching as a database query over category, location, and time.
Instead of
A similarity model over the free-text descriptions.
Why
The dataset is small and cold-starts empty, which is the condition under which learned similarity performs worst and is hardest to debug. A deterministic query is explainable to the user, tunable by changing a number, and correct on day one, and matches only need to be good enough for a person to confirm, not good enough to act alone.
03
Chose
Candidate matches surfaced for confirmation, never auto-resolved.
Instead of
Automatically 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
Chose
SQLAlchemy against SQLite locally and PostgreSQL in production.
Instead of
Writing SQL directly, or using SQLite everywhere.
Why
The ORM keeps one schema definition working against both, so local development needs no database server while production still gets real concurrency and real constraint enforcement. The cost is a layer between the code and the query plan, which is a bad trade at scale and a good one here.
04

The result

A working recovery platform, and a lesson that had nothing to do with the stack: the feature that decided whether the system was usable at all was not matching, ranking, or the interface. It was the question of what a listing is allowed to reveal, and that only became visible after building the version that got it wrong.