Skip to content

    Is your site invisible to AI? Get a free AEO Audit →

    From Months to Seconds: Building Gazette-Search for the Collections Industry

    The 5-minute challenge, the Lovable-to-Claude pivot, the data crisis we found, the customer-ethics call I'm proudest of, and who's using it now.

    An associate of mine in the collections space had been watching me work on a concept. I showed him the prototype one afternoon, with the kind of energy you only have for the first SaaS you've ever built. His response, paraphrased close to verbatim:

    "Unless you can get search results in under 5 minutes, my industry isn't interested. We've already tried to build something like this — with a developer, before AI — and it was a mess."

    That's the inciting incident for this whole project. Not a market research deck. Not a competitive analysis. One industry insider, sitting across the table, setting a clear bar and quietly letting me know what had already failed.

    It's also why this case study is worth your time if you run a collections agency, a BPO, or a financial-services team in South Africa. Because the bar that associate set wasn't just met. It was lapped. And the story of how a one-person shop got from "interesting demo" to "30-year credit management firm on a 3-month professional contract" runs through every interesting infrastructure problem a B2B SaaS can have.

    Pull up a chair.

    Why <5 minutes is the bar that matters in collections

    Large collection agencies and BPOs in South Africa run hundreds of thousands of searches per month against the Government Gazette. They're verifying deceased estates. Insolvencies. Liquidations. Sales in execution. Name changes. Every ID they don't clear is a case they can't close, a fee they can't bill, a recovery that doesn't ship.

    Turnaround time isn't a feature for this segment. It's the entire product.

    The manual baseline is unspeakable. Searches on government sites take hours, days, and sometimes months. The official government source is technically online but locked behind a corporate authentication layer that rejects anything other than a live browser session — useless for any kind of programmatic search at scale. The most popular community-built mirror, which most previous attempts had been built against, had started returning broken files for parts of the archive. The legally-clean public archive of historical issues was authoritative and complete, but frozen at 2021. Every existing access path was broken in a different way.

    For due-diligence work, a false "nothing found" is not a cosmetic problem. It's a real one — with legal and financial consequences a search engine isn't supposed to be responsible for. A lawyer who closes an estate without finding an unfiled insolvency notice ends up in a courtroom six months later answering questions about due diligence they thought they'd done. A collections analyst who clears an ID against a stale dataset puts a recovery into a queue that should never have been opened.

    That's the problem space. The associate had clocked it. So had everyone else in his industry. None of them had a working tool for it.

    The first build, the Lovable wall, the move to Claude

    One developer (me). One repo. A pragmatic web stack. The kind of stack you ship in, not the kind you put on a slide. I'm a designer who learned to ship — not a career backend engineer.

    I started in Lovable.

    Lovable is excellent for what it's excellent for. Fast UI iteration. Opinionated full-stack scaffolding. The kind of platform that gets a working web app standing in an afternoon. If you've never used it and you're building a marketing site, a dashboard, or a structured CRUD application, it's a serious tool.

    None of those strengths were the problem this product had to solve.

    The challenge wasn't "ship a search interface." It was: return matches against a database of millions of rows, fast enough that a collections analyst doesn't notice the wait — sub-second in the happy path, in a tool a user might run a thousand times in a shift. That requires query design and index strategy and the kind of repo-wide refactoring an SPA builder isn't designed for. I battled to get the system to return results in time. Not Lovable's fault. The wrong tool for the layer of the build I was on.

    So I switched to Claude.

    Claude understood the goal. Not in a marketing sense — in the practical sense of being able to hold the whole codebase in mind. Walking me through database queries I'd designed without thinking hard enough about how they'd be searched. Finding why a specific search was slow and rebuilding the index that fixed it. The engineering decisions stayed mine. The speed of working through them changed completely.

    Hundreds of prompts later — over several months of iteration — we had a system returning matches in seconds. Against a 2GB database. From a single web instance. For a use case where the manual alternative takes hours, days, sometimes months. The 5-minute bar wasn't met. It was lapped.

    This is what working with an AI assistant looks like in 2026, in my experience. The AI doesn't replace engineering judgment, and it doesn't write your architecture for you. It removes the cost of moving across unfamiliar territory. The bar an associate gave me was a bar a pre-AI small team had already failed to clear. A one-person shop with Claude cleared it. That isn't "AI builds it for you." It's "a small operator can punch above their weight class."

    I keep coming back to that distinction because it's the actual unlock — for me, and for every client build I do at BrandingLab. If you've ever been quoted six months for a build that should take six weeks because the agency is staffing five people on it, you've felt the inverse of this principle.

    The day the data started lying

    Six months into running the product, I caught a pattern I'd been missing.

    Roughly 29.6% of the historical searches we'd served had been silently coming back empty — not because the IDs weren't in the gazettes, but because the gazettes themselves had never been read correctly on our side. Lawyers had searched for IDs and gotten "nothing found" on cases that were actually there. For due-diligence work, that's not a quality issue. That's a defective product.

    The first place this showed up was a dashboard that said we had "0.3% gazette coverage" — which almost made me panic before I realised the metric was lying to me. The 0.3% was the share of total rows in the database that were gazettes, not the share of gazettes we'd processed. Each gazette spawns hundreds of child notices, so gazettes are always going to be a small slice of the row count by design. The real problem was buried one layer down, in a different table, where I hadn't been looking.

    I almost trusted the dashboard. I have written down, since, every metric on every dashboard I run, and what it is actually measuring. That's a habit I owe to a near-miss on a Thursday morning.

    The why was less mysterious than the what. The historical data source we'd been pulling from had become unreliable — returning broken or substituted files for parts of the archive. On top of that, the PDF parsing library we used couldn't read scanned image-based PDFs at all, and a meaningful slice of the older legal gazettes are scanned image-based PDFs. The two failure modes overlapped, and the result was a real data gap nobody on our side had noticed.

    The fix was honest work. I investigated every alternative source — official, community, archival, commercial — and most were broken in some way. One legally-clean public archive of historical issues was authoritative and complete, just frozen at 2021. I migrated all historical backfill to that source and rebuilt the missing data. For everything from 2022 onward, the platform now runs a weekly fetch against the official source — matched to the Gazette's own publication rhythm (52 issues a year). Data stays current without manual intervention.

    So the archive that was 29.6% empty six months ago is now both backfilled to completeness and kept current automatically. The next time we have a data-quality issue, it'll be a new one, not the old one.

    That's not a flex. That's how compounding investment in infrastructure actually works.

    Five times the platform fought us

    Even with the application returning matches in seconds, the question of how we kept the data fresh nearly took us down. Five separate times. All while the live product was serving paying users.

    First try. I ran the data-recovery work inside the same machine that served search traffic. The recovery pegged the CPU. The health check (which was, in retrospect, running a heavy database query — never do this) failed. The cloud platform interpreted the failed health check as a dead service and restarted the whole instance every 60 seconds. The recovery job never completed. The site flickered for an hour while users tried to search and got intermittent errors. The lesson: never put a database query in your health check. I now write this down on a sticky note before every new project.

    Second try. I made the health check stop doing database queries. Moved the recovery work into a low-priority background process on the same machine. Hit the memory ceiling instead — the recovery job got killed silently every time, even after I upgraded the machine to 5GB of RAM. The old legal gazettes are giant scanned PDFs and parsing them eats memory in ways no documentation warns you about, and the machine was also serving live search traffic in the background, and the kernel just kept choosing the recovery process to sacrifice.

    Third try. I tried to move the recovery work to a completely separate machine, sharing the database file with the live service. Turned out the cloud platform attaches a database disk to exactly one machine at a time. The architectural path I was on was closed by a platform constraint I should have read about a month earlier. The lesson: sometimes the platform is the boundary, not your code. The mental model you have of "I can just spin up another worker" assumes a degree of decoupling between compute and storage that doesn't actually exist on most managed platforms.

    The resolution. I took the recovery off the cloud platform entirely. Downloaded the production database to my Mac, ran the recovery work locally where there were no users to disturb and no platform limits to fight, then shipped the fixed database back to production through two new admin endpoints I built specifically for the purpose. Took an evening to wire up. Took a weekend to actually run the recovery. Took a long while to talk myself into the fact that the right move was off-platform after I'd spent so long trying to make on-platform work.

    The kicker. After the recovered 2.6GB database went live, the whole site started failing every request with a 502 error. Searches returned what looked like JSON to the browser but was actually HTML. The cloud platform's working scratch space had a hard 2GB ceiling. My database had just grown past it. Every time the service booted, it got evicted within 90 seconds, and the cycle repeated. I moved the database off the scratch space onto persistent storage, resized that persistent storage from 2GB to 10GB, and the platform finally stopped fighting me.

    The line I keep repeating to myself, and now to clients:

    It wasn't memory. It wasn't health checks. It was disk space. The CPU and RAM I'd been blaming were a red herring.

    None of this was about search latency. Sub-second search was already solved at the application layer. The five attempts above are the story of keeping that capability alive every time we needed to refresh the data underneath it. Operating a SaaS is mostly the second story, not the first. The first one ends the day you ship the feature; the second one continues for as long as anyone is using it.

    A bug from outside the system

    One of the worst bugs in the entire project wasn't on the cloud platform at all. It was on my own laptop.

    The folder I'd put the source code in was being silently synced by a cloud drive product running in the background. Every time I tried to save a change in the source-control system, the sync would write a file in the middle of the lock mechanism, and the save would silently fail. The first hint was that commits were failing on push. The second hint was that the commits had never actually completed locally. The third hint was a stack overflow thread three pages down that mentioned the same product by name.

    I spent more hours on this than I want to put in writing before I noticed.

    Moved the folder. Solved.

    The lesson: sometimes the bug is in a product you weren't even thinking about. The harder a bug is to reproduce, the more likely it's a system you didn't know was touching your system. I now keep a written list of every background-running product on every machine I develop on, just so I have a place to start when a bug refuses to make sense.

    The customer-ethics call

    This is the moment I'm proudest of in the whole project. It's also the moment that probably tells you the most about how I'd handle a client build, so it's worth slowing down for.

    The data crisis meant real users had searched for real IDs and gotten "nothing found" — when the gazette had been there the whole time. For collections agencies and lawyers running due diligence, that's not a service issue. It's a defective product they had paid us for and trusted.

    The expected SaaS move was obvious. Email everyone. Announce the dataset is now improved. Tell them to re-search. They'd pay for the re-searches. We'd technically be in the clear.

    I didn't do that.

    Instead, I went through every historical "nothing found" search in the system and quietly created a free retroactive watchlist for each one. 507 of the 728 historically failed searches were identifier-based and matchable against the recovered dataset. When a watchlist entry matches, the user gets an automatic alert at no cost, forever. They never have to know there was a problem. They just get the answer they originally needed, when it became findable.

    A bulk announcement would have re-opened the trust question. ("Wait — your data was wrong? For how long? What else?") A quiet retroactive watchlist alert, framed as a notification the user signed up for, simply delivers the value they were trying to buy in the first place. No "we apologise" email. No "please re-search at no charge" prompt that turns a defect into a marketing moment. Just the answer they came for.

    The principle:

    When the product was defective, the right move was to absorb the cost of the fix, not pass it back to the user.

    I've been quietly running that test on every operational decision since. It would have been cheap to do the bulk announcement and pocket the upsell. It would also have been the kind of decision I'd be embarrassed to write down in a case study like this one. The fact that you can read about it here without me cringing is, in a small way, the actual proof that it was the right call.

    A lawyer and a BPO walk into the same SaaS

    This is the title of an act, not the start of a joke. The structural tension Gazette-Search has had to live with from day one is the pricing tension between two completely different ends of the same market.

    A lawyer running a single estate-due-diligence search on one ID has the potential to surface billable work worth tens of thousands of rand. That one search is worth R35 to them all day, every day — it replaces a manual gazette check that costs R500-plus and takes months.

    An enterprise BPO running hundreds of thousands of searches a month against a recovery book cannot pay R35 per search. The unit economics of debt collection do not survive it.

    Same query. Two ends of the market. A several-hundred-thousand-fold volume gap. Completely different economic value per search.

    My first instinct was wrong. I started with what every SaaS founder starts with: subscription tiers. Three plans at R1,500 / R4,000 / R6,000 a month. It looked sensible on a pricing page. It fit neither persona. The lawyer who runs three searches a year shouldn't be paying R1,500 a month. The BPO running hundreds of thousands of searches a month wasn't going to fit inside a R6,000 ceiling without the spreadsheet starting to argue. The model penalised both ends and only worked for a narrow middle that didn't really exist.

    The current model is credits plus Enterprise.

    Credit packs. Eight tiers, R35 a search at the single end down to R0.55 at the 200,000-credit Volume end — a 64× per-credit compression across the volume curve. Pay for what you use. Credits valid 12 months from purchase. The lawyer buys one credit for R35 — or a 100-credit Starter pack at R10 a search — and never thinks about a subscription. The BPO buys the 200,000-credit Volume pack at R0.55 a credit (or steps up to Enterprise), and the per-search cost survives their unit economics. Monthly buyers put any pack on auto-refill and save 10%. Both ends pay a price that matches the value the search is actually delivering to them.

    Enterprise. From R250,000 for 500,000-plus credits, custom MSA. Banks, bureaus, continuous monthly screening — the segment where contracts and SLAs matter more than per-credit pricing.

    I'll be honest about what's still in transition. I migrated off the subscription model to credit packs earlier in 2026. The pricing config and every customer-facing page shipped clean. A few of the payment-processor-dependent pieces — the business-verification gate for the bigger packs, the monthly add-ons, auto-refill recurring billing — are still partially shipped. Some pages still advertise things that aren't billable yet. I'm fine telling you that, because honesty about what's not yet shipped is part of what this case study is.

    The lesson, the kind I'm going to keep repeating to clients:

    Subscriptions are for SaaS founders who haven't yet learned what they don't know about their pricing. Credits-plus-Enterprise is what most B2B products want to be eventually — usage-based pricing for the long tail, contract-based pricing for the head of the curve, and the discipline to stop pretending one model fits both.

    If you've ever sat across the table from a buyer and watched them do the arithmetic on a tier that doesn't fit their actual usage, you know how much commercial damage a bad pricing structure does. The damage is silent because the buyer doesn't tell you they're rounding you down to "too expensive." They just don't come back.

    Who's using it now

    I held off writing this section until the rest of the case study was solid, because traction without a built product to back it up is just a slide deck. Here's where it is today.

    The anchor customer is a 30-year-old South African credit management firm on a 3-month professional contract. The kind of business that has been doing due-diligence work the manual way for three decades — and decided to test the seconds-not-hours version on a paying contract. They're not named in this article. The point isn't who they are; the point is the kind of customer they are.

    A large BPO is in commercial discussions with us for an Enterprise contract right now — the right end of the pricing curve described above. Specifics are confidential while we're in negotiation.

    A handful of other businesses and solo practitioners are running the free demo tier. Some will convert when their first batch of credits runs out and they take a clean look at what they got for it.

    What this means for the reader: the 5-minute bar an associate set in the opening paragraph is operational at customer scale. The pricing model is not a thought experiment. It's billing real businesses for real searches at the per-credit prices specified.

    That's enough. I don't want to over-sell what's still a young product.

    The breach runbook, built before the breach (and not yet drilled)

    South African data-protection law gives a company 72 hours from discovering a breach to notify both the data-protection regulator and every affected user. Most SaaS startups don't think about that until incident one.

    I built the response runbook first. Five phases — Identification, Containment, Assessment, Notification, Post-mortem. Each phase has the actual database queries, command-line steps, and decision rules you would run while the 72-hour clock is on. Not theatre. Operational steps.

    The supporting infrastructure is deployed. A structured audit log of every admin action. A notifications table that proves which user got told what, and when. A "preview" admin endpoint that dry-runs the affected-users list and the exact email body before anything sends, so the IC can read every word before any user does. A "notify" endpoint that paces the actual sends to stay inside the email provider's rate limits. The code is in production. The endpoints respond.

    Why build all of this cold. A runbook you write under stress is a runbook with mistakes in it. Writing it cold meant I could think about edge cases I'd never think of mid-incident — like what to do if email itself is the compromised channel (fall back to LinkedIn messages and a notice on the public site).

    Here's what I haven't done — and what it's quietly taught me about my own operational discipline. I have never run a drill against the runbook. The runbook itself opens with a line that says "Last drill: never." I keep telling myself I'll do one next quarter. Compliance infrastructure is the kind of thing that's easy to leave alone until you can't anymore — until an incident lands and you find out, in real time, which parts of your runbook actually work and which parts you wrote for a version of the code that has since changed.

    The honest version:

    Built it cold. That was the right call. Haven't kept it warm since. That's the next call.

    I think that's a better closing line than the alternative version of this section, where I'd have told you confidently that the runbook is "battle-tested." The truthful version is more useful — to me, to anyone reading this who's also let a piece of compliance infrastructure go un-drilled too long, and to any prospect of mine who'd want to know what kind of person they're hiring to build their own infrastructure.

    Where it goes from here

    A roadmap with no overpromising attached.

    The database migration. The infrastructure war story above is the story of one specific decision — keeping the database on the same machine as the web service. Moving to a managed database (and running data refresh as a fully isolated scheduled job) is the version where the five attempts in Act 4 never repeat themselves. Costed at roughly $45–$105 a month all in. Next major architectural project.

    International expansion — Sub-Saharan first. Most Sub-Saharan African countries — Zimbabwe, Nigeria, and others — use the same Government Gazette structure as South Africa. The same core search engine works against any of them with minimal change. Sub-Saharan rollout is the active next data project, and it's commercially significant for collection agencies and BPOs with cross-border recovery work — which is the segment Gazette-Search was already built for. UK gazette scaffolding sitting in the repo was the original proof that the architecture generalises; the Sub-Saharan rollout is what's actually next.

    Image-based PDFs. The scanned PDFs that yielded nothing earlier would yield real text under an OCR pass. That's a quality-of-corpus win sitting right in the backlog and the cleanest path to closing the long tail of historical gaps.

    Pricing model still in transition. The subscription-to-credit-packs migration is mostly shipped. A few payment-processor-dependent pieces — the verification gate, the monthly add-ons, auto-refill billing — are still pending.

    No "we're disrupting the industry" close. Just honest sequencing.

    What this taught me about how BrandingLab works

    Three lessons. Each one shows up in every client build I do, and each one is here because the Gazette-Search build is where I actually learned it.

    1. Infrastructure debt compounds quietly, at the seams. Every problem in this build was where two systems met. The cloud platform's working storage meeting a growing database. A cloud file-sync product meeting source-control internals. A PDF parser meeting scanned image-based pages. The lesson isn't "test more." It's: look for the seams between systems and assume there's a hairline crack you haven't found yet. The most expensive bugs in a B2B product are never in one component. They're at the interface between two components nobody owns.

    2. The default option is not always the right option. The most popular data source for what I was doing was fine until it wasn't. The official government source was correct but unreachable. A quieter, legally-clean archive — the one nobody talks about — was the one that worked. The same principle holds for every client build I do at BrandingLab. The popular CMS, the standard hosting choice, the obvious stack are correct most of the time and quietly wrong in the cases that matter. The work is knowing which case you're in, and being honest with the client when the obvious answer isn't the right one.

    3. AI assistants don't replace engineering judgment. They remove the cost of moving across unfamiliar territory — and they let one-person shops compete with teams. I made every architectural call myself. Claude made it possible for me to make them across hundreds of prompts and several months of iteration, instead of the years it would have taken solo and pre-AI. The associate's 5-minute bar was a bar a pre-AI small team had already failed to clear ("it was a mess"). A one-person shop with Claude cleared it. That's the actual unlock — not "AI builds the product for you," but "a small operator can ship at a quality bar that used to require a team."

    This is what "B2B website and AI studio" means in practice at BrandingLab. I don't just build websites for clients. I run my own SaaS and feel every infrastructure call before I bring it to a client build.

    If you're a collections agency, a BPO, or a financial-services team running gazette searches — and you want to see what seconds-not-hours looks like inside your actual workflow — book a demo of Gazette-Search. The demo is real data against the live system, not a sandbox.

    If you're a B2B team with a project that doesn't fit a normal agency mould — including the kind of build where the only honest answer is "I'll prototype it on my own SaaS first" — talk to BrandingLab.

    A runbook you write under stress is a runbook with mistakes in it. I've been trying to write everything cold ever since.

    — Shalom

    Key Takeaways

    • The 5-minute-per-search bar in South African collections was a bar a pre-AI small team had already failed to clear. A one-person shop with Claude cleared it — the unlock is a small operator shipping at a quality bar that used to require a team.
    • A dashboard that said 0.3% gazette coverage was measuring the wrong thing. Write down every metric on every dashboard and what it is actually measuring — before you need to trust it in a crisis.
    • When the product was defective, the right move was to absorb the cost of the fix, not pass it back to the user. 507 quiet retroactive watchlists beat one bulk "we're sorry" email.
    • Subscriptions are for founders who haven't yet learned what they don't know about their pricing. Credits plus Enterprise — usage-based for the long tail, contract-based for the head — is what most B2B products want to be eventually.
    • The most expensive bugs in a B2B product live at the seams between systems nobody owns: platform scratch space meeting a growing database, a cloud sync product meeting Git internals, a PDF parser meeting scanned pages.

    Want to discuss this topic?

    Need a B2B Webflow agency that ships in 4 weeks with AEO baked in? See our Webflow services →

    Start a Conversation

    We use cookies

    We use essential cookies to make this site work, and optional analytics and marketing cookies to understand how it's used. You can change your choice anytime in Cookie settings.