{"id":89,"date":"2026-09-11T16:58:25","date_gmt":"2026-09-11T21:58:25","guid":{"rendered":"https:\/\/codyware.com\/moving-a-platform-off-a-vendor-without-losing-data\/"},"modified":"2026-09-11T16:58:25","modified_gmt":"2026-09-11T21:58:25","slug":"moving-a-platform-off-a-vendor-without-losing-data","status":"publish","type":"post","link":"https:\/\/codyware.com\/en\/moving-a-platform-off-a-vendor-without-losing-data\/","title":{"rendered":"How we moved a platform off a vendor we didn&#8217;t control without losing a single record"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Your business runs on a platform that works. It has customers, sales, inventory, a portal. So far, so good. The problem is where it lives: a vendor generates it, hosts it and keeps the database, and you have no way to take it out. There is no test environment. You don&#8217;t know what gets deployed or when. If the vendor changes its pricing or shuts down, your operation stops that same day.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is how a wellness club in Ecuador came to us. This is the path we took, without names or business figures.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The starting point<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The club sold memberships, follow-up protocols and products. Its platform covered a lot: customer records, sales and pending payments, quotes with PDFs, inventory, protocols, measurements, reports, a public site and a members&#8217; portal. Real users worked in it every day.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What was missing was control. The application had been generated on a third-party platform that also hosted it, and that came down to five things:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>A single environment: every change was tested in production.<\/li><li>Unconnected payments: &#8220;paid&#8221; was a box someone ticked by hand.<\/li><li>Sales that came in through chat and were typed into the system again.<\/li><li>Data in the vendor&#8217;s database, with no integrity between tables.<\/li><li>No documented way to deploy or reproduce the system.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The client&#8217;s request fit in two sentences. Get the platform out of there without losing users or data, and never again depend on a vendor to operate.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Freeze first, then touch<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Why not start writing the new system on day one? Because nobody knew exactly how the old one behaved. Migrating without that safety net is migrating blind, and the differences show up when users are already inside.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We ran the legacy application in a local environment and wrote tests that capture what it does today: for each operation, what goes in and what comes out, with the validations and errors it returned. On top of that we added an automated walkthrough of the interface. That suite became the contract. The new system would be finished when it passed exactly the same tests.<\/p>\n\n\n\n<p class=\"is-style-callout wp-block-paragraph\">Rule for the whole migration: no bug in the old system gets fixed. It is logged with its severity and left for later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It sounds like leaving problems loose on purpose. In part, it is. We found a list of issues, some of them serious, and we left them there. If you mix fixes into the migration, you can no longer tell a regression from an intentional change. With the behavior frozen, every difference between old and new has only one possible explanation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The audit also turned up something the system description never mentioned: a module that was supposed to be built did not exist in the code we received. It went from &#8220;migrate&#8221; to &#8220;build from scratch&#8221;, and the tests that covered it were marked as expected failures so nobody would mistake them for a problem in the new system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Keep what works, rebuild what hurts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Not everything was redone. The interface the club&#8217;s team used worked, and they already knew it. Redoing it would have meant charging for something that didn&#8217;t hurt. It was kept and pointed at the new system, under the same data contracts. That cut the scope of the first version in half.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What did get rebuilt was the engine. A single block of code became a set of independent modules, and the document database moved to a relational one that enforces integrity between customers, sales, inventory and protocols.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Component<\/th><th>Decision<\/th><th>Why<\/th><\/tr><\/thead><tbody><tr><td>User interface<\/td><td>Kept and reconnected<\/td><td>It works and the team knows it well<\/td><\/tr><tr><td>Application engine<\/td><td>Rebuilt module by module<\/td><td>A single block of code, hard to test and extend<\/td><\/tr><tr><td>Database<\/td><td>Migrated to relational<\/td><td>Integrity between tables and safe transactions for money<\/td><\/tr><tr><td>Hosting<\/td><td>Separate environments, sized to the business<\/td><td>Testing outside production and a cost that fits the size of the business<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The engine was built in vertical slices: authentication and customers, catalog and inventory, protocols and measurements, quotes, sales and debt, reports, members&#8217; portal. Each slice was checked against the contract before the next one started.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We turned down one shortcut: a set of generic responses that would have made the interface look &#8220;green&#8221; in a day. Of course it looked good. But a screen that works on fake data hides the modules that don&#8217;t exist yet. Only a few routes were left explicitly marked as pending.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">No longer tied to the vendor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The second sentence of the request was solved with a platform of its own, one the club can deploy and reproduce without asking anyone for anything. Deployment is documented, there is a test environment separate from production, and keys live in a secrets manager, outside the code. None of that existed with the previous vendor: every change was tested with real users and nobody knew how to bring the system up somewhere else.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The infrastructure was chosen for a small business: a service for the engine that scales with use, a managed database and the interface served from a content delivery network, all in the same region so latency between the parts stays low. Nothing oversized, because the monthly bill has to match the size of the business.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where it ended up<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>The parity suite passed in full, except for the cases of the module that never existed, marked as expected.<\/li><li>Within weeks of the proposal, the platform was running outside the vendor, in its own separate environments, with its real data loaded by a repeatable process.<\/li><li>On that foundation, the club later added a more complete members&#8217; portal, a public store with card payments through a local gateway (where the server, never the browser, decides whether a payment went through) and a sales cycle with invitations and source attribution.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-pullquote\"><blockquote><p>What can drift isn&#8217;t stored: it&#8217;s calculated. Remaining stock, a member&#8217;s status or whether an invitation is still valid are derived from facts that don&#8217;t change.<\/p><\/blockquote><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If your platform lives somewhere you don&#8217;t control, the first step is knowing, with tests, how today&#8217;s version behaves. The quote comes after that. The guide on <a href=\"\/en\/modernizing-a-legacy-system-in-stages\/\">modernizing a legacy system in stages<\/a> has the full method, and <a href=\"\/en\/#capacidades\">what we do<\/a> shows how we can help with your case.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>Your business runs on a platform that works. It has customers, sales, inventory, a portal. So far, so good. The problem is where it lives: a vendor generates it, hosts it and keeps the database, and you have no way to take it out. There is no test environment. You don&#8217;t know what gets deployed [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":90,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_locale":"en_US","_original_post":"72","footnotes":""},"categories":[5],"tags":[],"codyware_content_type":[6],"class_list":["post-89","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sistemas","en-US"],"_links":{"self":[{"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/posts\/89","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/comments?post=89"}],"version-history":[{"count":0,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/posts\/89\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/media\/90"}],"wp:attachment":[{"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/media?parent=89"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/categories?post=89"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/tags?post=89"},{"taxonomy":"codyware_content_type","embeddable":true,"href":"https:\/\/codyware.com\/wp-json\/wp\/v2\/codyware_content_type?post=89"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}