Outgrew a no-code CRM that could not keep up with invoicing, time tracking and multi-currency billing.
Situation
The firm ran sales, projects, time tracking and invoicing from a CRM built on a no-code platform. It had grown to thirteen screens, seventeen tables and two dozen automations.
Every new requirement meant another workaround. Multi-currency billing, invoice reconciliation and reporting were all being done half in the app and half by hand.
The platform was also a dependency the business did not control: pricing, limits and features could change under them at any time.
What was built
- Documented every screen, table and automation in the existing app first, so nothing the team relied on would be lost. The product was the specification; the platform was not.
- Rebuilt it as a modern web application on a mainstream database: companies, contacts, deals, activities, timers, timesheets and invoices, with the same day-to-day flows the team already knew.
- Integrated Stripe so invoices are sent from the app, and every Stripe event is logged and reconciled automatically against the right invoice.
- Added a daily exchange-rate job so multi-currency totals are always available without slowing the app down.
What held up
- The team moved over without retraining, because the flows matched what they had.
- Invoicing and reconciliation happen automatically. Outstanding balances are visible per client and per project at a glance.
- The system is built on mainstream tools, so it can be monitored, maintained and extended as the business changes.
What I would do differently
- Profile the live export on day one, not after the teardown. The teardown from the screens under-described two wide tables, and I found out during migration.
- Put the policy tests in before the first screen. They went in during the build and caught a widened grant late; earlier would have been free.
- Treat the two dozen automations as a list to prune, not a list to port. Only the scheduled jobs and webhook flows carried logic; I spent a day proving that instead of assuming it.
Stack
Next.js, Supabase (Postgres), Stripe, Vercel