«37 days, 373 commits, one developer — and a live B2B SaaS in production. AI doesn’t build products. AI writes code for those who know how to design products»
Solo Marathon: Building a SaaS with AI in 37 Days
37 days of nonstop work. 373 commits. One developer. The result — a full-blown B2B SaaS for the service industry: Clients.Express. Booking, billing, client wallet, an autonomous AI agent in Telegram, geo-tracking of sessions. All from scratch, no off-the-shelf templates, no team.
This isn’t “I hacked together an MVP over a weekend.” This is production already used by real clients, accepting real bookings and charging real money from real balances.
Let me be straight with you: what worked, what broke, where AI was a superpower, and where I burned two nights on something no model could have warned me about — because I had to see it with my own eyes from the chair of a real barber.
Why from scratch and not on top of something ready-made
The first question my colleagues asked me was: “Why not take some ready-made booking service and just adjust it to your needs?” Two-word answer: because I knew what was coming next.
Off-the-shelf solutions cover the first 60% of the job. The 60% you see on the landing page. The remaining 40% — subscription billing, multitenancy, an AI agent that actually talks to the user in Telegram, granular session security. On that 40% any ready-made solution turns into a patch on top of a patch, where you spend more time wrestling with someone else’s architecture than actually shipping features.
At the start I did try the easy path. The first days I wrote on Laravel + Filament — a typical choice when you need to spin up an admin panel for CRUD quickly. In a demo it looks like magic: one command and there’s your panel. But within a couple of days I hit a wall. Every time I needed a feature Filament doesn’t do out of the box — non-standard action flows, non-standard UI elements, specific billing logic — I was spending more time “convincing” Filament to do it my way than I would have spent writing my own implementation from zero.
At some point I realised one simple thing: Filament is a great tool for someone else’s standard tasks, not for my non-standard ones. I ripped it out and started building my own admin panel on plain PHP 8.4 — and that freed my hands to keep moving without any external obstacles.
But this Laravel research gave me a side bonus I’m genuinely happy about: I stumbled across Herd and almost immediately picked up a Pro subscription once I realised how powerful and professional this tool is. For years I’d been sitting on MAMP Pro thinking I needed nothing else. Turns out I did. All my WordPress projects on Herd are noticeably faster, the configuration is many times simpler, and switching PHP versions is literally one click. MAMP Pro is a classic, but it’s already legacy, no two ways about it. Herd is the kind of innovation that made my local dev stack so comfortable I stopped noticing it’s even there.
So the final stack is clean: PHP 8.4 with no frameworks at all — only a dozen carefully picked Composer libraries for specific tasks (PSR-compliant components that do one thing and do it well). Custom architecture, custom admin panel, custom data model, custom abstractions for subscriptions and bookings. Zero inherited technical debt from code I didn’t write.
Claude Code and Codex as AI coding assistants
Let me kill one common misconception right here. I did not vibe-code this product. I did not sit there telling a model “build me a SaaS for barbershops.” It doesn’t work that way — or rather it does, but it ends sadly two weeks later when you can’t explain why your own database looks the way it does.
I used Claude Code and Codex as AI coding assistants in human-in-the-loop mode — a tool that writes code dozens of times faster than a human, never gets tired, never gets distracted, but every step it takes goes through my validation. Because it has one fundamental flaw — it has never seen your production and bears no responsibility for it. You hold the architecture. You define the boundaries of modules. You set the contracts between layers. The agent writes the implementation that you review on the fly.
Specifically — two agents that pulled this marathon with me: OpenAI Codex on GPT 5.4–5.5 and Claude Code on Opus 4.6–4.7 with the 1M context window. This isn’t a random zoo, it’s a deliberate choice. Codex is fast, concise, excellent at short file-level iterations and writes clean PHP code without unnecessary abstractions. Claude Code on Opus with a million-token context is a different weight class: it holds the entire project in its head at once, sees connections between modules, understands how a change in billing will ripple into booking through three files away.
The role split came naturally. Codex — for pinpoint tasks: “rewrite this controller”, “add a method here”, “generate a migration”. Claude Code — for architectural ones: full module review, refactoring with contextual understanding, designing new layers. One agent is a fast executor of pinpoint tasks, the other is a senior engineer who sees the whole picture. When they work as a tandem under the direction of an architect who keeps the product in his head — the speed becomes indecently high.
In this mode, one Senior does the work of a team. Not because AI is magic. But because the human-architect no longer spends half a day on boilerplate, migrations, CRUD controllers, form validation and other routine stuff that used to be hand-written.
373 commits in 37 days — that’s an average of 10 a day. Some days were 25, some were 2 (when I was hammering on a single bug or rewriting a module’s architecture). It’s not “AI does it for me.” It’s me doing it twice as fast as I could on my own.
Killer feature #1: an autonomous AI agent in Telegram
The hardest and most interesting part of the product — a Telegram agent that actually understands what the user wants and just does it. Not “press /start, then /book, then pick a date from a list.” Just: “book me with Olya for tomorrow afternoon, haircut please.”
Architecturally it’s a JSON tool loop: the model gets a description of the available tools (book_appointment, check_availability, top_up_wallet, get_profile, etc.), returns JSON with a tool call, the backend executes it, passes the result back into context, and the model makes the next decision. A classic agentic loop, but with a few load-bearing details:
- Context isolation — every user has their own context scope. The agent of one client physically cannot see another client’s data, even if it hallucinates the request. The check is at the tool-handler level, not at the prompt level.
- Protection against DB hallucinations — the agent does not write to the database on its own. No mutation operation runs without inline confirmation from the user in Telegram. Booking at 14:30 on Wednesday? “Confirm” button. Topping up the wallet? “Confirm” button. If the model decides to hallucinate and book you on a date you didn’t ask for — you simply don’t tap the button. The transaction never happens.
- System prompt as a contract — the agent is allowed to talk only about what concerns the product. Attempts to push it into anything else (from the weather to jailbreak instructions) crash against the strict tool-only mode.
Inline confirmation isn’t a UX detail. It’s a fundamental layer of security. AI agents in 2026 are great, but letting a model write to the production billing DB unconstrained is the kind of scenario that ends up as a LinkedIn post about lost data.
Killer feature #2: billing with “graceful degradation”
There’s an architectural nuance worth dwelling on. In Clients.Express the tariff is tied not to the user’s profile but to the company. This fundamentally changes the logic of restrictions when a payment is overdue.
If a user’s subscription has expired for a particular company — only the business function of that company gets blocked (new bookings). The user account itself keeps living a full life: profile is accessible, the referral programme works, the wallet works, you can even create a new company and operate within it. The user doesn’t get kicked out into nowhere — they just see a soft message in the right place: “to accept new bookings in this company — please renew the subscription.”
Why does this matter? Because the scenario where “a barbershop owner with a client who has just walked in sees a broken interface” — that’s a lost customer and lost trust in the service. But when the system calmly says: “renew the tariff for this company and let’s keep going,” while the rest of the profile features stay alive — that’s a completely different feeling about the product.
Technically it’s a middleware layer that knows which routes are critical (write operations on bookings) and which are read-only or service-level (profile, wallet, documents). Blocked selectively, not “flip the master switch.”
Killer feature #3: security at the level of a grown-up product
Security is the thing that in most solo projects looks like “well, I put HTTPS and bcrypt on the passwords.” In Clients.Express it’s different:
- Fail2Ban — at the server level, with custom filters tailored to the application logs. Login brute force, aggressive API requests, attempts to break into the Telegram webhook — it all gets caught and banned by IP automatically and without appeal 😉
- Geo-tracking of sessions — every session is tied to a country and an IP provider. If you logged in from Kyiv and 10 minutes later the same session is active from Bangkok — something is off.
- Auto-logout of suspicious sessions with email notifications — if the system detects an anomaly (sudden geo change, new country, unusual user-agent), the session is terminated, and the user gets an email with details: when, where from, which device. One click and you know what’s happening.
- Active session manager — at any moment the user sees the full list of their active sessions (device, browser, geo, last activity time) and can forcibly terminate any of them. Lost your phone? Left an authenticated session on someone else’s laptop? One click — and the session is closed.
- Session manager protection in the Apple/Telegram model — a freshly created or “young” session has no right to terminate other, “older” sessions. The logic is simple: if someone has just slipped into your account, they can’t immediately sign you out of your main device and hijack access.
2FA: TOTP + Passkeys
This project became the first one where I actually figured out and shipped full-blown two-factor authentication at a professional level — and that was the kind of experience worth diving into a new area for. That implementation is now my working module for every project that follows.
In Clients.Express the user can enable three types of 2FA simultaneously:
- SMS codes to a phone number — a classic baseline that I had already implemented in previous projects. Not the most secure option (SIM-swap is a thing), but the necessary minimum for users who don’t have an Authenticator app or a device with biometrics yet.
- TOTP codes via Google Authenticator (or any compatible app — 1Password, Authy, Bitwarden) — classic RFC 6238, with a QR code for binding and backup codes for recovery.
- Passkeys via WebAuthn / FIDO2 — login confirmation through Touch ID, Face ID, Windows Hello, or hardware keys (YubiKey and the like). No SMS, no passwords — biometrics or a physical key, the way Apple, Google and other grown-up platforms do it.
Honestly — I’m especially happy about how the Passkeys implementation turned out. It’s not a technology you just enable through some ready-made package. WebAuthn requires understanding the challenge-response flow, attestation validation, correct handling of public key credentials, and edge cases across different platforms. Now this works for me — and it’ll work in all my future products and my clients’ projects.
All of this together is not “protection just in case,” it’s the normal sanitary minimum for a SaaS that touches users’ money. Yes, of course, AI helped me write it faster. But deciding how exactly all of it should work — that’s already my engineering responsibility, not the agent’s.
Payments: how LiqPay said “no” and Monobank said “Meow!”
A separate chapter of this marathon — the acquiring. By inertia I went where everyone goes — and where I was used to going myself: LiqPay from PrivatBank. I’ve been hooking it up to clients’ online stores for years, I have a working routine with it, I even use it myself for my own client portal. So it felt like for my SaaS it would be the fastest option too. I submitted a merchant application, filled in the questionnaire, waited and… and got a rejection.
My business partner and client explained it to me succinctly: “It’s a state-run thing, they’re not interested in anything new.” Crude? Yes. But it matches my experience — my SaaS didn’t fit their scenarios, because it’s not a store, not a delivery service, not a taxi. Live innovation is out of scope.
Tried Monobank — and started purring. Everything happened the way it should in a normal world: they called me back, asked sensible questions, answered mine, helped me open a sole-proprietor account in the process and issued the merchant without any issues. No 50-question forms, no two-week waits, no “your application is under review.” Just people who do their job professionally.
Now Clients.Express accepts online payments via Monopay — and it’s not just a technical detail, it’s also part of the story of why 37 days became possible at all. Because when the infrastructure around you works adequately, you don’t burn weeks fighting with it. Special thanks to the kitties at Monobank — for the kind of professionalism that, in our local banking reality, is worth calling out separately. 🐱
SMS notifications: a separate thank-you to АльфаSMS
Another point I can’t skip, because the topic is narrow but telling. Any service with bookings needs SMS notifications for clients — appointment reminders, confirmations, cancellations. For that you need an alpha name (sender ID), and registering one is usually a story of its own — full of waiting, paperwork and bounced applications.
A small detail only those who have dealt with it will appreciate: registering a new alpha name with mobile carriers takes about two weeks on average. Two weeks of waiting per name. Which means if I had gone the classic route, just getting the alpha names I needed would have taken longer than building the entire product.
I reached out to АльфаSMS — and they simply made my job easier. Instead of running me through two-week registrations for every possible business type, they gave me a whole pack of ready-made generic alpha names covering different niches of my SaaS and instantly activated them in my account. Not in two weeks. Not in a day. Instantly. No “come back tomorrow,” no “this alpha name is taken.” Just — bam, activated, use it.
Right now Clients.Express clients can send SMS under these alpha names:
- Info Vizit — universal for any visit booking
- Barbershop — for barbershops
- Beautysalon — beauty salons
- SAUNA, BaniSauny — saunas and bathhouses
- SPA — spa complexes
- STO, Auto — car services and auto repair shops
- Hostel, Hotel — hotels and hostels
- Sport, Fitness — gyms and fitness clubs
- Massage — massage rooms
- Clinic — clinics and medical centres
- Studio — creative studios and coworking spaces
- Online Urok — online education and tutors
- Manicure — nail masters and manicure salons
And this is far from the entire list — there’s an additional pool of generic alpha names activated in my account covering other niches. If a client works in a segment that needs something specific, an option will almost always be available.
This isn’t just a list — it means any client of my SaaS who plugs into the system can immediately send SMS to their customers under a recognisable branded sender, with no extra registration dance. A big thank-you to the АльфаSMS team for their professionalism.
Reality crash test: when architecture meets the barbershop
For 37 days I built the system. Everything worked. Tests passed. Demo accounts looked great. Then I drove out to my first live client — a barber — for a presentation and setup, to deploy the product into combat mode.
The first thing that broke — my plan. In my head, booking worked on a clean grid: 30-minute slots, 60-minute slots, service duration, all very tidy. In a real barbershop the barber says: “listen, I can squeeze this client in between 14:15 and 14:40, I have a window there after the colouring.” Between 14:15 and 14:40. Not at 14:00 and not at 14:30 — between!
Not a single booking pattern I designed accounted for that. Because I’m an architect and I was thinking in slots. The master thinks about a real human being who simply wants to squeeze into his day.
I properly extended the module — added the ability for barbers and admins to manually edit the time of any booking with a 5-minute granularity. The logic is built so that manual shifts only affect how the online booking occupies the calendar, but don’t touch service price calculation in any way. So the master freely “drags” the booking edges in the calendar to fit the client into the real working rhythm, while the service price stays whatever is set in the price list. And separately I want to thank my clients who share these cases and feedback with me — that’s exactly how we build a truly best product around real tasks together, not around the developer’s idea of those tasks.
The second thing that broke — mobile onboarding. I had a beautiful scheme: a new client scans a QR code in Telegram, gets routed into the bot, gets auto-attached to the profile. I tested this on a laptop. On two monitors. QR on one screen — Telegram desktop on the other. All slick.
In a real barbershop the barber hands the phone to the client and says “scan this.” The client opens the camera. On the phone screen. The same QR code that needs to be scanned by the camera of that very same phone. A paradox. Impossible to scan.
Another rework: deep link instead of QR, fallback to a screenshot of the screen with the QR code that the user sends directly to the Telegram bot, a separate mobile onboarding flow that doesn’t require scanning at all.
Lesson from reality: AI doesn’t sit in the customer’s chair
I can ask Codex to write me a booking module. It will — fast, clean, with tests. But neither Codex, nor Claude Code, nor any other model sits in a barbershop and knows that the barber thinks about time differently than a programmer does.
Same with the QR code. Purely from an engineering point of view, binding via QR is an elegant solution. I tested it. AI helped me ship it. But only a real client in a real salon, with a single phone in his hand, made it clear that all that elegance was irrelevant. Because UX has to be tested on people, not on a developer’s monitor.
This is the boundary of AI development in 2026. The speed is cosmic. The code quality is decent. Architectural foresight — zero. If you don’t know how to design for real humans, AI will simply generate a fast wrong product for you. Fast wrong is not better than slow wrong. It’s worse: you’ve also wasted more time, because now you have to fix not a hundred lines but a thousand.
What 37 days and 373 commits mean in 2026
The most honest framing I can give: what used to take a team of 4–5 people 4–6 months is now done by one Senior architect with AI tools in a month. This isn’t marketing or hype (well, maybe a little hype 😊). It’s a fact backed by code, commits and a live client already using the system.
But there’s a price. And the price isn’t “buy a Claude Code subscription.” The price is 17 years of experience that hold the architecture, security, databases, networks, UX patterns, production operations, monitoring and a hundred other things in your head in parallel. AI accelerates those who already know what they’re doing. Those who don’t, AI just makes wrong faster.
I see two scenarios unfolding in parallel right now:
- Senior architects become 5–10× more productive — and that’s the new normal for solo development of complex products. One experienced engineer can now genuinely launch a SaaS that previously required a startup with seed funding.
- Beginners drown faster — because they generate code they don’t understand, at a speed they can’t review at. Mines fly into production that will explode at any moment.
Bottom line: a superpower with conditions
The result — a live SaaS in production with real payments, an AI agent, granular security and “graceful degradation.” And the first live client — a barber whose reality forced me to rewrite two modules over two nights. This isn’t a fairytale about “AI did it all.” It’s a story about how the tools compressed months into weeks — for those who know how to use them.
If you want to see what came out of it — here’s the product: Clients.Express. If you want the same pace for your own business — you know where to find me: vitaliikaplia.com.
As I’ve said before, AI is a crazy keyboard. The barbershop is reality. And between them sits the architect. Without an architect and pinpoint knowledge of “how to do it right,” the crazy keyboard will print you a huge pile of crazy AI-slop you’ll find almost impossible to handle — and is there even a point?