DevSolutions Solar is a Philippine solar installer. They had a working website but a fragmented operations layer: leads came in through a contact form, the sales team chased them by hand, common product questions ate hours of reply time, and there was no single place to see every inquiry's status. The brief was simple. Capture leads, qualify them, answer questions, and give the team visibility on the whole pipeline.

I shipped it in about two weeks, working primarily inside Claude Code, with Vercel and Supabase as the deploy and storage layer and n8n orchestrating the backend logic. You can talk to the chatbot at devsolutions-demo-v2.vercel.app.

This post is the build journal: what I chose, why, and the specific patterns that made the timeline possible.

The three problems, stated plainly

I always start by writing the problem in plain language, not in solution terms. For DevSolutions the list looked like this:

  1. Homeowners visiting the site cannot get a price estimate without a sales rep, which kills urgency.
  2. When a lead does come in, the sales team has no shared view of who is in the funnel and where each one is.
  3. Reps spend hours every week answering the same product questions over chat and email.

Each of those is solvable independently, but the leverage comes from solving them as a connected system. A lead who got an instant quote, was qualified by a chatbot, and lands in a dashboard the team can act on, is a lead with way more momentum than one who filled out a generic form.

The stack, and why

Before any code, I locked the stack:

  • Frontend: Next.js with the App Router, deployed on Vercel
  • Database: Supabase (Postgres with pgvector for the chatbot embeddings)
  • Orchestration: n8n, self-hosted
  • LLM: OpenAI API for the chatbot itself
  • Dev environment: Claude Code in VS Code, the entire build directed through it
  • Credentials: Bitwarden CLI, no API keys touch local disk

Some of these are choices anyone in 2026 might make. Two are worth explaining.

Why n8n over a code-only approach: the chatbot logic involves a fetch from a knowledge base, an LLM call, and conditional routing depending on whether the question is in-scope. I could have written all of that in a Next.js API route. I used n8n because each node is visible, the team can audit the flow without reading TypeScript, and when I need to add a step (a Slack notification, a Sheets write, a tag update on a CRM) I add a node, not a deployment.

Why Claude Code as primary IDE: I do not use the raw Claude API directly day-to-day. I live inside Claude Code. The W80 framework I follow (workflow, agents, tools, an approach Nate Herk talks about on YouTube) maps cleanly onto Claude Code's environment. Every new project starts with a claude.md file that documents the workflow, the agents I expect to call, and the tools each agent needs access to. Claude Code reads that and behaves accordingly.

The quote calculator

The first thing a homeowner hits is the calculator. They enter their monthly bill, their roof orientation, and a couple of other inputs. The calculator outputs a recommended system size, an estimated price band, and a "download PDF quote" button.

The PDF is real. It is generated server-side via a webhook into n8n, which pulls a template, fills in the numbers, and returns a signed URL. The homeowner clicks download. The same submission writes a row into the Supabase leads table with all the inputs plus the calculated outputs.

Two things mattered here:

  1. The PDF needed to be branded, not generic. Branded PDFs get screenshot-shared. Generic ones get ignored. n8n handles this cleanly via its Document node and a Supabase storage bucket for the template assets.
  2. The form had to feel instant. I do not want a homeowner waiting six seconds for a quote. The calculation is pure client-side TypeScript. The webhook for the PDF runs async in the background and the download link appears when ready.

The lead pipeline dashboard

Once a quote is generated, the lead lands in a custom pipeline dashboard built into the same Next.js app. Every submission becomes a card with stage, source, calculated system size, follow-up history, and notes.

The sales team can drag cards across stages (lead, contacted, quoted, scheduled, won, lost). Stage changes write back to Supabase via a useTransition optimistic update, so the UI feels fast even on a slow connection.

I did not use Trello or HubSpot. The reason is data ownership. When the chatbot needs to qualify a lead, it queries Supabase directly. When the calculator writes a new quote, it lands in the same table. The dashboard is just a view on top. There is no syncing, no webhooks fighting each other, no "but it's already in HubSpot" mismatches.

The RAG chatbot, which is where Claude Code shines

The chatbot is the part most readers came for. It answers product questions (panel specs, pricing tiers, installation timelines, warranty terms) in real time, and hands off to a human when the question goes out of scope.

The architecture:

  1. Knowledge base: a structured set of markdown documents living in Supabase, each chunked into roughly 300-token sections and embedded via OpenAI's embedding model. The embeddings live in pgvector inside the same Supabase project. One row per chunk, plus metadata (topic, intent, audience).
  2. Retrieval: on every user message, the chatbot embeds the question, runs a cosine-similarity search in pgvector, and pulls the top 4 to 6 chunks.
  3. Generation: those chunks plus the conversation history get sent to OpenAI's GPT-4 model with a tight system prompt. The prompt explicitly tells the model: answer only from the provided context, and if the answer is not in the context, say so and offer to hand off.
  4. Handoff: when the model returns a "I don't know" response, an n8n step pings the team in Slack with the question and the conversation snippet.

Here is the part that mattered for shipping speed: I did not build the n8n flow by clicking through the canvas. I used the n8n MCP server through Claude Code. That means Claude Code itself created the flow, node by node, in response to my instructions. I described the orchestration in plain English in a chat with Claude Code, and the MCP integration translated that into actual n8n workflow JSON, deployed it, and tested it.

This is the W80 framework in practice. The workflow is the RAG flow. The agent is Claude Code itself, building on my behalf. The tools are the n8n MCP server, the Supabase CLI, and the Vercel CLI. When I work this way, a chatbot that would have taken a week to wire by hand takes two days.

What I would have done differently with more time

A few items in the post-launch backlog, written here for honesty:

  • The handoff to human is a Slack ping, not a queued ticket. A real ticket system (Linear or even a Supabase table with status) would survive Slack scroll and let the team batch-handle handoffs at end of day.
  • The chatbot has no memory across conversations. A returning user starts fresh. Adding a user_id keyed conversation history would let the bot remember context across visits, which matters when someone is comparison shopping and comes back two weeks later.
  • The dashboard's drag-and-drop stage changes write immediately. There is no undo. A real CRM ships with an undo buffer. I would add that next.

None of those are blockers for what DevSolutions needed at launch. They are next-iteration items.

What I learned about Claude Code from this build

A few patterns I now use on every project:

  1. The claude.md file is the spec, and it is the most important file in the repo. It is what Claude Code reads at every new session to understand what we are building. If you skip it, every session starts cold and you waste tokens re-explaining the project.
  2. Bitwarden CLI for credentials, every time. I do not put API keys in .env files on my laptop. Claude Code asks Bitwarden CLI for the key it needs, gets it for the duration of the session, and never writes it to disk. If my laptop is compromised, my keys are not.
  3. MCP servers are the leverage point. The n8n MCP server is the difference between a two-week build and a two-day build for the chatbot flow. Wherever there is an MCP for the tool I am integrating, I use it. If there is not one, I check whether I can write a thin one in an afternoon.

If you are building something similar (lead capture, qualification, customer support automation on a real production site) and you want to talk through the architecture before you commit to a stack, that is a conversation I genuinely enjoy. The contact form on this site reaches my inbox within 30 seconds.