Here is what we found, what we think is genuinely good and worth keeping, our leading hypothesis for the empty dashboard, and an honest map of what happens in what order, with the free part clearly marked.
It is worth saying plainly, because handoff documents tend to read like confessions and this one should not. What is sitting on that laptop is a working three-role assessment platform with a sound relational model, version-controlled migrations, security policies written at the database layer rather than bolted on, anonymous survey links decoupled from authentication, and pipeline state derived from data instead of stored and drifting.
Several of those are decisions that experienced teams get wrong. The data model in particular is normalised enough to carry year-over-year history and denormalised enough to read quickly. We would not change its shape. The handoff document itself is unusually good: nineteen numbered constraints, each with the specific fix, is more clarity than most production systems can produce about themselves.
Stating this carefully, because it is a hypothesis rather than a finding. The zeros are a symptom we saw in the screenshots you shared in June; your handoff document does not mention them, so what follows is inference from the architecture rather than something either of us has confirmed.
Averages are recomputed in the browser after each staff member submits. The browser reads the current responses, works out the new averages, and writes them back onto the cycle. That single design choice puts the only write of every derived number on the least reliable machine in the system.
The race you describe, two people submitting within the same few seconds, both browsers reading the same starting state and the second write winning, explains wrong averages cleanly. On its own it does not explain zero averages, because whichever browser writes last still writes the mean of at least one response.
For zeros you need the write to be failing outright rather than merely racing. That could be a permissions rejection on the update, an error swallowed with no handler, or the recompute keyed to a different cycle than the one the responses landed on. All three are failure modes of the same architecture, which is why the constraint is still where we would start.
Rather than argue about it, this can be answered in about a minute with read access:
responses for a church whose cycle reads 0.00. Responses present, parent cycle empty means the aggregate write is failing, and the hypothesis is confirmed.Worth naming either way: if aggregates have ever been computed client-side under load, historical cycles may hold quietly incorrect averages rather than obviously empty ones, which are harder to notice and worse to present. Recomputing every existing cycle from its raw responses is part of phase zero regardless of which hypothesis turns out to be right.
Every constraint from your document, sorted by what it actually blocks rather than by how hard it is. Tap a phase to filter.
Scores are recomputed in the browser after every submission, so two responses landing at the same moment can overwrite each other. Last write wins, and a response silently vanishes from the mean.
responses INSERT. The database becomes the only thing that does arithmetic.The proxy that carries AI calls exists only in the Vite dev config. The moment the app is deployed, every AI request returns a 404, so insights and themes go blank in production, not in development.
Every component re-declares its own spacing, colour and borders. You named the consequences as no dark mode and inconsistent focus styles; the one that matters commercially is that the app cannot be put into focus412 brand without touching every file.
It runs on localhost and nowhere else, so nothing can be shown to a church without your laptop in the room.
Several tables overflow on a phone and the heatmap is desktop-only by design. Staff take surveys on their phones.
Any rule the database cannot express by itself has nowhere to live. “When a cycle closes, email everyone who responded” being the obvious one.
Two lines of regex reading the URL. Fine at two routes; it stops being fine at the third.
One component owns everything and passes a bundle of actions down three or four levels. Every new screen makes that worse.
After login the app queries two tables just to establish which role it is dealing with, before it can render anything role-specific.
Invitations do not send and “your report is ready” never arrives. The UI for it exists but the wiring does not, and the built-in mail is rate-limited to roughly two messages an hour per recipient.
The current deliverable is, in your own words, a screenshot of the browser. Meanwhile the archive holds twenty-five hand-built decks. This is the single largest hour-sink in the whole operation.
Every regression is caught by a person clicking through the app. As the surface grows that stops being viable.
When something breaks for a church, nobody finds out until they mention it.
Policies are written per role, so they cannot express “this coach sees only the churches assigned to them.” That constraint binds the moment a second coach uses the system.
Uploads are held as base64 text on the row, so a 5 MB PDF becomes a 7 MB database row. Comfortable at pilot volume, expensive at a hundred churches.
Two people editing in two tabs cannot see each other until someone reloads.
The twenty questions live in a source file, so no engagement can be given a variant and no version of the instrument can be retired cleanly.
The close date is stored in UTC and displayed in whatever zone the viewer is in, so “closes at 5pm Central” cannot currently be expressed.
Custom controls carry no ARIA, keyboard traps are untested, and focus rings are missing in places. Fine for a small pilot; it fails an audit the first time a larger church runs one.
“Rewrite all React components.” True eventually, but not first. A full rewrite of every screen puts three to four weeks between today and the first thing a church can see. We would rather brand the two surfaces a church actually touches, the survey and the report, then deploy those, and let the internal admin screens stay plain a while longer. They are working, and nobody outside your team looks at them.
“Move to a new framework.” Also probably right, and also not urgent. None of the five phase-zero fixes require it, and re-platforming before the data layer is trustworthy means debugging two things at once. Better to make the current build correct and visible, then move it on a known-good foundation.
Neither of these is a disagreement about the destination. It is a disagreement about what to do in week one.
This is the build we committed to in June, and it has not changed. One church goes all the way through: survey out, staff respond on their phones, scores compute correctly, report renders in focus412 brand, live on a real URL you can send to someone. Nothing about it is a trial or a teaser; when it is done you own it.
What we would ask of you: read access to the repository and the Supabase project, one pilot church willing to go first, and one decision on which version of the instrument is the version of record.
This is the phase that gets you out of the loop. A server layer so rules can live somewhere; email so invitations and “your report is ready” send themselves; tests on the maths where being wrong is expensive; and error reporting so you find out about problems before a church tells you.
The centre of it is the export. Twenty-five hand-built decks sit in the archive you sent us. Phase one is where a finished deck (your shape, your brand, your language) comes out the other end of a completed cycle without anyone assembling it. If only one thing on this page gets built after the free work, it should be this.
Everything that binds the second time a second person uses the system: per-coach visibility, files out of the database and into proper storage, live sync between tabs, a versioned instrument that can be varied per engagement without a deploy, real time zones, and an accessibility pass that survives an audit at a larger church.
This is also where the twenty-first question and the six drifted question wordings get settled permanently, because it is where the instrument stops being a source file.
Nothing in this phase is a bug fix, because none of it exists yet. It is the thing you described in June: a church finishes its cycle and sees immediately how it compares to churches its size, its age, its region and its stage, drawn from every church that has ever taken it.
The companion benchmark brief shows what that already looks like against your existing archive. The work here is turning that from something we built by hand into something that updates itself, plus the region derivation and the de-identification step that should run before any church's data joins the pool.
The timeline below is not ours. It is the one in section seven of your own handoff document: “estimated calendar time for a competent full-stack engineer to reach production-parity: three to four weeks.” We have taken your estimate and applied what that work actually bills at. The only figure we supplied is the hourly rate.
This one is not in your handoff, so there is no estimate of yours to anchor to. The figures below are ours, and we would rather label them clearly than let them look more solid than they are.
These are not list prices. They are what we are charging focus412, and it is worth saying why rather than leaving you to wonder.
The honest reason for the rate is that we want to build this with you rather than for you. You are the first church-consulting group we have done this with, and what you already have is unusual: a real methodology, twenty-five engagements of evidence behind it, and a working platform that most people in your position would not have got as far as building.
If it goes the way we think it will, the thing we would most value is not a bigger invoice. It is being able to point at this work, and, when it feels natural and only where you think it fits, being introduced to a church or two in your world who might want something similar. No obligation attached to any of the numbers above, and nothing here is contingent on it. It just seems like the kind of relationship where both of us end up better off, and we would rather name that openly than hope for it quietly.
Phase zero stays free regardless, and it is not contingent on any of the rest. If we finish the demo and you decide to take the code to someone else, that is a completely reasonable outcome and the work is still yours.
One thing to be straight about: these prices cover building and handing over. If at some point you would rather we also operated and monitored it for you, that is a separate and explicit conversation, never something that quietly becomes assumed.
The repository and the Supabase project. We can confirm the aggregation diagnosis in a single query and tell you within the hour whether it is what we think it is.
One church, ideally mid-sized and already familiar with you, willing to be first through the finished flow.
Enough to settle the instrument of record, the twenty-first question, and which of the four phases, if any, you actually want after the free one.