A software handover list names everything that has to pass from the vendor to you, with the check that proves each item on delivery day. Whether the list closes is what moves it in time: a closed list goes into the contract, an open one waits for the last week. KGM SsangYong’s corporate site arrived with its vehicle images on disk and no written note of which model each image belonged to.
One question decides whether an item belongs on the handover list
Handover conversations usually open with a wish list. Code, database, documents, passwords. The longer the list grows, the safer the arrangement feels, and length is not a criterion. A list built from things that would be nice to have never closes. Another line arrives at every meeting, and none of the lines can say why it is there.
Only one question closes the list. If this item were not in your hands, could you bring a working copy of the system up in an empty environment without putting a single question to the vendor? If the answer is no, the item belongs on the list. If the answer is yes, the item may still be useful, but it is not what handover is about.
Closing the list also settles when it gets written. A list that closes can go into a contract; a list that never closes is remembered at the end, in the week everyone is trying to finish. An item named in the contract sits inside the scope and inside the price. An item requested on the last day is limited to whatever the vendor still happens to hold.
Set the criterion against a real handover. KGM SsangYong’s corporate site reached us already live; the team that originally built it was not us. It is worth counting what the brand held at that point from the buyer’s side of the table. There was a live site on a domain carrying the brand’s own name. There was a codebase complete enough to work inside. Catalogue data sat in MySQL, and the vehicle images sat on disk. The system was standing, and its parts were visible.
What was not in hand was not a file. It was a piece of knowledge: which image belonged to which vehicle model. The images were there, the mapping was not. That is the line most often left blank on a handover list, because nothing about it can be zipped and sent. Leave it out and the rebuilt system fills its pages with the wrong pictures.
The criterion survives subscription software unchanged; only the items move. Source code is not handed over in a product you rent, so the list carries the export format of your data, the downloadable state of your files, and the names on the accounts instead. The question stays the same: if access to this product ended tomorrow, what could you do with what you hold?
Repository, dependency list and setup instructions are separate items
A sentence gets spoken the moment the repository arrives: we have the code. It is true, and it hides the two items that are missing at exactly that moment. A repository tells you what the system is. It does not tell you the route from code to a running site. That route runs through two more items. First, a dependency list naming the parts the system runs on. Second, setup instructions saying which step happens in what order on an empty machine. The three are separate items, because none of them can be checked without the others.
A dependency list is simpler than it sounds: it is a set of written tool names. On KGM SsangYong’s corporate site the stack is named on the project page as Laravel, Tailwind, jQuery, MySQL and Redis. That is what the stack line of a handover list looks like. Without it, nobody knows what to install on an empty machine, and the work turns into a sequence of questions for the vendor. Version detail is a question of its own; if the list does not carry it, there is a gap there too, and it surfaces during the install rather than in the meeting.
Anything added to the stack later has to be named on the list as well. On the SsangYong site the later addition was a cache layer, and the project page names it. Writing it down is not a matter of tidiness. It changes what a rebuild produces: if a later addition goes unnamed, the system you stand up in an empty environment matches the code and diverges in behaviour.
The check fits in one sentence. Open the site in an empty environment using nothing but the repository, the dependency list and the instructions, and ask the vendor nothing. The output of that check is not “it worked”. The output is how many questions you had to ask. Each question marks a step the instructions left out, and the check is not finished until that step is written down.
There is a limit worth stating. If nobody on your side can follow the instructions, you have a third team do it, independent of the vendor. That is a one-off cost paid while the contract is still open. Asking the vendor to follow their own instructions is not a check at all, because the person who already knows the missing steps will not notice them. Why an existing toolset gets kept rather than replaced is a separate decision, and we wrote it up in the maintenance article, where staying on the existing stack is explained.
A database dump and the uploaded files are separate items
Most handover lists carry a single line called “backup”, and that line quietly assumes it stands for two things. It does not. A database dump carries the records; uploaded files sit on disk. You collect them from different places, move them separately and check them separately. A list with one line loses one of the two on delivery day, and which one it meant only becomes clear once something is missing.
A third item sits between them, usually unnamed: the knowledge of which file belongs to which record. That knowledge lives in one of a few places. It can be a field in the database. It can be carried by the file name itself. It can be written in a document. If it lives in none of them, it lives in the vendor’s memory, and memory cannot be handed over. Because the item is knowledge rather than a file, it rarely reaches the list on its own: counting files feels like real work, and counting a mapping feels like fussiness.
KGM SsangYong’s corporate site carried precisely that gap at the point it reached us. The vehicle images were on disk; which image went with which model was written nowhere. Every file was in hand, and the pages filling correctly was not.
The check is small and definite. Load the dump and the files into an empty environment together, then open a single record page. If the image is right, the mapping is written down and it belongs to you. If the image is missing or wrong, the mapping is in somebody’s memory. One page answers the question; you do not need to walk the whole catalogue.
In a system that carries no uploaded files, this item comes back empty. An empty item is not deleted from the list, it is marked “none”. Delete it, and on handover day nobody can tell whether files never existed or whether they were forgotten, and that distinction cannot be reconstructed later. What earlier decisions in a system you take over leave you with is covered in the architecture article on what a taken-over system’s earlier decisions mean for you.
Config, cache and scheduled jobs
Not everything a system needs to run lives inside its code. Some parts are called by the code and do not ship with it: a cache server, a queue, a scheduled job that fires at a set hour. These belong on the handover list by name, along with where they run. Leave them off and the rebuilt system still starts, because the code loads without them. The gap shows up as silence rather than as an error.
Environment configuration and secret keys form their own item, and this is the one people misfile. They do not live in the repository, and they should not. But if they are not handed over separately, the system never starts on your side at all. This is where “we have the code” fails most often: the repository is complete and the system is dark.
The portfolio has a concrete case of the first kind. On KGM SsangYong’s corporate site the cache layer was the part that entered the stack later, and it runs outside the code; catalogue reads are served from it. Had that part been absent from the handover list, the rebuilt site would still have opened, and every catalogue read would have gone back down to MySQL. The system would have returned to its earlier state, and nobody would have seen an error message.
So the check is this: start the system using only what the written list contains, adding nothing from memory. If the code tries to reach an address and cannot find it, that address is missing from the list. The question the check asks is not “did it open” but “is everything the code calls written down”. The distinction matters, because a system that opens on handover day relaxes the room, and relaxation is what hides the missing item.
One limit applies. If a part runs on the vendor’s own infrastructure, it cannot be handed over. The list then carries not the part itself but what will be set up in its place on your side. A part that cannot transfer does not drop off the list; it is marked “to be rebuilt”, and its cost stays visible in the handover conversation.
Domain, hosting and third-party accounts belong to whoever opened them
The accounts that sit outside the code are these: the domain registration, the hosting account, and the accounts for the outside services the system talks to. Whoever opened each of them holds it in practice. The contract can name you as the owner while access stays with the person who created the login. What handover checks is not the ownership on paper. It is the access in your hands.
Among these, the domain on its own is worth as much as the rest of the system. Whoever holds the address holds the visitors. You can hold the code, hold the data and hold the hosting account, and still be unable to move the system anywhere if you cannot change where the address points.
The check runs on delivery day. Log into every account with your own credentials rather than the vendor’s. Then confirm that you can change where the domain points without asking the vendor first. If both work, the account is yours. If either does not, that line is still open on the list, and it closes before the contract does.
The institutions under Vipkurum show why this item is counted separately: to a visitor they appear under their own domains and their own brands, not under the platform’s address. Read for handover, that means this: if the registration is in the institution’s name, the address stays with the institution even when the platform underneath it changes. KGM SsangYong’s corporate site is likewise live on an address carrying the brand’s own name. An address carrying a brand’s name and a registration held in that brand’s name are not the same thing; the second is visible only from inside the registrar account, and it is a separate line on the handover list.
None of this makes ownership a rule about operations. An account in your name does not mean you have to operate it. Ownership and operation separate cleanly: the vendor gets limited access, the primary account stays with you. Some services never transfer an account at all. There, the account is reopened in your name and the connections are rebuilt through it, which is work you plan while the contract is being written rather than on handover day.
Handover items side by side
Set out together, the list is something you can carry into the room on delivery day. Every line answers three questions: what the item is, what breaks without it, and how it is checked while the vendor is still there. The third column is the reason the list exists. An item with no written check counts as checked the moment the vendor says it was delivered.
| Handover item | What breaks without it | The check at delivery |
|---|---|---|
| Repository, dependency list and setup instructions | You hold code, not a running site; the install on an empty machine advances through questions to the vendor, and each question is a missing step | Open the site in an empty environment from the repository, the list and the instructions alone, asking nothing |
| Database dump: schema and records | The site opens and is empty; or the schema arrives without records, or records without a schema | Load the dump into an empty environment and open one record page |
| Uploaded files and the file-to-record mapping | Files sit on disk with no way to tell which record they belong to; the page opens and the image is missing or wrong. KGM SsangYong’s corporate site reached us in exactly this state: files in place, mapping written nowhere | Load the dump and the files together, then open a single model page and see whether the right image appears |
| Environment configuration, secret keys and parts running outside the code (cache server, queue, scheduled job) | Without configuration the system never starts; without a part it starts and runs short, and the symptom is slowness or unprocessed work rather than an error | Start the system from the written list alone; every address the code reaches for and cannot find is a missing item |
| Domain registration, hosting and third-party service accounts | The contract may name you, while access stays with the vendor and every redirect needs them. Vipkurum’s institutions appearing under their own domain rather than the platform’s is what it looks like when the address is the institution’s own asset | Log into each account with your own credentials; change where the domain points without asking the vendor |
The rehearsal at delivery: rebuilding the system a second time while the vendor is still under contract
Checking an item on its own proves the item exists. Only one action proves the items are enough together: rebuilding the system a second time in an empty environment, from the handed-over items alone, while the vendor is still under contract. Anything added from memory invalidates the exercise, because memory is exactly what the exercise measures.
What the rehearsal produces is not a working copy. It produces a list of what is missing. Every moment of “we had to ask them” becomes a line, and handover is not finished until that line is closed. The rehearsal ends when the missing list empties; the second copy can be deleted after that, because its job was to produce evidence.
The portfolio shows what a rehearsal pulls forward. On KGM SsangYong’s corporate site, the fact that the mapping between image files and vehicle models was written nowhere surfaced not while the original team was at the table, but when the next team read the codebase. The gap was already there. The only thing that changed was when it became visible. A rehearsal surfaces the same gap while the vendor is still reachable, and the difference is not whether an item is missing but who carries the cost of closing it.
What the word “check” measures here is reproducibility. Whether the software behaves correctly, meaning what to test at acceptance, is a different question. Confuse the two and the rehearsal turns into an acceptance round. Screens get clicked, records get opened, everyone relaxes, and the handover list closes without ever having been checked. That is also why the questions-to-ask-a-software-company article left the handover question for its own piece.
Two objections come up in practice. A vendor may treat the rehearsal as extra work; if they do, it is written into the contract and priced, and it is not dropped. Standing up a second environment costs something as well. It costs less than discovering what the handover list got wrong after the vendor is no longer reachable. And if the system does not exist yet, the list is written at the founding rather than at delivery, which puts that conversation inside the system architecture service instead.
If you already run a system that nobody ever wrote a handover list for, the first step is to produce the list: read the codebase, then separate what is written down from what only lives in someone’s memory. Our software consulting page shows what that reading produces on a system we took over.