Seven applications were rebuilt to run without Manus, which is being shut down. Every one is live below on a staging subdomain, ready to check.
All seven run on *.staging.aetenum.com. They are marked noindex so Google will not index them alongside the live sites.
Three things are known to be incomplete, all waiting on credentials rather than code: the tents lead form needs its GoHighLevel webhook URL, the delivery calculator needs a replacement fuel-price source, and the time clock's Google Calendar and QuickBooks connections need their OAuth keys re-issued. Everything else is working.
Manus is shutting down. What survived was seven private GitHub repositories and nothing else — no running servers, no database, no environment settings, no admin console. The job was to make all seven run again on infrastructure we control, and to prove each one actually works rather than merely loads.
The repos turned out to be seven copies of one Manus scaffold: a React front end, an Express back end, and a folder called server/_core holding Manus's own platform code. That sameness was the single biggest advantage in the whole project — nearly every fix, once found, applied to all seven.
On the surface, six of the seven looked database-backed. They shipped a database schema, a database driver, and login plumbing. Looking closer, the schema in five of them was untouched boilerplate that still ended with the generated comment // TODO: Add your tables here, and no page in any of those apps had a login screen.
So the databases were decoration. Removing that dead weight meant five apps needed no database at all — no hosting bill, no credentials, no backups, nothing to break. Only the time clock was a real application.
| Application | What it actually needs |
|---|---|
| Dinnerware, Tables & Chairs, Brand | Static pages. The server only handed out files. |
| Tents, Delivery, Vantage | Static pages plus a single API call each. |
| Time Clock | Full application: real data, logins, Google Calendar, QuickBooks. |
The exports were complete in the sense that the source code was all there. They were incomplete in every way that matters for actually running the software. Each of the following would have produced a site that looked fine in testing and then quietly broke.
The build quietly injected a large script into every page — a second copy of React, a design-preview overlay, and a listener that let an embedding page set browser cookies. That last part is a genuine security concern on a public site, and none of it had any purpose outside the Manus editor.
Removed from production builds. The home page's HTML went from 369,928 bytes to 2,960 — about 99% smaller — and builds got roughly three times faster.
The sites loaded their imagery from Manus-owned servers. Those addresses work today and would have stopped working at shutdown, taking every photo on every site with them. Worse, the tents page was already broken — its four hero images were on temporary Manus URLs that had expired before we started.
All 32 images are now stored in the repositories and served from our own hosting. Nothing points at Manus.
The ten styled-shoot photographs were fetched through a Manus storage service that required a Manus API key to unlock. With Manus gone, they were unreachable — the single most likely thing to be lost for good.
The same ten images were found in the repository's own assets/gallery/ folder. The export notes said they were stored "in display order," and every photo's caption text matched its filename exactly, so the pairing was confirmed rather than guessed. The gallery is intact.
The tent hero images were full-resolution files of about 6.5MB each — roughly 26MB for one page. On a phone that is a very slow page and a real cost to whoever loads it.
Re-encoded to modern WebP at sensible dimensions: 25.8MB down to 0.92MB, a 96% reduction with no visible difference. The tables page dropped from 2.77MB to 0.35MB. The untouched originals are kept in the repositories.
Each page tried to load a Manus analytics script; with Manus's settings gone it requested a nonsense address on every visit. Separately, the projects did not pass their own type checks — the tents app shipped with eight errors, including a file that imported the same thing twice and a login screen calling a server function that did not exist.
Analytics tag removed; all eight errors resolved. Every project now type-checks cleanly and its tests pass.
The time clock's data came out as a single 274KB export file, produced by TiDB — a MySQL-compatible database, but not identical. Exports like this often need hand-editing before another database will accept them.
This one did not. Its TiDB-specific markers are written in a comment style that ordinary MySQL ignores, so it imported unmodified: 9 tables, 169 rows — 48 employees, 109 jobs, historical time entries and settings, all intact.
Everything was deliberately created fresh under aaron@olympustentsandevents.com, kept separate from any personal accounts, so ownership and billing sit with the business.
| Service | Role | Cost |
|---|---|---|
| Vercel | Hosts all seven applications; rebuilds automatically on every code change. | ~$20/mo |
| Railway | MySQL database for the time clock. Nothing else needs one. | ~$5/mo |
| Clerk | Handles staff logins for the time clock. | Free tier |
| Cloudflare | Existing domain; seven new subdomain records added. | No change |
Roughly $25 a month for all seven. The Vercel paid tier is not optional: its free plan forbids commercial use, and the time clock's automatic calendar sync needs scheduling that only the paid tier allows.
server/_core went from 17 files to 4, and about 16,700 lines of dead code were removed across the projects.This was the only genuinely difficult application, and the only one with real business data at stake.
Staff signed in through Manus's own login service. There was no way to keep that, so it was replaced with Clerk.
The risk in swapping a login system is losing the connection between a person and their history. Here the numbers made it manageable: the database held 48 employees but only 2 user accounts — only two people had ever actually logged in; the rest exist as employee records. The new system matches people by email address, so those two accounts keep their identity, their admin rights, and their attached time entries.
Helpfully, the whole application asks "who is this?" in exactly one place in the code, so the swap touched one file rather than being spread across the app.
The app pulled jobs from Google Calendar every 15 minutes using a timer inside the always-on server. On-demand hosting has no always-on process for a timer to live in, so the sync now runs as a scheduled task that calls the application on the same 15-minute cadence. The sync logic itself is untouched — only what starts it changed. The endpoint is protected by a secret, and refuses unauthorized calls.
Restored into the new database and verified row by row. One deliberate detail: the export file contains employee names, hours and location data, so it is explicitly excluded from anything deployed to the web. It stays in the repository for recovery only.
Five things broke that no amount of local testing would have caught, because each only appears in real hosting.
The three sites with APIs worked perfectly on a laptop and failed instantly in production. The development tools are lenient about how files reference each other; the production runtime is strict. Nothing in local testing could reveal it — builds, type checks and tests were all green.
Corrected across all four affected projects.
Deployments kept landing in a "blocked" state with no error message. Two separate causes: the account was still mid-upgrade, and then Vercel's rule that whoever authored a code change must be a member of the paid team — the changes were being authored under a personal identity.
Upgrade completed and authorship corrected to the business account.
An early check pronounced every image healthy. It was wrong. These sites answer unknown addresses with the home page rather than an error, so a missing image still replies "200 OK" — it just replies with a web page instead of a picture. Checking the status alone made deleted files look present.
Re-checked by asking what each address actually returned, not whether it answered. That immediately exposed four broken tent images and eleven broken Vantage gallery photos. Every image on every site is now confirmed to be a real image.
To stop 171MB of original photographs being uploaded on every deployment, they were excluded by folder name — which also matched a different folder of the same name that the sites genuinely needed, quietly deleting the tents logo and favicon.
The rule now points at one specific folder. Self-inflicted, caught by the same verification pass.
Cloudflare's automatic certificates cover name.aetenum.com but not name.staging.aetenum.com. Left at the default, every one of these addresses would have shown a browser security warning, and the usual fix is a $10/month add-on.
Routing the traffic slightly differently lets the host issue the certificates instead, at no cost. Anticipated before the first record was created, so it never became a visible problem.
"It loads" is not proof. Every claim above was tested against the live addresses:
| Item | Effect | Needed |
|---|---|---|
| GoHighLevel webhook (tents) | Lead form returns an error | The URL from the GHL account |
| Google & QuickBooks keys | Calendar and accounting sync are off; clocking in/out is unaffected | Re-issue from Google and Intuit |
| Fuel price source | AAA blocks automated lookups, so quotes flag that fuel is excluded rather than guessing | Free government data API key |
| Clerk production keys | Currently on development keys — fine for review, not for daily staff use | Promote when a permanent address is chosen |