Building TCleanner
tcleanner ios
The first post here said there was nothing to show yet. I’ve since built TCleanner, an iPhone and iPad app for searching my own Telegram history.
Over the years I’ve sent things in Telegram that should not still be there: a Wi-Fi password typed in a hurry, an API key pasted to a colleague. Finding them again means remembering what I wrote and where I sent it. I usually don’t.
What I wanted was grep over my history. Something like \b\d{4} ?\d{4} ?\d{4} ?\d{4}\b,
run across chats, with a checkbox beside each match and a button to delete the selected messages
for everyone.
What it does
TCleanner signs in to your own account and indexes message text from private chats and groups on the device. Channels are included only if you turn that on. Search works offline, with regular expressions. Built-in templates cover passwords, one-time codes, API keys, card numbers, emails and phone numbers. You can save your own patterns too.
You select the messages you want to delete. The app checks whether Telegram allows deletion for everyone and asks you to confirm the exact count. Deletion is always for everyone and is never scheduled. The app never sends messages.
There is no server of mine. The app connects only to Telegram, with no analytics or trackers. Its third-party app dependencies are TDLib and GRDB. The index stays in the app’s private storage and is excluded from backups. The privacy policy has the details. Its principles are also in Settings › How it works, available before sign-in, with a link to the full policy.
How I built it
One Swift package holds the domain and the presenters; SwiftUI renders their state. TDLib’s own message database is disabled because the app owns its index. That index is SQLite through GRDB. Search scans it newest first and stops at the result limit or time budget. I left out FTS and trigram indexes: searches need arbitrary regular expressions, and the reference measurements put the trigram index at more than the size of the database itself.
I spent more time than I expected on testing. Behaviour is specified first, across eleven capabilities. Each requirement has a stable ID that code and tests cite. Domain tests use fakes and an injected clock instead of waiting for real time to pass.
I also wrote a mutation tester: it changes the code on purpose and checks whether a test fails. I couldn’t use the existing tools for this project. For each capability, mine compiles all its mutants into one build behind a runtime switch, then runs the test bundle for each mutant. The target is 100%, and every capability is there now.
I test indexing with a local harness that interrupts connections while it runs. The harness uses Telegram’s test datacentres and compares the resulting index chat by chat with a baseline run. Those checks run on macOS; device checks are still pending.
Status
TCleanner is not released yet, and there is no release date. The built-in demo archive lets me test it without a Telegram account.
Questions and ideas go to the feedback tracker or to support@kudravets.com.
It is an unofficial app. It uses the Telegram API and is not affiliated with Telegram.