BrainIT Consulting Master Build No. 1
Build it on accounts you own
Master Builds takes one real application from an idea to a system you own, run, and remain accountable for. The application is Countercheck. It reads an accounts-payable export, reports the payments that look wrong, shows the rows behind each one, and never writes anything back.
About fifteen minutes to read. Ninety minutes to complete the card at the end, most of it spent creating accounts and writing down who holds them.
Part 1 decided what Countercheck is for. This part puts it somewhere real. That sounds like the boring half — hosting, a database, an email sender — and it is where most of the ownership of a system is won or lost, usually before anybody notices there was a decision to make.
- The Ownership Card, Countercheck's filled in beside your blank one
- The two rules that decide whether a system is yours: who may transfer it, and who owns the code
- Two things that went wrong in this build, one that broke loudly and one that broke nothing at all
1. Ownership is not something you add afterwards
Ask an agent to deploy your application and it will. It will create what it needs, under whatever account is convenient, and the thing will work. You will have a running system and a URL, and the question of whose it is will not have come up.
It comes up later, and it comes up at the worst possible time: when the relationship ends, when the contractor stops answering, when the agency is acquired, when you want to move.
Two rules decide the answer, and neither of them is negotiable after the fact.
The transfer rule
Vercel's documentation on transferring a project says:
"You must be an owner of the team you're transferring from, and a member of the team you're transferring to."
Read that as the sentence it is. If the project sits in somebody else's team, you cannot move it out. Not with a support ticket, not with a contract, not with goodwill. There is no button you can press, because the button is not yours. Every serious platform has a rule of this shape; this one is quoted because it is the platform this build runs on and because it is written down plainly, which not all of them are.
What the transfer does not carry is worth knowing before you plan one. On this platform: a root domain stays behind on the origin scope when a subdomain moves, integrations have to be added again afterwards, and runtime and build logs are not transferred at all. A transfer is a migration with a friendly name.
The work-made-for-hire rule
Under United States copyright law, a commissioned work can be a "work made for hire" only if it falls into one of nine listed categories. Software is not one of them.
The consequence is the opposite of what most people assume. Paying for code does not buy the copyright in it. Absent a signed assignment, the contractor who wrote it owns it, and you have — at best — an implied licence to use it, the scope of which you will be arguing about at exactly the moment you can least afford to.
This is not exotic. It is the default. The fix is one clause and it costs nothing while everyone is still friendly.
The test
A system is yours when you can answer three questions without asking anyone:
- Whose name is on the account? Not who has access. Who is the owner of
record, and whose card is on it.
- Who can lock everyone else out, and who can be locked out?
- **If the person who built it stopped answering today, what would you have to
ask them for?** Anything on that list is not yet yours.
Do this before the build, because after the build it is a negotiation.
2. The accounts came first
Countercheck needed three things: somewhere to run, a database, and something to send email. All three were created before a line of it was deployed, in my name, on my billing.
| What | Why it exists | Who owns it |
|---|---|---|
| A hosting account | Somewhere to run the application, and the address it answers on | Me, personally |
| A database | Where ledgers, decisions and the audit trail live | Me, personally |
| An email sender | Sends the sign-in link, and nothing else | Me, personally |
That table is the whole of it, and its unremarkableness is the point. There is no clever architecture here. There is a fifteen-minute job that has to happen first, and a strong pull — from an agent, from a contractor, from your own impatience — to skip it because the thing runs perfectly well without it.
Two notes from doing it:
Use the platform's own integration if there is one. The database here was provisioned through the hosting platform's marketplace, which means one bill, one place to revoke, and the connection string wired in without it ever being pasted into a file. Fewer places for a credential to sit is worth more than whatever you save by shopping around.
Free tiers are fine, and their limits are a design input. This runs on free tiers throughout. That is a legitimate choice for a system at this stage, and it is also the reason the database goes to sleep when nobody is using it — which you will meet as a slow first page load, not as an error.
3. What "runs at a real address" actually means
Countercheck is now at a URL anyone can open. You give it a spreadsheet export, it reports what looks wrong, it shows the rows behind every finding, and a person decides. It still never writes anything back.
There are two ledgers in it:
| Ledger | Rows | Findings | At stake |
|---|---|---|---|
| The demo from Part 1 | 237 | 6 | £27,401.25 |
| A second export, imported to test the column mapping | 218 | 6 | — |
The second one exists for a specific reason. The import path is the part of this application most likely to be wrong in a way nobody notices, because it succeeds quietly: a column mapped to the wrong field produces a ledger that looks completely normal and is completely wrong. Importing a second export with different headers — the kind a different accounting package produces — is the cheapest test of that path there is, and it is a test you can run on your own system this afternoon.
4. It broke the moment it left my laptop
Then it broke. Every page that showed a ledger stopped working, the moment it stopped running on my own machine.
The reason will happen to you, so it is worth understanding properly.
Countercheck kept each ledger in a file. That is a perfectly reasonable choice for something you clone and run locally — no database, no configuration, one command. The code was careful about it: it wrote to a temporary file and renamed it over the target, so a process killed halfway through would leave either the old ledger or the new one, never a half-written one.
None of that care survives contact with a rented computer. A serverless host does not give your program a disk it can keep. The filesystem is read-only apart from a temporary area, and what you write there cannot be relied on to exist for the next request — it may be a different machine entirely.
The one-line fix I did not take
There was a one-line fix. Point the storage at the temporary area, and every page loads again.
I did not take it, and this is the decision the whole part turns on.
That version works. It also quietly loses decisions — a reviewer confirms a finding, the page updates, everything looks right, and some time later the machine is recycled and the decision was never anywhere. In a product whose only claim is that a person decided and it was written down, a version that silently forgets is worse than one that plainly refuses. The refusal is visible. The forgetting is not.
So the storage moved to a real database instead. It cost the rest of an afternoon.
What to take from this
The general form is: when a fix makes the symptom go away, ask what it does to the claim. A system that is 95% reliable at remembering decisions is not 95% of an audit trail. It is not an audit trail.
5. Every decision was signed by a constant
The second thing was worse, because nothing broke.
Every decision recorded in Part 1 was attributed to the words demo reviewer — a fixed piece of text sitting in one function. The audit trail had a column for who decided, and it said the same thing every time, whoever was sitting there.
/** Until sign-in is added, decisions are attributed to a single reviewer. Auth
* replaces this one function, not every call site. */
const currentUser = () => "demo reviewer";
Nothing failed. Every screenshot looked correct. The figure was right and the name was furniture.
This is the class of defect worth being frightened of. It produced no error, no warning, no failed test and no wrong number. It made a document that looked like evidence and was not, and it would have gone on doing that indefinitely.
What fixed it
Signing in, with no password. You enter an email address, you get a link, the link expires in fifteen minutes, and your address is what appears beside your decision from then on.
No password is a deliberate choice rather than a shortcut. There is nothing to leak, nothing to reuse from another site, nothing to reset, and no password database to be the most valuable thing you own.
The change reached one function, because Part 1 had put the attribution behind one function. That comment above was written eight days before it was needed and it turned out to be true — which is the argument for narrow interfaces made better than any diagram.
What it does not fix
The decisions already recorded still say demo reviewer, and they still say it today. They were not rewritten, because an audit trail that is edited to look better is not an audit trail. The old lines sit above the new ones, and the difference between them is the point.
An audit trail that names a placeholder is not evidence of anything.
6. Three became five
Part 1 showed you a file as evidence: the list of outside code Countercheck depends on. There were three lines in it.
There are five now — a database driver and the sign-in library. If you go and look you will find five, and I would rather tell you than have you find it.
"dependencies": {
"@neondatabase/serverless": "^1.1.0",
"better-auth": "^1.6.26",
"next": "^16.2.6",
"react": "^19.2.4",
"react-dom": "^19.2.4"
}
What has not changed is the part that matters. There is still no model in that list. Nothing in it sends your ledger anywhere and nothing reports back to me. The detection is the same seven rules from Part 1, and every one of them is ordinary code you can read.
A dependency you cannot explain is one you do not control. Five is a number you can hold in your head and check. The moment it is forty, nobody is checking, and "we don't send your data anywhere" becomes a thing you are repeating rather than a thing you know.
7. The front door was open
One more, and it is the one that makes this a five-part series.
Signing in protected deciding. It did not protect uploading. Anyone who found the address could have put a real company's accounts payable into my database — supplier names, what they were paid, part of their bank details. That is closed now: uploading requires an account.
But closing it raised a question I could not answer in a sentence: who should be allowed in at all?
You cannot establish that someone is genuine from a form. Every signal on one is easy to fake — a company name, a role, a work email address on a domain registered that morning. And the data being handed over is exactly the data you would want if you were not genuine.
That is a part of its own, so this series is five parts and not four. Part 1's video still says four on screen. It was made, and it is not being quietly re-cut.
8. The Ownership Card
One page, filled in before the build, kept where you can find it in two years.
1. The accounts
For each service the system needs — hosting, database, email, domain, anything that sends or stores:
| Column | What goes in it |
|---|---|
| Service | What it does for you, in your words |
| Owner of record | The named person or company. Not "the team" |
| Billing | Whose card, and where the invoices go |
| Who else has access | Everyone, including your builder |
| Transfer rule | What that platform requires to move it out |
2. The recovery path
Write the answer to this in full sentences: if the person who built this stopped answering today, what would I have to ask them for?
Anything on that list is not yours yet. Work the list to nothing.
3. The code
- Where does it live, and whose account is that under?
- Is there a signed assignment of copyright? If a contractor wrote it and there is no assignment, they own it.
- Could you hand the whole thing to a different builder tomorrow without asking permission?
4. The data
- What is stored, where physically, and under whose account?
- What does the interface promise about retention, and is that promise true on every path — including the ones where the user gives up halfway?
- Can a customer get their data deleted? By pressing what?
5. The refusals, revisited
Part 1's refusals were about what the software may do. These are about what the arrangement may do:
- No account in anybody else's name.
- No credential that exists only in a builder's password manager.
- No production data in a system you cannot get a list of.
9. What to do this week
If you have something already running that somebody else built:
- List the accounts. Every service with a login. You will find one you did
not know about.
- Check the owner of record on each, not the access list. Move the ones
that are wrong now, while everyone is friendly.
- Ask for the copyright assignment if you do not have one. This is a normal
request and a builder who resists it has told you something.
- Open your own product and read what it promises about data. Then check
whether it is true. That is a twenty-minute job and it is the one on this list most likely to find something.
If you are about to start: do sections 1 and 3 of the card before the first line of code, and the rest of it before the first real customer.
10. Where this leaves Countercheck
It runs at an address I own, on a database I own, and every decision now carries the address of the person who made it. Two ledgers, six findings each. A hundred and fifty-five tests, run against a real database rather than a pretend one.
Part 3 reviews what was built — and ends on a promise this software makes and does not keep. Part 4 decides who may come in. Part 5 runs it for a year.
Write down what you own before you need it. If a second pair of eyes helps, BrainIT is here.
https://brainitconsulting.com
Sources and limits
The transfer rule. Vercel's documentation, Transferring a project, at <https://vercel.com/docs/projects/transferring-projects>, carrying a last-updated date of 29 July 2026 and re-read on 11 August 2026. The sentence quoted in section 1 is verbatim from that page. The narration in the video paraphrases it as "only an owner of the team a project sits in can transfer it out"; the paraphrase is accurate to the rule, and the page's own words are used here because a page is where you go to check.
The notes about what a transfer leaves behind are from the same page: a root domain stays on the origin scope when a subdomain or wildcard is delegated, integrations must be added again afterwards, and runtime and build logs are not transferred.
A first draft of this section cited vercel.com/docs/projects/transferring-a-project, which does not exist — the path is transferring-projects. It was a plausible guess written from memory and it returned 404 on the first check. A sources section is the last place a URL should be typed from memory, so it is noted here rather than silently corrected.
Work made for hire. 17 U.S.C. § 101, which defines a "work made for hire" and lists the nine categories a specially ordered or commissioned work must fall into. Software is not among them. This is a statement of the general position under United States law and not legal advice; the position differs elsewhere, and an employee writing code in the course of employment is a different case from a contractor.
The figures about Countercheck — 237 rows and 6 findings worth £27,401.25, 218 rows and 6 findings, three dependencies becoming five, seven rules, 155 tests — were measured against the running application at commit 184734d on 9 August 2026, not quoted from a document. The application is open source and the numbers are checkable: <https://github.com/brainit-consulting/countercheck>.
What is not claimed here. Several widely repeated figures about duplicate payments, invoice fraud and AP automation were traced during the writing of this part and are absent from it, because the trail ended at vendor posts citing one another rather than at a study. They are not repeated in softened form, and they are not in the video either. A citations page closing the series will publish with the final part.
This series became five parts on 9 August 2026, having been planned as four. The Part 1 video still shows "Part 1 of 4" on its title card. That frame is rendered and published, and re-cutting it quietly would be the opposite of what this series argues for.