Case story
Ten years, one codebase: what maintaining Kapa since 2015 taught me about software that lasts
In 2015 I took on a client platform as a mid-level developer, with an honest promise and a lot to learn. A decade, one rewrite-free evolution and 26 services later, this is what building software that lasts actually looks like.
In 2015, a friend I played Dota 2 with told me his brother was looking for a programmer. I was a mid-level developer back then. I knew some PHP, and enough JavaScript with jQuery to be dangerous.
His brother was Ka Kei Ho, and he didn’t want a script or a landing page. He wanted a platform: a subscription service where businesses request unlimited graphic design and a real team delivers it. It was called Kapa99 back then; today the brand is simply Kapa. Payments, task management, file handling, the workflow of an entire agency.
I told him the truth: I had never built anything that size, and it would demand skills I only partly had. CSS at real depth, servers, database modeling, knowing what to build first, and the mental stamina to carry a system from zero to production. Then I told him the other half: if he trusted me with it, I was committing to finish it.
He trusted me. The design files arrived, and I broke into a cold sweat. The UX was excellent, full of interactions, carefully thought out by Ka Kei and his designer, Juan Carmona. It was clearly beyond what I knew how to build that day. That was the point.
Version 1: it wasn’t pretty, but it worked
My routine for the next stretch of my life: full-time job during the day, Kapa at night, weekends for studying whatever the week had exposed. I bought a Laracasts subscription and learned Laravel from Jeffrey Way, following a series called “Let’s Build a Forum” that started exactly where I was standing. PHP, databases, caching, design patterns, all at once.
Remember, this was the pre-AI era. No Claude, no ChatGPT, no autocomplete that writes functions. Books, forums, Stack Overflow, and an unreasonable amount of persistence.
The first version shipped on Laravel 4, jQuery, plain CSS and MySQL. It was not the best code of its time. But it worked, and it worked without drama, because I had tested that system until I ran out of ways to break it. That unglamorous first version ran a real business for four years and collected the most valuable asset a product can have: feedback from people using it daily.
2019: evolving without a rewrite
Four years in, Ka Kei and Juan produced a complete visual revamp. A new Kapa that looked nothing like the first one: more polished, more interactions, more professional. The first commit of that new era is dated November 25, 2019. I felt nothing but excitement about building a design of that level.
The tempting move was a full rewrite. We did something narrower: we split the system in two, so each part could evolve on its own schedule.
- The marketing site and blog went to Astro, React, TypeScript and Markdown, deployed on Cloudflare Pages so it loads fast anywhere in the world.
- The application stayed on a DigitalOcean droplet: Laravel, Vue, TypeScript, Redis, MySQL, with Stripe and PayPal handling subscriptions.
The other big change was automation. The operation had grown past what manual coordination could handle, so we built bots with Laravel and Supervisor to do what humans were doing by hand:
- Priority queues. Kapa has two plans whose main difference is delivery time, and 24-48h requests jump the line automatically.
- Task assignment that matches each request to the designer who does that type of work best, balanced against their current workload.
- A two-way Trello sync, because several clients loved Trello and didn’t want to leave it. Whatever happened on one side showed up on the other.
- Reports on subscriptions about to expire, and a list of smaller chores nobody misses doing manually.
The hardest thing I ever built
A logo request doesn’t ask the same questions as a business card, a book cover or a PowerPoint template. Every service needs its own request form, and Kapa launched with about 12 services. Today it offers 26.
Hardcoding 26 forms was never an option. The answer was a system I called attributes: independent form components that combine, in a specific order and steps, into the request experience of each service. A color picker. A gallery connected to Unsplash with its own search. Checkbox sets, image galleries with and without labels, drag-and-drop uploads, range sliders, datepickers, brand dropdowns. Independent pieces, composed like Lego into forms that feel designed by hand.
There was nothing on the market that came close at the time, so I built it from zero. It is still the heart of the product.
It is also where I owe my biggest confession. Deep in that code you will
find expressions like task.value.value, one .value per layer of
nesting. That section predates TypeScript in the project, and to this day
I haven’t managed to type it. It is powerful and flexible, and at the same
time fragile. When I extend it, I follow the reasoning of the person who
invented that mechanism. That person was me, ten years younger, and we’ve
learned to work together.
Two other builds deserve a mention. An image annotation component where anyone can click any point of an image and leave a comment, which sounds simple until you calculate positions proportionally across every screen size. And the kanban board, optimized through many late nights to hold the workload of agency clients who delegate all their design work, without freezing the browser.
The night the disk filled up
The worst incident in ten years started as they all do: the site was down, and SSH wouldn’t let us in. I was out on the street without a computer.
Ka Kei was at his machine, and he has been a Linux user for many years. So
we did the only sensible thing: brainstorm together while he tried. After
several attempts he got a session in and found the cause. The disk was at
100%, and /tmp was packed with temporary files.
The culprit was my own drag-and-drop upload component. It stored files in
/tmp, and when the user saved their card, it moved them to DigitalOcean
object storage and cleaned up after itself. A tidy design that ignored two
questions we never asked: what happens when a user abandons a card in
draft forever, and what happens when many users upload at the same time.
It got away from us. We optimized that pipeline afterwards, and it never
happened again.
Two lessons stayed with me. Incidents don’t come from the code you distrust; they come from the happy path you believed in. And a technical client is worth gold: that day, Ka Kei was our monitoring, our on-call and our remote hands, all at once.
Boring by design: the architecture that survived
Nobody would write a conference talk about Kapa’s architecture, and that
is exactly why it has lasted. Controllers. Fat models, even though the
blog posts of the era said not to: query scopes, relationships and small
single-purpose methods. There is nothing like reading $user->owns($board)
months later and understanding it instantly. No repository layer, because
the models were enough. Laravel’s notifications module. Model observers
for cascade cleanup, so deleting a task takes its messages, attachments
and activity with it. The Cache facade, which is a small masterpiece of
API design. Queues for syncing, email and notifications. And very few
events and listeners, because I like knowing where things fire from.
None of these layers is my invention. Every one of them shipped with the framework. That is a feature, and it is the reason I chose Laravel after trying Yii, Express and Meteor. My rule for tools has not changed since: a framework should feel like superpowers, like it and you are headed in the same direction. Most days, the documentation answered my questions before Stack Overflow had to. Need a controller? Documentation. A model? Documentation. Formatting dates between backend and frontend? Fine, Stack Overflow, because dates are delicate in every language ever made. I earned a decent chunk of Stack Overflow reputation during those years, which became my first way of giving back to the developers I had been learning from.
One more heresy: Kapa is not a single-page app. It renders server-side with Blade, and Vue appears only where real-time interaction earns its place. Posting a comment without a reload. Opening a card in a modal. Assigning a designer from inside the task. Everything else is traditional server rendering, with the data each screen needs passed down as props.
What a decade teaches you
The technology is maybe a third of the story. Kapa made me grow as a professional and as a person: prioritizing with the whole scope in mind, finding bottlenecks, running servers, handling DNS, and developing the judgment to know which work matters. Ka Kei is a genius at cutting the work he won’t need, and I learned to put myself in the shoes of the person operating the platform. That combination is why this partnership works, ten years and counting.
That project also changed my life in a way no line of code shows. The income from Kapa paid for my migration from Venezuela to Chile when things got hard back home, with day-long blackouts and shortages of water and gas. Custom software sounds abstract until it changes lives on both sides of the contract.
The part I didn’t expect: AI can read it
Here is the 2026 punchline. Today, AI tools understand the Kapa codebase without any rewrite. They extend it, they evolve it, they navigate it the way a new senior hire would. Not because the code is clever. Because it is conventional. Predictable structure and framework idioms turn out to be legible to machines for the same reason they are legible to humans.
The boring decisions of 2015 are still paying dividends in the age of AI.
Kapa has been in production since 2015. It has served nearly 5,000 users, processed almost 15,000 design tasks, stored over 117,000 attachments and hosted more than 100,000 comments. It has grown from 12 services to 26, survived one disk-full incident, and had exactly one engineer. If you are weighing custom software and wondering whether it can last a decade without a rewrite: it can. It just has to be built like it intends to stay.
Thinking about a project like this?
Get a free 15-minute audit of your current site or infrastructure. I reply with what I would build, what I would skip and a realistic budget range.
Keep reading
Custom software vs off-the-shelf: an honest framework from someone who builds custom
I make my living building custom software, and most businesses that ask me for it should buy off-the-shelf instead. This is the framework I use to tell which one you are, with the three-year math for both paths.
How much does custom web software cost in 2026? Honest ranges from a senior engineer
Real price ranges for automations, dashboards, portals and full platforms, from the engineer who quotes them. What drives the number up, what maintenance costs after launch, and how to budget without getting burned.