
TheCatfish: A Flutter Scam-Reporting App
Social apps are deceptively hard. A feed and a like button look trivial until the content is user-generated reports about other people — and suddenly search, trust, and moderation become the whole product. That's what building TheCatfish was really about.
What is a scam-reporting social app?
A scam-reporting social app lets people search for, post, and discuss reports about suspected online scammers inside a single feed-based mobile app. Built in Flutter for Bitwise Solutions, TheCatfish pairs social features — posting, likes, comments — with a searchable database of reports, so a user can check someone before they get burned rather than after.
The interesting engineering problem here wasn't the feed. It was that every post is a claim about a real person, so search had to be fast and forgiving, and a "report" had to be a first-class, queryable entity — not just another social post that happens to have text in it.
The brief
TheCatfish was built for Bitwise Solutions as a social-style mobile app. It needed to support three core things:
- Search — look up existing reports before engaging with someone online
- Report — post a new scam report with details and supporting evidence
- Engage — likes and comments, so the community can corroborate or push back on a report
TODO: confirm platforms (Android / iOS / web companion), auth method, and the exact evidence/attachment types supported.
Search that has to be forgiving
People don't search the way your data is stored. They misspell names, paste half a phone number, or type a username with the wrong casing. So search debouncing and normalization mattered more than raw speed:
class ReportSearchCubit extends Cubit<ReportSearchState> {
ReportSearchCubit(this._repository) : super(ReportSearchIdle());
final ReportRepository _repository;
Timer? _debounce;
void query(String term) {
_debounce?.cancel();
if (term.trim().isEmpty) {
emit(ReportSearchIdle());
return;
}
_debounce = Timer(const Duration(milliseconds: 350), () async {
emit(ReportSearchLoading());
try {
final results = await _repository.searchReports(term.trim());
emit(ReportSearchLoaded(results));
} catch (e) {
emit(ReportSearchError(e.toString()));
}
});
}
@override
Future<void> close() {
_debounce?.cancel();
return super.close();
}
}Debouncing keeps the app from firing a request on every keystroke; normalizing the term (trimming, lowercasing) on both write and read is what makes a fuzzy human query actually find the right report.
Treating a report as a first-class entity
The temptation in a social app is to model everything as a generic "post." That falls apart the moment you need to search reports by the scammer's identifiers, not by the author. Modelling a report as its own entity — with structured fields for the reported identity, the claim, and evidence — is what let search, feeds, and engagement all read from the same source cleanly.
Handling user-generated content responsibly
An app built around accusations carries real risk, so it can't just be a feed with no guardrails. That means at minimum: the ability to report or flag abusive posts, clear engagement signals so the community can weigh a claim, and a path for moderation. TODO: confirm which moderation and reporting features shipped in v1 so this section reflects the real build.
Results
TheCatfish shipped as a working social platform where users can search, post, and engage with scam reports from their phone. TODO: add real numbers — reports posted, active users, store links — once available and confirmed with Bitwise.
Building something similar?
If you're planning a social or community app where search and user-generated content are the hard parts — not the UI — I'm happy to talk through how to keep it fast, trustworthy, and maintainable — reach out, or find me on Fiverr and Upwork.


