DEV Community

Akın Coşkun
Akın Coşkun

Posted on

I Built a RAG Chatbot Platform With Java Spring Boot and Next.js

TL;DR

I built an AI Chatbot Platform: a SaaS where you upload PDFs, URLs, or plain text, and it turns that content into a chatbot that only answers from what you gave it. Under the hood it's a RAG (Retrieval Augmented Generation) pipeline: pgvector with an HNSW index for similarity search, and a two-provider AI setup that tries Groq's Llama 3.3 first and falls back to Google Gemini. The backend is Java Spring Boot, the frontend is Next.js, and the resulting chatbots embed into any website with one line of code.

What it actually does

A user uploads documents (PDF, URL, or raw text), the platform chunks and embeds them, and stores the vectors in Postgres via pgvector. When a visitor asks the chatbot a question, the platform retrieves the most relevant chunks by vector similarity and feeds them to an LLM as context, so the answer is grounded in the uploaded material instead of the model's general training data. The finished chatbot can be embedded into any website with a single script tag.

Why pgvector with an HNSW index

Storing embeddings in Postgres (via the pgvector extension) instead of standing up a dedicated vector database keeps the stack to one database for both relational data (users, chatbots, documents) and vector data. HNSW (Hierarchical Navigable Small World) is the index type that makes similarity search fast at scale: it builds a layered graph of embeddings so a query doesn't have to compare against every stored vector, trading a small amount of recall for a large speedup. For a platform where every chatbot response depends on a fast retrieval step, that trade-off is the right one.

Why two AI providers, not one

The platform calls Groq's Llama 3.3 first because Groq's inference is fast and cheap, which matters when every chatbot reply requires a live generation call. But relying on a single provider means a rate limit or an outage on their end becomes an outage for every chatbot built on the platform. So there's a fallback path to Google Gemini: if the primary call fails or gets rate-limited, the request retries against Gemini instead of just failing. It's a small amount of extra complexity in exchange for not going down when one vendor has a bad day.

Java Spring Boot for the API, Next.js for the frontend

Most of my other projects are Node/Next.js end to end, so splitting to a Java Spring Boot backend here was a deliberate choice, not a default. Spring Security handles JWT-based auth, and Spring Boot's ecosystem made it straightforward to wire up the document ingestion pipeline (chunking, embedding calls, pgvector writes) as a set of clearly separated services rather than a pile of API route handlers. The frontend stays in Next.js 14 with TypeScript and shadcn/ui, talking to the Spring Boot API over REST. Keeping the boundary explicit (one API, one frontend, deployed separately on Render and Vercel) made it easy to reason about what each layer is responsible for.

The stack

Java 21, Spring Boot 3.x, Spring Security (JWT), PostgreSQL with pgvector, Next.js 14, TypeScript, shadcn/ui, Groq (Llama 3.3), Google Gemini, HuggingFace, Render, Vercel, Neon.

Try it

The AI Chatbot Platform is live at chatbot-web-peach.vercel.app, frontend source on GitHub: akincskn/chatbot-web, backend API: akincskn/chatbot-api.

I'm Akin Coskun, a full-stack developer from Turkey building production SaaS tools with zero-cost infrastructure. More projects on my portfolio: akin-coskun.web.app.

Top comments (0)