Case study 01 · Web3Connect.com · Deep dive 2 of 3

Four apps in eight weeks

Tech stack selection, prototyping, AI hallucination, agents coding in parallel, and the cost of building fast. This is how I built Web3Connect.com in eight weeks, and the lessons learned.

Roles I covered
Founder, product designer, technical architecture, full-stack engineer, running releases
Team
Me, with Claude Code doing the engineering to a set of written rules and standards I wrote for it
Duration
Build began mid-October 2025. Launched 13 December 2025 — eight weeks
Tools
Next.jsTypeScriptPostHog PrismaPostgreSQLStripe RailwayCloudflareAlgolia Claude Code
Outcome
Four applications and a background service, launched on time. 259,600 lines of code, 929 changes committed before launch day

Part of a larger project

Web3Connect.com is a B2B reviews marketplace for the blockchain industry that I founded, designed and built solo. This page is about how it got built, how fast, and what that speed cost. Learn more about how I developed the commercial model behind it, and the post-launch discoveries & refinements. The overview has the background.

01

Choosing the tech stack

The default tech stack for this kind of project was Vercel for hosting & Supabase for database & user management. Instead of assuming this common stack would suit, I wrote down what the platform had to do, then used that list to rule options out.

Logins. Supabase sells itself partly on handling user accounts for you. While that is convenient, it also creates vendor lock-in, as user accounts and passwords are difficult to migrate. I researched various options that retained portability, and selected a well-maintained open-source solution, Better Auth instead. With logins handled elsewhere, Supabase was really just selling me a PostgreSQL database at a premium.

Scheduled work. The platform needed activities running in the background from day one: fetching data via APIs, recalculating rankings, summarising content, clearing caches, sending email, aggregating statistics, etc. At the time neither Vercel nor Supabase could run background jobs. I commissioned a research report using AI comparing the alternatives and went with its recommendation, Railway.

Requirements first, then vendors

I didn’t pick a platform and then find out what it couldn’t do. I wrote down what had to run and used that to rule platforms out. That sounds obvious, but it is often not the case for less mature engineers.

02

Buying a second opinion

Working on your own, the thing you miss most is a senior engineer telling you your plan is wrong. So I bought one. I paid for Supastarter, a mature commercial Next.js starter kit — not initially to build on, but to check my own technical specification against.

It found real gaps, and I adopted all of its answers: a simpler structure than the microservices I had been sketching, Turborepo to manage the applications together, Prisma for the database, TanStack Query for loading data, and Zod to validate data at every boundary. I rewrote the specification around what it taught me, and in the end used the starter kit as the foundation too.

The boilerplate natively supported the abstraction of 'organisations' vs associated users (members) which mapped well to Web3Connect.com where a user could manage multiple 'partner' profiles, or a partner could have multiple associated editor accounts.

Prisma allowed me to define the whole database and all its relationships in a single readable file, which meant the AI could read the entire data model at once. That turns out to matter a great deal, for reasons the next two sections explain.

03

Prototypes before building

With the specification, database design, category structure and brand positioning settled, I used AI to turn the specification into targeted design briefs, and then into working clickable prototypes — real pages, using the real design system, before any of the actual product existed.

Six full-page React prototypes laid out side by side on a canvas: home page, how-we-rank, category listing, for-partners, categories, and a smart contract audit pricing page.
Prototypes of the public site, reviewed and refined before building anything.
A partner dashboard prototype with placeholder charts and a demo user switcher in the sidebar listing New Seeker, Service Seeker, Pending Partner, New Partner Free, Partner Free and Partner Pro.
The dashboard prototype had a switcher for jumping between the six different types of user in one click.

The greatest challenge during this phase was that AI kept hallucinating 'enhancements' when building out the prototypes. Some were genuinely good ideas, however many of them would have added significant work I had not allowed for in my eight week build & launch timeline.

The fix was four changes to how I gave instructions, not a change of tool. Roll back rather than trying to prompt/edit the hallucinated features out. Edit the design brief to explicitly state what not to build. Rewrite every user journey diagram as text ('mermaid' markdown) rather than a picture, so the AI could read it instead of interpreting an image. And move every “later” idea out of the specification into a separate document, so ideas I'd noted for post-launch didn’t leak into what I was building now.

04

Day four: a hundred invented fields

On day four of the production build, I checked the database against my specification and found it had drifted badly: more than a hundred fields that weren't in my schema specification. AI had invented them, plausibly and consistently enough that nothing had visibly broken yet.

I must admit my confidence in building the whole platform using AI was shaken at this point. I was working with early-stage models with 200-250k token context windows, no sub-agent functionality, which dictated a high bar on context management.

I rolled back to a clean copy and updated the AI's base context file to place a mandatory check on database field alignment with my source specification schema.

The real problem was having two sources of truth

The AI wasn’t malfunctioning. I had a specification describing the data and a separate file defining it, and I had never said which one won. Faced with the ambiguity, it filled in the gap sensibly.

The fix is a rule I would apply to a team of people too: when two documents describe the same thing, one of them has to be named as the authority, in writing. The AI just exposed the gap in four days instead of four months.

05

Day eleven: splitting into four

By day eleven it was clear the single large application I was building was the wrong shape. I was working toward four distinct surfaces and each surface had genuinely different security risks and traffic patterns.

So I split it into four separate applications plus a background service, still managed as one project.

A file tree showing the web3connect monorepo apps directory containing admin, dashboard, public and review applications.
The four applications, after the split.
AppTraffic & accessWhy it’s separate
Public siteAnyone, read-only, very high trafficPages can be pre-built and served fast, and it needs to survive traffic spikes. Nothing here changes data.
Review submissionAnyone, writes data, moderate trafficThe only place a stranger can create content without logging in, which makes it the riskiest part. Isolated on purpose.
Partner dashboardLogged-in customers, low trafficEverything is personalised, so almost none of it can be pre-built or cached.
AdminMe and two staff, very low trafficHas the most power over the system. Needs a level of security isolation that would be unacceptable for public apps.

Keeping the four in completely separate projects would have given the same isolation, but then any code they share has to be versioned and published between them — ongoing work, every week, forever. Keeping them in one project ('monorepo' approach) means shared code is always immediately available to all four.

The benefit I hadn’t planned for

Four separate applications turned out to mean four separate projects I could work on at the same time. Using Git Worktrees, I could run four or five AI sessions at once, each building out features for a different application, without them overwriting each other’s work.

06

Managing the AI properly

An AI can only hold so much information at once, and building a complex platform with consistent coding & architecture practices, unique business model, abstraction of reviewing of offerings (vs partners) – all starts to create context constraints.

As my base approach, I used a roadmap + sprint approach to break the project into chunks that an AI agent with limited context window could handle. I provided pre-built prototype code & database schema to avoid ambiguity on output.

Dynamic context loading. My base context file had grown from 580 lines to 2,845 — this was using up valuable capacity that could be going to the actual task. I cut it to 200 lines: an index page and the rules that always apply, with everything else loaded only when relevant. I also added a hook function that reads the request, works out which reference documents are needed, and loads those before starting.

Handing over between sessions. When a session ran out of capacity prior to completing a sprint, the standard 'compact' process was leading to hallucination in output from that point onward. Monitoring context usage and 'handing over' the work-in-progress to a clean session was the only solution, however no method existed for cleanly transferring state. So I built commands that wrote a hand-off prompt for a new session to pick up where the last session ran out of context.

Writing decisions down. If the business went well it wouldn't have made sense for me to be stuck in engineering, so at every step of the platform build I planned for handover. I kept a build log for every session - and an architectural decision record for every significant technical decision, why it was made, and what alternatives were considered. By the end that came to 149 decision records and 105 session logs.

A project-management directory tree containing architecture-decision-records, audits, future-plans, parallel-development, reviews, roadmap and sprints with completed and parked sub-folders.
Roadmap, sprints, architectural decision records, build logs - all stored as markdown files for quick AI injestion.
A GitHub contribution graph showing 1,983 contributions in the last year, with density building from late October and continuing heavily through December to March.
Activity from late October onwards. 929 of the project’s 1,841 changes were made between starting and launch day.

As AI tools improved & context windows expanded I moved from writing detailed specifications towards defining the objective (or issue) in 'Plan mode', reviewing & agreeing to the execution plan in conversation first and building second. The conversational approach works well for established product refinement or bug diagnosis, but taking this approach for the initial core product build would have led to chaos.

Overall I'm happy with the quality of the final product and believe my oversight and orchestration approach was appropriate and effective for the state of AI development at the time.

07

Changing course mid-build

Avoiding a $10,000-a-year bill. I had planned to use Algolia for both search and filtering across the whole site. Partway through the build I projected the costs: Algolia charges per request, and at the traffic I was forecasting that came to US$3,000–10,000 a year. It also embedded a critical vendor dependency on nearly every page.

I decided to cut back the scope of Algolia to search query parsing — handling the cases where people misspell keywords, used synonyms or US vs UK spelling. I moved the filtering of partner offerings into PostgreSQL at no extra cost.

Measuring speed during the build. I logged how long every database query took and had the AI watching for slow ones as new features went in. That is how I caught a query taking 600 milliseconds and got it below 100ms through query restructuring.

Cutting scope openly. To achieve my launch date I postponed or feature-gated several features, including a pricing builder for offerings (nice-to-have), messaging facility (required claimed partner profiles), and various Pro features (advanced dashboard, visibility boost subscription). Partners would want to see traffic and reviews before they paid - building functionality that wouldn't be used until this happened was a commercial decision. Thanks to the speed of AI development, much of this was built in the weeks after launch.

A wasted day, and what it taught me

I spent a whole day trying to integrate my complex prototyped pricing plan functionality and end up with 100 modified files and a broken site that AI couldn't fix. The context window was simply too small for the breath of the feature. The next morning I rolled back a day’s work, broke the feature into smaller pieces, and had it working in two hours.

Nothing about the tool changed between those two days. It came down to understanding its current limitations & working within them.

AI can build fast, but humans need to provide the guardrails on scope and checkpoints.

shannon.diyNovember 2025
08

What building fast cost me

Four AI sessions running at once means four sessions that cannot see each other’s work. Each one needed something, so each one built it.

By the time I stopped to tidy up, the four applications had separate versions of the same basic operations: saving and editing records, form/content validation, cache clearing, score recalculation, counting reviews.

The worst case was logins: four separate versions, roughly 2,400 lines of duplicated code, each at a different level of completeness. Four different approaches to handling user sessions in one product isn’t just untidy, it’s a security risk.

I had AI perform a duplicate code audit and refactored the duplicates into shared libraries.

Plan ahead or plan for the clean-up

The duplication should have been obvious at the time – sessions that can’t see each other will inevitably duplicate code. Authentication & session management should have been identified and moved to a shared library earlier.

Working in parallel always costs something to pull back together. It's important to plan for code reviews as a trade-off of speed.

Inconsistent content state values: I had used a variety of words in my PRD to describe the state of content (partner profiles, offerings, reviews & reviewers). Keywords such as SUBMITTED, VERIFIED, APPROVED and PUBLISHED were being used to describe content states, and didn’t always mean the same thing across different content types.

A reviewer could be 'verified' (via email/LinkedIn), but their review may not be 'verified' by a moderator (thus should not be published). This nuance was causing AI to trip up during implementation, even though the database schema & PRD was clear.

On a review site this carries legal and reputational risk – a customer review could reach the public site without anyone checking it, because one application read another’s “verified” as “ready to publish”.

I standardised the content state terms across the entire system. It touched more than 130 files and took over two days - breaking in places, which I found and fixed during testing.

Don't make AI guess intent

I'd used terms for content states that were open to interpretation, which invited AI hallucination.

Testing regularly & thoroughly caught it, but it taught me a lesson in clarity (which applies to both humans and AI).

09

Launch, and the 48 hours after

Launch week involved three all-nighters in the final push to go-live. I launched on 13 December 2025, eight weeks after the first line of code (and 2 days before a Christmas cruise with family).

Two things went wrong that weekend.

Day one, the review submission app went down. I only found out because I happened to check. That evening I set up automatic monitoring across all three public sites.

Day two, a login bug on the live site. I added thorough error reporting so any error, no matter how small, would come to me immediately via Pumble (Slack alternative).

Don't just track success

I'd implemented extensive tracking of clicks & impressions (the core value proposition of the platform), but I'd neglected monitoring for failures and errors.

Over the following weeks I built error and status reporting into all layers of the application.

10

Fixing what I’d rushed

The months following launch went into speed optimisation, releasing held-back functionality, monitoring user behaviour (PostHog), back-office tools and automations, and targeting vendors to claim thier profiles.

There were various architectural issues that needed attention:

Forms. Adding one field to a partner or offering form meant editing more than ten different places. I audited how every form was built and validated, then consolidated it. The UX behaviour was included – scrolling to a field with an error, highlighting it, explaining the problem, greying out ‘next’ button with a tooltip saying why – all written once and shared, rather than rebuilt in each application.

Release process. I found a gap in my pre-release checks that was letting broken code through to the live site even though it worked fine on my machine, and added several automatic safeguards behind it.

Page speed. Restructured the key pages, removed or delayed code that wasn’t needed immediately, and audited what was actually being loaded.

PageSpeed Insights mobile report for web3connect.com showing 93 performance, 96 accessibility, 100 best practices and 100 for the fourth metric.
Google PageSpeed Insights for mobile after the work. Every public page type scored between 91 and 100, and Core Web Vitals were all inside the range Google considers good.

Caching, race conditions, and more duplication. Caching the public site made it load 30× faster, but it introduced a new problem — content staleness.

Resolving this issue was complex as it involved an analysis of:

  • which admin and user interfaces may trigger a state change to scored or ranked content
  • code duplication across each of these interfaces
  • the background worker / queue-based quality score recalculation system
  • related actions such as updating Algolia, a third-party content search index
  • mapping how content state changes (publishing, deletion, etc) for different types of content affected listed and static content across the public site
  • the multi-server app architecture (with no inter-app communication)
  • caching layers (database, page, CDN)
  • cache invalidation methodologies
  • security & performance considerations

I ultimately refactored the system to adopt a pipeline approach, where any change in content state would trigger a single 'downstream' function. This queued and performed a sequence of actions to recalculate quality scores, update rankings, update search indexes, invalidate caches, and rebuild affected pages in the correct order. This ensured that the live site always reflected the most current content state without inconsistencies or stale data.

A pipeline run detail showing ordered stages: quality score recalculation in 99 milliseconds, rankings in 724 milliseconds, then cache invalidation in 1.2 seconds purging and edge-warming 18 URLs, with the affected partners, offerings and categories listed.
Recalculate the score, redo the rankings, then rebuild the affected pages & cache. The steps that used to happen out of order now can’t.
A caching dashboard showing 99.8 percent overall cached, 5755 of 5769 items, broken down by static pages, categories, partners, product offerings and service offerings, with a dirty queue of 14 entries awaiting rewarm.
A dashboard to see the state of cache. After every release the whole site is rebuilt automatically, at a rate the server can handle.

The attack that was Google

Four hours of traffic at 51 times the normal level, which looked exactly like an attack:

254,900
requests per hour
204,084
gateway timeouts
30.3%
error rate
51×
normal traffic, for four hours

I checked three sources – Cloudflare, PostHog and Railway – querying each one conversationally through its MCP server rather than trying to read three dashboards at speed.

The diagnosis: it wasn’t an attack. 63% came from fifteen Google addresses running speed tests, and another 33% was Cloudflare multiplying those requests by pre-fetching pages.

I implemented a post-deploy cache warm-up process and implemented several bot-detection measures at the CDN and application level.

11

What I learned

Six things

  • If you can’t hire a second opinion, buy one. A commercial starter kit, used as something to check my plan against, cost a fraction of what fixing the same problems after launch would have.
  • Work within the tool's limits. AI coding is incredible, but it requires careful guidance and context management.
  • Be wary of AI interpretation. Where there is ambiguity there is scope for hallucination. Always define your source of truth when providing instructions. Detect and tackle inconsistency early.
  • Don't just track success. Tracking errors and failures provides valuable insights for improvement.

Get in touch

Want to go through any of this in detail?

Happy to walk through the code, the way I set the AI up to work, how I planned the build, or any of the problems above.