Tasmi’ - Every recitation, on record
A mobile-first web app for a Qur'an recitation program, with two sides. On the participant side, people register for two weekly sessions and log each recitation. On the supervisor side, supervisors verify, correct and report on them.
It started in WhatsApp and Google Sheets. The quick first app that replaced them held 54 participants’ records by Batch 5, and lost people’s history three times. More patches would not fix that, so I first defined what every report may and may not do, then redesigned each screen around those rules.
From v0 to v1: nothing lost, nothing guessed, every fix undoable.
“No need to type my name or level again. Just progress and sick leave. Much easier.”
Two roles, one phone each, a few minutes around class.
Classes run weekly, in separate male and female groups.
Participants are working adults who report from a phone in the minutes around class.
Supervisors are paid teachers who also hold other jobs.
They teach the classes and correct each participant’s recitation.
History went missing three times, and the code had already written down why.
With WhatsApp and Google Sheets, participants lost track of their own records, and supervisors struggled to log them while teaching.The app was meant to fix that, but then history went missing.
I expected a mystery. Instead, each incident was described in a comment beside the line that caused it.Read together, they all came from one root cause.
{{ owQuery }}How might participants and supervisors log and fix progress quickly on a phone, in a way they can trust, when the first version let them pick wrong and then lost what they picked?
Before writing v1, I audited the plan so it could not repeat v0.
Zero foreign keys was never one bad line of code.
It was a decision nobody wrote down, so nobody checked it
against the others.
v1 was planned as four documents: framing, flows, schema, migration.
Each passed review alone. Read together, they had gaps:
two correct decisions that break the moment they meet.
The first audit found 11. Drawing the decisions as screens found 19 more, and all 30 were closed before the build started.
Four rules, read at the start of every session.
I built v1 with an AI coding assistant that forgets everything between sessions. The rules are what carries over.
Time of day first, exactly two sessions, and an alias instead of a name.
Most people choose by when they are free, so sessions are grouped by time of day. Registration needs exactly two, and the button says how many are still missing.



Looking does not delete. Changing does.
Going back to check your group keeps your sessions. They clear only when the group or class actually changes, and the warning sits inline on that step, instead of a dialog that warned about a loss that had not happened yet.
Ask what happened, then offer only what fits.
The old form asked for a time, then a status, then a mode, and allowed every combination. The Hub now asks one question: what happened today?


A mistake costs one tap to fix, and one tap to undo.
Supervisors used to fix entries from a laptop, in Google Sheets, after a chat message. Now a correction happens on a phone, on the participant’s own history.
Three tools that run on the same rule as the edit above. Supervisors fix records, report the day and promote participants without losing data or doing the work twice.




One table that is always current.
To see how everyone stood since the program began, the program lead had to total a sheet by hand. Now it is one live table.
Rust color means "you can still catch up", never "you failed".
Everything this app flags can be fixed: a missed session can be made up,
a wrong PIN can be typed again. So there is no red anywhere.
Warm neutrals carry the screen, green is for action,
and rust only marks what is behind.
Then a WCAG 2.1 AA audit against all five backgrounds failed five tokens.
Each was deepened in the same hue, not swapped,
and primary was deepened too so the soft green could clear 3:1
against both white and primary.
Same jobs, fewer steps, nothing to reconcile.
The jobs did not change between versions.
What changed is how many decisions each one asks of the person,
and where the record ends up.
Move every row, then count them back.
Starting empty would have been the easiest build,
and it would have lost history a fourth time,
after the three incidents in section 02. Instead v1 launched with Batch 6, and Batch 5 came across as read-only history.
That changed the stakes: old rows only had to be right
to read, not right to calculate.
The two old databases looked alike
and meant different things, so the script ran two paths.
On 20 August 2026 it finished, and every number
was read back from the new database against its source.
The canvas is a test the code has to pass.
Every Tasmi' screen was drawn in Solide, the design tool I built,
and moved into code through its MCP, the bridge that lets an AI agent read and write anything on the canvas, without limits. A drift script compares each frame
with the shipped screen, and known differences are held in a baseline
so new ones cannot hide among them.
A tool that says “done” must prove it. Solide now reports what it wrote.
Five times in one week, a command reported success and did not do what it was asked. A loud failure costs a minute. A silent one costs a day. Building Tasmi' on Solide turned into the bug report that made its MCP say when it had not written anything. I still check the result with my own eyes, and an extra skill tells the AI to do the same before it says done.
Batch 6 runs entirely on v1.
All 47 participants re-registered through the new flow,
and all 5 supervisors work from it. The outcomes below come from the database
and from what supervisors and participants
reported after the switch.

