<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JavaCoder7</title>
    <description>The latest articles on DEV Community by JavaCoder7 (@sweety717).</description>
    <link>https://dev.to/sweety717</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4066834%2Fe2f5e9c7-7608-4a07-9ae5-67642bdafd71.png</url>
      <title>DEV Community: JavaCoder7</title>
      <link>https://dev.to/sweety717</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sweety717"/>
    <language>en</language>
    <item>
      <title>I Built a Self-Hosted AI Code Reviewer for GitHub PRs with Spring Boot</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Wed, 30 Sep 2026 01:29:54 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-a-self-hosted-ai-code-reviewer-for-github-prs-with-spring-boot-1ocf</link>
      <guid>https://dev.to/sweety717/i-built-a-self-hosted-ai-code-reviewer-for-github-prs-with-spring-boot-1ocf</guid>
      <description>&lt;p&gt;Why I built this&lt;/p&gt;

&lt;p&gt;Code review is one of the most important parts of a software development workflow, but reviewing every Pull Request manually can become repetitive.&lt;/p&gt;

&lt;p&gt;I wanted to experiment with a different approach:&lt;/p&gt;

&lt;p&gt;What if an AI reviewer could inspect a GitHub Pull Request, identify potential problems, explain them, and post the review back to GitHub?&lt;/p&gt;

&lt;p&gt;That led me to build CodeGuard AI.&lt;/p&gt;

&lt;p&gt;It is a self-hosted AI code-review application built with Java 17+ and Spring Boot.&lt;/p&gt;

&lt;p&gt;The goal wasn't to replace human code review.&lt;/p&gt;

&lt;p&gt;Instead, the idea was to create an additional automated layer that can identify potential issues before a human reviewer spends time going through the PR.&lt;/p&gt;

&lt;p&gt;What CodeGuard does&lt;/p&gt;

&lt;p&gt;The workflow is essentially:&lt;/p&gt;

&lt;p&gt;GitHub Pull Request&lt;br&gt;
        ↓&lt;br&gt;
GitHub API / Webhook&lt;br&gt;
        ↓&lt;br&gt;
Spring Boot Review Service&lt;br&gt;
        ↓&lt;br&gt;
Fetch PR information + changes&lt;br&gt;
        ↓&lt;br&gt;
AI Provider&lt;br&gt;
        ↓&lt;br&gt;
Bug / Security / Performance / Best Practice Analysis&lt;br&gt;
        ↓&lt;br&gt;
Quality + Risk + Confidence&lt;br&gt;
        ↓&lt;br&gt;
GitHub Comments&lt;br&gt;
        ↓&lt;br&gt;
Review History &amp;amp; Trends&lt;/p&gt;

&lt;p&gt;The application supports multiple AI providers:&lt;/p&gt;

&lt;p&gt;OpenAI&lt;br&gt;
Google Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;That makes the AI layer replaceable instead of tying the application to a single provider.&lt;/p&gt;

&lt;p&gt;The application dashboard&lt;/p&gt;

&lt;p&gt;The main dashboard provides two ways to start a review.&lt;/p&gt;

&lt;p&gt;A review can be triggered manually by providing a repository and Pull Request number, or the application can work with the GitHub workflow.&lt;/p&gt;

&lt;p&gt;It also exposes the major review categories directly in the interface:&lt;/p&gt;

&lt;p&gt;Security Review&lt;br&gt;
Performance&lt;br&gt;
Best Practices&lt;br&gt;
Bug Detection&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64pqny2sz78xor5ugxr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F64pqny2sz78xor5ugxr0.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The manual-review interface was particularly useful during development because it allowed me to test the complete review pipeline without depending on a live webhook every time.&lt;/p&gt;

&lt;p&gt;Starting a review&lt;/p&gt;

&lt;p&gt;For example, I can provide a repository and PR number and start the review.&lt;/p&gt;

&lt;p&gt;The application then moves through the review pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frplskeewlptdmvtp48r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frplskeewlptdmvtp48r8.png" alt=" " width="799" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The UI exposes the progress of the operation instead of making the user wonder whether the review is still running.&lt;/p&gt;

&lt;p&gt;The basic stages are:&lt;/p&gt;

&lt;p&gt;Reading PR&lt;br&gt;
    ↓&lt;br&gt;
Finding bugs&lt;br&gt;
    ↓&lt;br&gt;
Checking security&lt;br&gt;
    ↓&lt;br&gt;
Generating review&lt;/p&gt;

&lt;p&gt;This also highlights an important part of AI integrations that can easily be overlooked:&lt;/p&gt;

&lt;p&gt;AI operations are asynchronous from the user's perspective.&lt;/p&gt;

&lt;p&gt;A review may involve API calls, fetching repository data, preparing the PR changes, sending the analysis request, processing the response, and finally publishing the result.&lt;/p&gt;

&lt;p&gt;What does the AI review actually produce?&lt;/p&gt;

&lt;p&gt;After the analysis is complete, CodeGuard generates a structured review rather than returning one large block of AI text.&lt;/p&gt;

&lt;p&gt;For one of my test Pull Requests, the result included:&lt;/p&gt;

&lt;p&gt;Overall score: 8/10&lt;br&gt;
AI confidence: 90%&lt;br&gt;
Critical issues: 0&lt;br&gt;
Suggestions: 2&lt;br&gt;
Merge recommendation&lt;br&gt;
Categorized findings&lt;br&gt;
Code locations&lt;br&gt;
Suggested fixes&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjkenapoof6ks6pk38wao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjkenapoof6ks6pk38wao.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes the output much easier to consume than simply displaying an LLM response.&lt;/p&gt;

&lt;p&gt;The reviewer can immediately see the overall result and then drill down into individual findings.&lt;/p&gt;

&lt;p&gt;Findings are categorized&lt;/p&gt;

&lt;p&gt;Each finding is classified so that developers can focus on the type of problem they care about.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Critical&lt;br&gt;
High&lt;br&gt;
Medium&lt;br&gt;
Low&lt;br&gt;
Security&lt;br&gt;
Performance&lt;br&gt;
Best Practice&lt;/p&gt;

&lt;p&gt;In one test, CodeGuard identified a potential configuration issue involving GitHub token overrides.&lt;/p&gt;

&lt;p&gt;It also detected a repository-name case-sensitivity issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpz5f32bmh9qvkigfcomr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpz5f32bmh9qvkigfcomr.png" alt=" " width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The important part here isn't just detecting an issue.&lt;/p&gt;

&lt;p&gt;The system also provides:&lt;/p&gt;

&lt;p&gt;Location → Explanation → Suggested fix&lt;/p&gt;

&lt;p&gt;That makes the result more actionable for a developer.&lt;/p&gt;

&lt;p&gt;Posting the result back to GitHub&lt;/p&gt;

&lt;p&gt;One of the parts I wanted to experiment with was closing the loop.&lt;/p&gt;

&lt;p&gt;The reviewer shouldn't have to stay inside a separate dashboard forever.&lt;/p&gt;

&lt;p&gt;CodeGuard can post the review back to GitHub.&lt;/p&gt;

&lt;p&gt;The dashboard therefore shows whether the review has been posted successfully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3wl5vq996k8xwnu5d8c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3wl5vq996k8xwnu5d8c0.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a workflow closer to:&lt;/p&gt;

&lt;p&gt;Developer opens PR&lt;br&gt;
        ↓&lt;br&gt;
CodeGuard analyzes it&lt;br&gt;
        ↓&lt;br&gt;
Findings generated&lt;br&gt;
        ↓&lt;br&gt;
Review posted to GitHub&lt;br&gt;
        ↓&lt;br&gt;
Developer fixes issues&lt;br&gt;
        ↓&lt;br&gt;
Human reviewer continues the normal review&lt;br&gt;
Review history&lt;/p&gt;

&lt;p&gt;Another feature I wanted was historical visibility.&lt;/p&gt;

&lt;p&gt;Instead of treating every PR review as an isolated event, CodeGuard stores review results and exposes them through the review history.&lt;/p&gt;

&lt;p&gt;This allows the application to show:&lt;/p&gt;

&lt;p&gt;Previous Pull Requests&lt;br&gt;
Quality scores&lt;br&gt;
Issues found&lt;br&gt;
Repository information&lt;br&gt;
Review status&lt;br&gt;
Review details&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpqhl7tr9gwm1gs9luv0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpqhl7tr9gwm1gs9luv0i.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review trends&lt;/p&gt;

&lt;p&gt;The history also provides a simple trend view.&lt;/p&gt;

&lt;p&gt;The dashboard tracks:&lt;/p&gt;

&lt;p&gt;Quality Score vs Issues Found&lt;/p&gt;

&lt;p&gt;over previous reviews.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxu62jpq7xnikvogni1mj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxu62jpq7xnikvogni1mj.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is useful because a single review score doesn't tell the whole story.&lt;/p&gt;

&lt;p&gt;For example, if a project repeatedly receives lower-quality reviews or increasing numbers of findings, that pattern may be more interesting than any individual PR.&lt;/p&gt;

&lt;p&gt;Making the AI provider configurable&lt;/p&gt;

&lt;p&gt;Another engineering decision was avoiding a hard dependency on one AI provider.&lt;/p&gt;

&lt;p&gt;CodeGuard supports:&lt;/p&gt;

&lt;p&gt;OpenAI&lt;br&gt;
Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;The provider can be selected/configured through the application settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdsoximdm7049shtxur4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdsoximdm7049shtxur4k.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This also makes the project interesting for developers experimenting with local models.&lt;/p&gt;

&lt;p&gt;For example, a developer can use a hosted provider during development and experiment with a local Ollama setup when self-hosting is preferred.&lt;/p&gt;

&lt;p&gt;Custom review instructions&lt;/p&gt;

&lt;p&gt;The settings also allow custom review instructions.&lt;/p&gt;

&lt;p&gt;For example, a team could specify additional standards such as:&lt;/p&gt;

&lt;p&gt;Flag public methods without Javadoc.&lt;/p&gt;

&lt;p&gt;Flag endpoints that don't validate input.&lt;/p&gt;

&lt;p&gt;Flag direct System.out usage instead of logging.&lt;/p&gt;

&lt;p&gt;Flag newly thrown generic exceptions.&lt;/p&gt;

&lt;p&gt;These instructions are added to the review process alongside the built-in review criteria.&lt;/p&gt;

&lt;p&gt;This makes the reviewer more adaptable to a project's own engineering standards rather than relying only on generic AI code-review prompts.&lt;/p&gt;

&lt;p&gt;The Spring Boot architecture&lt;/p&gt;

&lt;p&gt;The backend is built around Spring Boot.&lt;/p&gt;

&lt;p&gt;The main pieces include:&lt;/p&gt;

&lt;p&gt;GitHub Integration&lt;br&gt;
        ↓&lt;br&gt;
PR / Diff Retrieval&lt;br&gt;
        ↓&lt;br&gt;
Review Service&lt;br&gt;
        ↓&lt;br&gt;
AI Provider Layer&lt;br&gt;
        ↓&lt;br&gt;
Structured Review Result&lt;br&gt;
        ↓&lt;br&gt;
Finding Classification&lt;br&gt;
        ↓&lt;br&gt;
GitHub Comment / Dashboard&lt;br&gt;
        ↓&lt;br&gt;
Review History&lt;/p&gt;

&lt;p&gt;The project uses:&lt;/p&gt;

&lt;p&gt;Java 17+&lt;br&gt;
Spring Boot&lt;br&gt;
Spring Security&lt;br&gt;
GitHub REST API&lt;br&gt;
AI provider integrations&lt;br&gt;
REST APIs&lt;br&gt;
Maven&lt;br&gt;
HTML/CSS/Vanilla JavaScript&lt;/p&gt;

&lt;p&gt;The important architectural decision was keeping the AI provider layer replaceable.&lt;/p&gt;

&lt;p&gt;That means the application isn't fundamentally tied to one model provider.&lt;/p&gt;

&lt;p&gt;What I learned building it&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI output needs structure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sending code to an LLM is relatively easy.&lt;/p&gt;

&lt;p&gt;Building a useful code-review product around that response is considerably more involved.&lt;/p&gt;

&lt;p&gt;You need to think about:&lt;/p&gt;

&lt;p&gt;What constitutes a finding?&lt;br&gt;
How should severity be represented?&lt;br&gt;
How do you identify the relevant code location?&lt;br&gt;
How do you avoid overwhelming the developer?&lt;br&gt;
How should findings be presented?&lt;br&gt;
How should the result get back into the existing GitHub workflow?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confidence and severity aren't the same thing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An AI system can be highly confident about a low-severity issue.&lt;/p&gt;

&lt;p&gt;So I wanted CodeGuard to keep concepts such as:&lt;/p&gt;

&lt;p&gt;severity&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;AI confidence&lt;/p&gt;

&lt;p&gt;separate.&lt;/p&gt;

&lt;p&gt;That gives developers more information when deciding which findings deserve attention.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Human review still matters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The purpose of CodeGuard isn't:&lt;/p&gt;

&lt;p&gt;"AI reviewed the PR, therefore merge it."&lt;/p&gt;

&lt;p&gt;The more useful model is:&lt;/p&gt;

&lt;p&gt;AI performs an additional automated review layer, while humans remain responsible for the final engineering decision.&lt;/p&gt;

&lt;p&gt;That distinction became important as I designed the workflow.&lt;/p&gt;

&lt;p&gt;What could be improved next?&lt;/p&gt;

&lt;p&gt;There are several directions I'd like to explore:&lt;/p&gt;

&lt;p&gt;Better inline GitHub comments&lt;br&gt;
More precise code-location mapping&lt;br&gt;
Improved false-positive handling&lt;br&gt;
Repository-level review policies&lt;br&gt;
Custom severity rules&lt;br&gt;
More granular review configuration&lt;br&gt;
Better webhook lifecycle handling&lt;br&gt;
Additional local-model support&lt;br&gt;
More detailed review analytics&lt;/p&gt;

&lt;p&gt;The project is intentionally designed as a self-hosted foundation that developers can customize, rather than a hosted SaaS product.&lt;/p&gt;

&lt;p&gt;Final thoughts&lt;/p&gt;

&lt;p&gt;Building CodeGuard taught me that an AI code reviewer is not simply:&lt;/p&gt;

&lt;p&gt;GitHub API + LLM = code reviewer.&lt;/p&gt;

&lt;p&gt;The interesting engineering work happens around the model:&lt;/p&gt;

&lt;p&gt;GitHub integration → PR processing → review orchestration → structured findings → severity → confidence → developer feedback → history.&lt;/p&gt;

&lt;p&gt;That's where the application becomes an actual workflow rather than just an AI prompt.&lt;/p&gt;

&lt;p&gt;Want to explore the implementation?&lt;/p&gt;

&lt;p&gt;I built CodeGuard AI as a self-hosted Spring Boot source-code project for developers who want to study, customize, and build on this type of AI code-review workflow.&lt;/p&gt;

&lt;p&gt;Get the CodeGuard AI source code on Gumroad: &lt;a href="https://javacoder716.gumroad.com/l/codeguard-ai" rel="noopener noreferrer"&gt;https://javacoder716.gumroad.com/l/codeguard-ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>github</category>
      <category>springboot</category>
    </item>
    <item>
      <title>I Built a Multi-Provider AI Resume Analyzer with Spring Boot — Here's How ATS Matching Works</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Tue, 29 Sep 2026 15:36:11 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-a-multi-provider-ai-resume-analyzer-with-spring-boot-heres-how-ats-matching-works-3jg5</link>
      <guid>https://dev.to/sweety717/i-built-a-multi-provider-ai-resume-analyzer-with-spring-boot-heres-how-ats-matching-works-3jg5</guid>
      <description>&lt;p&gt;If you've ever tried building an AI-powered resume analyzer, one of the first things you discover is that:&lt;/p&gt;

&lt;p&gt;"Send the resume to an AI model and ask for an ATS score" isn't really enough.&lt;/p&gt;

&lt;p&gt;A useful resume-analysis system needs to answer several questions:&lt;/p&gt;

&lt;p&gt;How well does the resume match a specific job description?&lt;br&gt;
Which skills are missing?&lt;br&gt;
Which keywords are missing or underrepresented?&lt;br&gt;
How strong is the ATS compatibility?&lt;br&gt;
Does the candidate's experience match the role?&lt;br&gt;
What could be improved?&lt;br&gt;
Can AI help rewrite the resume?&lt;br&gt;
Can the system compare different resume versions?&lt;/p&gt;

&lt;p&gt;I wanted to explore these problems from a backend-engineering perspective, so I built ResumeIQ AI, a Java and Spring Boot based AI resume-analysis application.&lt;/p&gt;

&lt;p&gt;The interesting part wasn't simply connecting an application to an AI API.&lt;/p&gt;

&lt;p&gt;It was building the workflow around it.&lt;/p&gt;

&lt;p&gt;The Technology Stack&lt;/p&gt;

&lt;p&gt;The backend is built around:&lt;/p&gt;

&lt;p&gt;Java 17&lt;br&gt;
Spring Boot 3&lt;br&gt;
Spring Security&lt;br&gt;
Spring Data JPA&lt;br&gt;
MySQL&lt;br&gt;
Thymeleaf&lt;br&gt;
Maven&lt;br&gt;
OpenAI&lt;br&gt;
Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;One of the design decisions I wanted to explore was multi-provider AI support, rather than coupling the application to a single AI provider.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Starting With the Resume and Job Description&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An ATS score without a target job isn't particularly meaningful.&lt;/p&gt;

&lt;p&gt;Consider a resume containing:&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
MySQL&lt;br&gt;
Docker&lt;br&gt;
REST APIs&lt;br&gt;
Microservices&lt;/p&gt;

&lt;p&gt;For one position, that could be a strong match.&lt;/p&gt;

&lt;p&gt;For another position requiring:&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
Kafka&lt;br&gt;
AWS&lt;br&gt;
Kubernetes&lt;br&gt;
Redis&lt;/p&gt;

&lt;p&gt;the same resume could have significant gaps.&lt;/p&gt;

&lt;p&gt;So instead of asking:&lt;/p&gt;

&lt;p&gt;"Is this a good resume?"&lt;/p&gt;

&lt;p&gt;the application asks:&lt;/p&gt;

&lt;p&gt;"How well does this resume match this particular job?"&lt;/p&gt;

&lt;p&gt;The basic workflow is:&lt;/p&gt;

&lt;p&gt;Resume&lt;br&gt;
   +&lt;br&gt;
Job Description&lt;br&gt;
   ↓&lt;br&gt;
Resume Analysis&lt;br&gt;
   ↓&lt;br&gt;
Matching&lt;br&gt;
   ↓&lt;br&gt;
ATS Score&lt;br&gt;
   ↓&lt;br&gt;
Skills + Keywords + Gaps&lt;br&gt;
   ↓&lt;br&gt;
AI Suggestions&lt;br&gt;
   ↓&lt;br&gt;
Resume Improvement&lt;br&gt;
Here's what the analysis starts with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxyzp1kfli70dvzxeye1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxyzp1kfli70dvzxeye1c.png" alt=" " width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ResumeIQ starts with a job description and resume rather than generating a generic resume score.&lt;/p&gt;

&lt;p&gt;The user can provide a resume and the complete job description, and the application analyzes the two together.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resume → Job Description Matching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The matching process can be thought of as:&lt;/p&gt;

&lt;p&gt;Resume&lt;br&gt;
   ↓&lt;br&gt;
Extract relevant skills / experience / keywords&lt;br&gt;
   ↓&lt;br&gt;
Job Description&lt;br&gt;
   ↓&lt;br&gt;
Extract required skills / keywords&lt;br&gt;
   ↓&lt;br&gt;
Compare&lt;br&gt;
   ↓&lt;br&gt;
Generate analysis&lt;/p&gt;

&lt;p&gt;The result isn't intended to be just one number.&lt;/p&gt;

&lt;p&gt;It can contain:&lt;/p&gt;

&lt;p&gt;Overall match score&lt;br&gt;
ATS compatibility&lt;br&gt;
Matching skills&lt;br&gt;
Missing skills&lt;br&gt;
Keyword analysis&lt;br&gt;
Experience comparison&lt;br&gt;
Score breakdown&lt;br&gt;
Improvement suggestions&lt;br&gt;
Here's an example from the application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbga69v417yop1a0b50zm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbga69v417yop1a0b50zm.png" alt=" " width="799" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The analysis provides both an overall match score and a more detailed breakdown of the resume against the job description.&lt;/p&gt;

&lt;p&gt;The example shows an 88% match along with an ATS compatibility score of 90%.&lt;/p&gt;

&lt;p&gt;The important part is that the score is accompanied by additional information explaining what contributed to it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Breaking Down the Score&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A single score can be difficult to interpret.&lt;/p&gt;

&lt;p&gt;For that reason, ResumeIQ breaks the analysis into different categories.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Technical Skills&lt;br&gt;
Experience&lt;br&gt;
Projects&lt;br&gt;
Education&lt;br&gt;
Achievements&lt;/p&gt;

&lt;p&gt;Each category contributes to the overall analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld24ma2stcr2eyc70i35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld24ma2stcr2eyc70i35.png" alt=" " width="799" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The score is broken into multiple categories rather than presenting only a single ATS number.&lt;/p&gt;

&lt;p&gt;This makes it easier to identify where the resume is relatively strong and where it needs improvement.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finding Missing Skills and Keywords&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the more useful parts of resume-to-job matching is identifying what is missing.&lt;/p&gt;

&lt;p&gt;For example, a job description might require:&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
Hibernate&lt;br&gt;
PostgreSQL&lt;br&gt;
Microservices&lt;br&gt;
AWS&lt;br&gt;
CI/CD&lt;/p&gt;

&lt;p&gt;while the resume may clearly demonstrate some of those skills but not others.&lt;/p&gt;

&lt;p&gt;ResumeIQ separates this information into areas such as:&lt;/p&gt;

&lt;p&gt;Matching skills&lt;br&gt;
Missing skills&lt;br&gt;
Keyword frequency&lt;br&gt;
Keyword recommendations&lt;br&gt;
Importance of missing skills&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnbfaciejs31u02mryad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnbfaciejs31u02mryad.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application identifies missing skills and also analyzes how frequently important keywords appear in the resume.&lt;/p&gt;

&lt;p&gt;This is more actionable than simply telling someone:&lt;/p&gt;

&lt;p&gt;"Your ATS score is 78."&lt;/p&gt;

&lt;p&gt;The more useful question is:&lt;/p&gt;

&lt;p&gt;"Why is the score 78, and what can I change?"&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Looking Beyond Simple Keyword Matching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Traditional keyword matching has limitations.&lt;/p&gt;

&lt;p&gt;Suppose a resume contains:&lt;/p&gt;

&lt;p&gt;"Built backend services using Spring Boot."&lt;/p&gt;

&lt;p&gt;while a job description says:&lt;/p&gt;

&lt;p&gt;"Experience developing RESTful microservices using Spring Boot."&lt;/p&gt;

&lt;p&gt;A useful system needs to consider more than whether two strings are identical.&lt;/p&gt;

&lt;p&gt;This is where AI can become useful.&lt;/p&gt;

&lt;p&gt;The application can use AI to interpret the resume and job-description context and generate recommendations around:&lt;/p&gt;

&lt;p&gt;wording&lt;br&gt;
experience descriptions&lt;br&gt;
missing information&lt;br&gt;
resume structure&lt;br&gt;
potential improvements&lt;/p&gt;

&lt;p&gt;The goal isn't to let the LLM decide everything.&lt;/p&gt;

&lt;p&gt;Instead, the application combines structured analysis with AI-generated reasoning.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turning Analysis Into Suggestions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After identifying potential weaknesses, the system can turn them into concrete recommendations.&lt;/p&gt;

&lt;p&gt;For example, the analysis can suggest improvements around:&lt;/p&gt;

&lt;p&gt;AWS experience&lt;br&gt;
resume structure&lt;br&gt;
duplicate skills&lt;br&gt;
ATS formatting&lt;br&gt;
experience descriptions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94eosm07u72pd9e0hxvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F94eosm07u72pd9e0hxvx.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI layer turns the analysis into specific suggestions instead of stopping at a score.&lt;/p&gt;

&lt;p&gt;This creates a workflow closer to:&lt;/p&gt;

&lt;p&gt;Analysis&lt;br&gt;
   ↓&lt;br&gt;
Identify weakness&lt;br&gt;
   ↓&lt;br&gt;
Explain weakness&lt;br&gt;
   ↓&lt;br&gt;
Suggest improvement&lt;/p&gt;

&lt;p&gt;rather than simply:&lt;/p&gt;

&lt;p&gt;Resume → Score → Done&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before vs After Resume Improvements&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the more practical features is showing how specific resume statements could be improved.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Before&lt;/p&gt;

&lt;p&gt;Developed and Maintained backend microservices and relational databases in production; reduced API response time by 30% through query optimization and service tuning.&lt;/p&gt;

&lt;p&gt;After&lt;/p&gt;

&lt;p&gt;Developed and maintained production backend microservices and relational databases using Spring Boot, reducing API response times by 30% via query optimization and database tuning.&lt;/p&gt;

&lt;p&gt;The objective isn't to invent experience.&lt;/p&gt;

&lt;p&gt;It's to make existing experience clearer and more aligned with the job requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fytrnllvhxttubtgmmetn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fytrnllvhxttubtgmmetn.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application shows concrete before-and-after examples rather than only giving general writing advice.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI Resume Rewriting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next step is taking those recommendations and generating a complete improved version.&lt;/p&gt;

&lt;p&gt;ResumeIQ includes an AI resume-rewriting workflow that can generate an ATS-oriented version based on the selected job description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpfetsvlymyr58uu5s9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpfetsvlymyr58uu5s9o.png" alt=" " width="799" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generated resume can then be reviewed and exported in different formats.&lt;/p&gt;

&lt;p&gt;The important design principle here is that the system should improve how existing experience is presented rather than fabricate qualifications.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resume Versions and Comparison&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Resume optimization is often iterative.&lt;/p&gt;

&lt;p&gt;A candidate might have:&lt;/p&gt;

&lt;p&gt;Version 1 → 82%&lt;br&gt;
Version 2 → 88%&lt;br&gt;
Version 3 → 92%&lt;/p&gt;

&lt;p&gt;Instead of treating every analysis as completely independent, ResumeIQ includes functionality around:&lt;/p&gt;

&lt;p&gt;analysis history&lt;br&gt;
resume versions&lt;br&gt;
comparing resumes&lt;br&gt;
tracking score changes&lt;/p&gt;

&lt;p&gt;The application also supports comparing two resumes against the same job description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskmmhwrqw9thti7jg3fj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskmmhwrqw9thti7jg3fj.png" alt=" " width="799" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be useful when experimenting with different versions of the same resume.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multi-Provider AI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One architectural decision I wanted to explore was avoiding a hard dependency on one AI provider.&lt;/p&gt;

&lt;p&gt;ResumeIQ supports:&lt;/p&gt;

&lt;p&gt;OpenAI&lt;br&gt;
Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             ┌── OpenAI
             │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Application ── AI Provider Layer ── Gemini&lt;br&gt;
                 │&lt;br&gt;
                 └── Ollama&lt;/p&gt;

&lt;p&gt;This gives developers flexibility to experiment with different providers and deployment approaches.&lt;/p&gt;

&lt;p&gt;For example, a developer might want to use a cloud model in one environment and a locally running model through Ollama in another.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why Use Spring Boot?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For this project, Spring Boot acts as the backend foundation connecting the different parts of the application.&lt;/p&gt;

&lt;p&gt;The application needs to handle:&lt;/p&gt;

&lt;p&gt;Authentication&lt;br&gt;
      ↓&lt;br&gt;
Resume processing&lt;br&gt;
      ↓&lt;br&gt;
Job-description processing&lt;br&gt;
      ↓&lt;br&gt;
Matching&lt;br&gt;
      ↓&lt;br&gt;
AI integration&lt;br&gt;
      ↓&lt;br&gt;
Persistence&lt;br&gt;
      ↓&lt;br&gt;
Analysis results&lt;/p&gt;

&lt;p&gt;This is where the project becomes more interesting than simply calling an AI API.&lt;/p&gt;

&lt;p&gt;The backend has to coordinate multiple workflows and maintain the state of analyses, resumes and versions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Interesting Engineering Problem&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most interesting part of building an AI application isn't necessarily:&lt;/p&gt;

&lt;p&gt;"How do I call an LLM?"&lt;/p&gt;

&lt;p&gt;The harder questions are:&lt;/p&gt;

&lt;p&gt;What information should be sent to the model?&lt;/p&gt;

&lt;p&gt;How much context is enough?&lt;/p&gt;

&lt;p&gt;Which parts should be deterministic?&lt;/p&gt;

&lt;p&gt;Which parts actually benefit from an LLM?&lt;/p&gt;

&lt;p&gt;How do you avoid coupling the entire application to one provider?&lt;/p&gt;

&lt;p&gt;These questions become increasingly important as an AI application grows beyond a simple API demo.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What I Built&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The resulting application includes functionality around:&lt;/p&gt;

&lt;p&gt;ATS-style resume analysis&lt;br&gt;
Job-description matching&lt;br&gt;
Match scoring&lt;br&gt;
Missing keywords&lt;br&gt;
Missing skills&lt;br&gt;
Keyword analysis&lt;br&gt;
Experience-gap detection&lt;br&gt;
Improvement suggestions&lt;br&gt;
AI rewriting&lt;br&gt;
Resume/JD comparison&lt;br&gt;
Resume versioning&lt;br&gt;
Analysis history&lt;br&gt;
Interview preparation&lt;br&gt;
Multiple AI providers&lt;br&gt;
Dashboard functionality&lt;/p&gt;

&lt;p&gt;The project is designed as a source-code foundation that developers can customize and extend, rather than as a hosted SaaS product.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What I'd Improve Next&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are several areas I'd like to explore further.&lt;/p&gt;

&lt;p&gt;Better semantic matching&lt;/p&gt;

&lt;p&gt;Moving beyond basic keyword matching toward deeper semantic comparison between resume experience and job requirements.&lt;/p&gt;

&lt;p&gt;Better context selection&lt;/p&gt;

&lt;p&gt;Determining which parts of a resume and job description actually need to be sent to the model.&lt;/p&gt;

&lt;p&gt;Model evaluation&lt;/p&gt;

&lt;p&gt;Creating a consistent way to compare different models and prompts for resume-analysis tasks.&lt;/p&gt;

&lt;p&gt;More provider flexibility&lt;/p&gt;

&lt;p&gt;Making it easier to switch between cloud-based and locally hosted models.&lt;/p&gt;

&lt;p&gt;More career workflows&lt;/p&gt;

&lt;p&gt;Expanding the system beyond resume analysis into additional parts of the job-search workflow.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;Building ResumeIQ changed how I think about AI applications.&lt;/p&gt;

&lt;p&gt;The interesting part isn't:&lt;/p&gt;

&lt;p&gt;Resume → LLM → Score&lt;/p&gt;

&lt;p&gt;It's the system around the model:&lt;/p&gt;

&lt;p&gt;Structured Analysis&lt;br&gt;
       +&lt;br&gt;
Matching&lt;br&gt;
       +&lt;br&gt;
AI Reasoning&lt;br&gt;
       +&lt;br&gt;
Actionable Recommendations&lt;br&gt;
       +&lt;br&gt;
Resume Improvement&lt;/p&gt;

&lt;p&gt;AI becomes much more useful when it is combined with application logic instead of being treated as the entire application.&lt;/p&gt;

&lt;p&gt;For me, the combination of:&lt;/p&gt;

&lt;p&gt;Java + Spring Boot + AI + document processing + matching + real-world automation&lt;/p&gt;

&lt;p&gt;is what makes this project interesting from a backend-engineering perspective.&lt;/p&gt;

&lt;p&gt;Source Code&lt;/p&gt;

&lt;p&gt;If you're building a resume platform, career SaaS, ATS tool, or experimenting with AI-powered career applications, I made the complete ResumeIQ AI source code available as a customizable Spring Boot foundation.&lt;/p&gt;

&lt;p&gt;ResumeIQ AI — AI Resume Analyzer &amp;amp; ATS SaaS Starter&lt;br&gt;
&lt;a href="https://javacoder716.gumroad.com/l/resumeiq-ai" rel="noopener noreferrer"&gt;https://javacoder716.gumroad.com/l/resumeiq-ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>github</category>
      <category>webdev</category>
      <category>java</category>
    </item>
    <item>
      <title>How to Build a Self-Hosted AI Code Review Pipeline with Spring Boot and GitHub Webhooks</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Sat, 26 Sep 2026 10:53:48 +0000</pubDate>
      <link>https://dev.to/sweety717/how-to-build-a-self-hosted-ai-code-review-pipeline-with-spring-boot-and-github-webhooks-9n0</link>
      <guid>https://dev.to/sweety717/how-to-build-a-self-hosted-ai-code-review-pipeline-with-spring-boot-and-github-webhooks-9n0</guid>
      <description>&lt;p&gt;How to Build a Self-Hosted AI Code Review Pipeline with Spring Boot and GitHub Webhooks&lt;/p&gt;

&lt;p&gt;AI-assisted code review is becoming increasingly useful for catching issues before a Pull Request reaches a human reviewer.&lt;/p&gt;

&lt;p&gt;But building an AI code-review workflow isn't simply a matter of sending source code to an LLM.&lt;/p&gt;

&lt;p&gt;A useful system needs to handle several pieces:&lt;/p&gt;

&lt;p&gt;GitHub Pull Requests&lt;br&gt;
Webhooks&lt;br&gt;
GitHub API integration&lt;br&gt;
Diff extraction&lt;br&gt;
AI provider integration&lt;br&gt;
Structured AI responses&lt;br&gt;
Finding categorization&lt;br&gt;
Risk and quality assessment&lt;br&gt;
Review history&lt;br&gt;
Automated GitHub comments&lt;/p&gt;

&lt;p&gt;In this article, I'll walk through a practical architecture for building such a system with Java, Spring Boot and GitHub webhooks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The basic architecture&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The overall workflow can look like this:&lt;/p&gt;

&lt;p&gt;GitHub Pull Request&lt;br&gt;
        ↓&lt;br&gt;
GitHub Webhook&lt;br&gt;
        ↓&lt;br&gt;
Spring Boot Application&lt;br&gt;
        ↓&lt;br&gt;
Fetch PR Changes&lt;br&gt;
        ↓&lt;br&gt;
AI Analysis&lt;br&gt;
        ↓&lt;br&gt;
Structured Findings&lt;br&gt;
        ↓&lt;br&gt;
Quality / Risk Assessment&lt;br&gt;
        ↓&lt;br&gt;
GitHub Review Comment&lt;/p&gt;

&lt;p&gt;The important idea is that the AI model isn't directly responsible for the entire workflow.&lt;/p&gt;

&lt;p&gt;Spring Boot acts as the orchestration layer.&lt;/p&gt;

&lt;p&gt;It receives the GitHub event, retrieves the relevant changes, prepares the AI request, processes the response, stores the review result and optionally sends the findings back to GitHub.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receiving GitHub Pull Request events&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub webhooks allow an external application to receive events when something happens in a repository.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Pull Request opened&lt;br&gt;
Pull Request updated&lt;br&gt;
Pull Request synchronized&lt;/p&gt;

&lt;p&gt;A Spring Boot endpoint can receive these events.&lt;/p&gt;

&lt;p&gt;@RestController&lt;br&gt;
@RequestMapping("/webhooks/github")&lt;br&gt;
public class GitHubWebhookController {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping
public ResponseEntity&amp;lt;Void&amp;gt; handleWebhook(
        @RequestBody String payload) {

    // Validate webhook
    // Parse event
    // Trigger review workflow

    return ResponseEntity.ok().build();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;In a real implementation, the webhook should also validate the GitHub signature before processing the request.&lt;/p&gt;

&lt;p&gt;This prevents arbitrary callers from pretending to be GitHub.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't send the entire repository to the AI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the most important design decisions is deciding what the model actually receives.&lt;/p&gt;

&lt;p&gt;For a Pull Request review, sending the entire repository can be:&lt;/p&gt;

&lt;p&gt;expensive&lt;br&gt;
slow&lt;br&gt;
unnecessary&lt;br&gt;
difficult to fit into the model's context window&lt;/p&gt;

&lt;p&gt;Instead, retrieve the Pull Request changes.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Repository&lt;br&gt;
     ↓&lt;br&gt;
Pull Request&lt;br&gt;
     ↓&lt;br&gt;
Changed files&lt;br&gt;
     ↓&lt;br&gt;
Diff&lt;br&gt;
     ↓&lt;br&gt;
Relevant code&lt;br&gt;
     ↓&lt;br&gt;
AI&lt;/p&gt;

&lt;p&gt;The GitHub API can be used to retrieve the files and changes associated with the Pull Request.&lt;/p&gt;

&lt;p&gt;The review service can then construct an analysis request from those changes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Separate GitHub integration from AI integration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where the architecture becomes important.&lt;/p&gt;

&lt;p&gt;I would avoid putting GitHub API calls and AI provider calls inside the same service.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;p&gt;GitHubWebhookController&lt;br&gt;
          ↓&lt;br&gt;
PullRequestReviewService&lt;br&gt;
       ↙       ↘&lt;br&gt;
GitHubService   AIReviewService&lt;br&gt;
                   ↓&lt;br&gt;
              AI Provider&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;public interface AIReviewService {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReviewResult review(String codeChanges);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;The rest of the application doesn't need to know whether the request is going to OpenAI, Gemini or a locally running Ollama model.&lt;/p&gt;

&lt;p&gt;That's particularly useful if you want the provider to be configurable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Supporting multiple AI providers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A code-review tool shouldn't necessarily be locked to one AI provider.&lt;/p&gt;

&lt;p&gt;A configuration-driven approach can look like:&lt;/p&gt;

&lt;p&gt;ai.provider=openai&lt;br&gt;
ai.model=gpt-model&lt;/p&gt;

&lt;p&gt;And another environment could use:&lt;/p&gt;

&lt;p&gt;ai.provider=gemini&lt;br&gt;
ai.model=gemini-model&lt;/p&gt;

&lt;p&gt;Or a local provider:&lt;/p&gt;

&lt;p&gt;ai.provider=ollama&lt;br&gt;
ai.model=local-model&lt;/p&gt;

&lt;p&gt;The application logic should remain the same.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            AIReviewService
                   |
          Provider Selection
          /       |       \
     OpenAI     Gemini    Ollama
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This separation also makes it easier to test the review workflow independently from a particular provider.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask the AI for structured output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another important part of an AI code-review system is the response format.&lt;/p&gt;

&lt;p&gt;A free-form response such as:&lt;/p&gt;

&lt;p&gt;"There might be a security problem here..."&lt;/p&gt;

&lt;p&gt;is difficult for an application to process reliably.&lt;/p&gt;

&lt;p&gt;Instead, define a structured review result.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "qualityScore": 8,&lt;br&gt;
  "riskLevel": "LOW",&lt;br&gt;
  "confidence": 0.90,&lt;br&gt;
  "findings": [&lt;br&gt;
    {&lt;br&gt;
      "category": "SECURITY",&lt;br&gt;
      "severity": "MEDIUM",&lt;br&gt;
      "title": "Potential credential handling issue",&lt;br&gt;
      "description": "Review how the credential is overridden.",&lt;br&gt;
      "recommendation": "Validate and restrict credential updates."&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Now the application can use the response programmatically.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;AI response&lt;br&gt;
     ↓&lt;br&gt;
Parse JSON&lt;br&gt;
     ↓&lt;br&gt;
Validate structure&lt;br&gt;
     ↓&lt;br&gt;
Store review&lt;br&gt;
     ↓&lt;br&gt;
Display dashboard&lt;br&gt;
     ↓&lt;br&gt;
Generate GitHub comment&lt;/p&gt;

&lt;p&gt;This is much more useful than treating the model response as plain text.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Categorizing findings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The review can classify problems into different categories.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;🐛 Bugs&lt;/p&gt;

&lt;p&gt;Potential logical errors or unexpected behavior.&lt;/p&gt;

&lt;p&gt;🔐 Security&lt;/p&gt;

&lt;p&gt;Potential security weaknesses, credential handling problems, authentication issues or unsafe input handling.&lt;/p&gt;

&lt;p&gt;⚡ Performance&lt;/p&gt;

&lt;p&gt;Potential inefficient operations, unnecessary database calls or expensive processing.&lt;/p&gt;

&lt;p&gt;✅ Best Practices&lt;/p&gt;

&lt;p&gt;Maintainability, readability and implementation practices that could be improved.&lt;/p&gt;

&lt;p&gt;A finding can also have a severity:&lt;/p&gt;

&lt;p&gt;CRITICAL&lt;br&gt;
HIGH&lt;br&gt;
MEDIUM&lt;br&gt;
LOW&lt;br&gt;
INFO&lt;/p&gt;

&lt;p&gt;This allows developers to focus on the most important findings first.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding a quality and risk assessment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Individual findings are useful, but a summary can make the review easier to understand.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Quality Score: 8/10&lt;/p&gt;

&lt;p&gt;Risk: LOW&lt;/p&gt;

&lt;p&gt;AI Confidence: 90%&lt;/p&gt;

&lt;p&gt;Critical Issues: 0&lt;br&gt;
Suggestions: 2&lt;/p&gt;

&lt;p&gt;The important thing is to make these scores supporting signals, not replacements for human review.&lt;/p&gt;

&lt;p&gt;An AI reviewer can help surface potential problems, but developers still need to inspect the actual code and decide whether a change should be merged.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Posting the review back to GitHub&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the analysis is complete, the application can use the GitHub API to post the review.&lt;/p&gt;

&lt;p&gt;The workflow becomes:&lt;/p&gt;

&lt;p&gt;PR opened&lt;br&gt;
    ↓&lt;br&gt;
Webhook&lt;br&gt;
    ↓&lt;br&gt;
Fetch diff&lt;br&gt;
    ↓&lt;br&gt;
AI analysis&lt;br&gt;
    ↓&lt;br&gt;
Structured result&lt;br&gt;
    ↓&lt;br&gt;
Save review&lt;br&gt;
    ↓&lt;br&gt;
GitHub review/comment&lt;/p&gt;

&lt;p&gt;This makes the AI reviewer part of the existing developer workflow instead of forcing developers to open another application every time.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manual reviews are useful too&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Webhooks are great for automation, but a dashboard can provide a manual review option.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Repository&lt;br&gt;
Pull Request&lt;br&gt;
     ↓&lt;br&gt;
[ Review PR ]&lt;br&gt;
     ↓&lt;br&gt;
AI Analysis&lt;/p&gt;

&lt;p&gt;This is useful when developers want to review a Pull Request on demand without waiting for another webhook event.&lt;/p&gt;

&lt;p&gt;It also gives you a good place to expose review history.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Store review history&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If reviews are persisted, the application can provide historical information such as:&lt;/p&gt;

&lt;p&gt;PR #42&lt;br&gt;
Quality: 8/10&lt;br&gt;
Risk: LOW&lt;br&gt;
Critical Issues: 0&lt;br&gt;
Suggestions: 2&lt;br&gt;
Reviewed: Sep 26&lt;/p&gt;

&lt;p&gt;Over time, this can become more useful than a single AI response.&lt;/p&gt;

&lt;p&gt;You can start identifying trends such as:&lt;/p&gt;

&lt;p&gt;Review History&lt;/p&gt;

&lt;p&gt;PR #38 → 6/10&lt;br&gt;
PR #39 → 7/10&lt;br&gt;
PR #40 → 7/10&lt;br&gt;
PR #41 → 8/10&lt;br&gt;
PR #42 → 8/10&lt;/p&gt;

&lt;p&gt;This gives developers another way to understand how their code is evolving.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Security considerations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A self-hosted implementation still needs careful handling of credentials.&lt;/p&gt;

&lt;p&gt;Typical sensitive values include:&lt;/p&gt;

&lt;p&gt;GitHub Personal Access Token&lt;br&gt;
GitHub Webhook Secret&lt;br&gt;
AI Provider API Key&lt;br&gt;
Database Credentials&lt;/p&gt;

&lt;p&gt;These shouldn't be hardcoded in source code.&lt;/p&gt;

&lt;p&gt;Use environment variables or an appropriate secret-management mechanism.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;github.token=${GITHUB_TOKEN}&lt;br&gt;
github.webhook-secret=${GITHUB_WEBHOOK_SECRET}&lt;/p&gt;

&lt;p&gt;ai.api-key=${AI_API_KEY}&lt;/p&gt;

&lt;p&gt;The application should also apply appropriate permissions to GitHub tokens rather than requesting more access than necessary.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why self-host the reviewer?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are situations where developers may want more control over the review infrastructure.&lt;/p&gt;

&lt;p&gt;With a self-hosted architecture:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   ↓&lt;br&gt;
Your infrastructure&lt;br&gt;
   ↓&lt;br&gt;
Your AI provider&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   ↓&lt;br&gt;
Third-party SaaS&lt;br&gt;
   ↓&lt;br&gt;
AI provider&lt;/p&gt;

&lt;p&gt;The exact privacy and compliance benefits depend on how the system and AI provider are configured, but self-hosting gives the developer more control over where the application, credentials and review workflow operate.&lt;/p&gt;

&lt;p&gt;It also makes customization much easier.&lt;/p&gt;

&lt;p&gt;You can modify:&lt;/p&gt;

&lt;p&gt;review rules&lt;br&gt;
prompts&lt;br&gt;
finding categories&lt;br&gt;
scoring&lt;br&gt;
dashboard&lt;br&gt;
AI provider&lt;br&gt;
GitHub workflow&lt;br&gt;
storage&lt;br&gt;
authentication&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The complete workflow&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Putting everything together:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             GitHub Pull Request
                     │
                     ▼
              GitHub Webhook
                     │
                     ▼
          Spring Boot Application
                     │
                     ▼
            Fetch PR Changes
                     │
                     ▼
              Prepare Prompt
                     │
                     ▼
             AI Provider Layer
              /      |       \
         OpenAI    Gemini    Ollama
              \      |       /
                     ▼
            Structured Review
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
        Bugs     Security   Performance
          │          │          │
          └──────────┼──────────┘
                     ▼
             Quality / Risk
                Assessment
                     │
          ┌──────────┴──────────┐
          ▼                     ▼
   Review Dashboard       GitHub Comment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The key architectural principle is separation of concerns.&lt;/p&gt;

&lt;p&gt;GitHub integration shouldn't know how an AI provider works.&lt;/p&gt;

&lt;p&gt;The AI layer shouldn't know how GitHub authentication works.&lt;/p&gt;

&lt;p&gt;And the business layer shouldn't need to change simply because you switch from one AI provider to another.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Building CodeGuard AI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I built CodeGuard AI around this type of workflow.&lt;/p&gt;

&lt;p&gt;It's a self-hosted GitHub AI code-review application built with:&lt;/p&gt;

&lt;p&gt;Java 17+&lt;br&gt;
Spring Boot&lt;br&gt;
Spring Security&lt;br&gt;
GitHub REST API&lt;br&gt;
AI provider integrations&lt;br&gt;
REST APIs&lt;br&gt;
HTML/CSS/Vanilla JavaScript&lt;br&gt;
Maven&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;p&gt;AI-powered Pull Request reviews&lt;br&gt;
Bug detection&lt;br&gt;
Security analysis&lt;br&gt;
Performance analysis&lt;br&gt;
Best-practice checks&lt;br&gt;
Quality and risk assessment&lt;br&gt;
AI confidence scoring&lt;br&gt;
Automatic GitHub review comments&lt;br&gt;
GitHub webhooks&lt;br&gt;
Manual PR reviews&lt;br&gt;
Review history&lt;br&gt;
Review trends&lt;br&gt;
Markdown/PDF export&lt;br&gt;
OpenAI&lt;br&gt;
Google Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;The goal was to build a customizable source-code foundation rather than another closed review service.&lt;/p&gt;

&lt;p&gt;Final thoughts&lt;/p&gt;

&lt;p&gt;An AI code reviewer is more than an LLM prompt.&lt;/p&gt;

&lt;p&gt;The interesting engineering work is around the LLM:&lt;/p&gt;

&lt;p&gt;GitHub events → code extraction → provider abstraction → structured AI output → validation → persistence → developer-facing results → GitHub integration.&lt;/p&gt;

&lt;p&gt;That's where Spring Boot fits particularly well.&lt;/p&gt;

&lt;p&gt;If you're building an AI developer tool, keeping the AI layer modular and the surrounding application deterministic can make the system much easier to extend and maintain.&lt;/p&gt;

&lt;p&gt;About the project&lt;/p&gt;

&lt;p&gt;CodeGuard AI is available as a self-hosted Spring Boot source-code project for developers who want to build and customize their own AI-powered GitHub code-review workflow.&lt;/p&gt;

&lt;p&gt;Build. Customize. Self-host.&lt;br&gt;
Get CodeGuard AI → &lt;a href="https://javacoder716.gumroad.com/l/codeguard-ai" rel="noopener noreferrer"&gt;https://javacoder716.gumroad.com/l/codeguard-ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>github</category>
      <category>java</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Building a Multi-Provider AI Resume Analyzer in Spring Boot (and why I didn't lock it to one AI provider)</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Thu, 24 Sep 2026 05:58:00 +0000</pubDate>
      <link>https://dev.to/sweety717/building-a-multi-provider-ai-resume-analyzer-in-spring-boot-and-why-i-didnt-lock-it-to-one-ai-2pkj</link>
      <guid>https://dev.to/sweety717/building-a-multi-provider-ai-resume-analyzer-in-spring-boot-and-why-i-didnt-lock-it-to-one-ai-2pkj</guid>
      <description>&lt;p&gt;I've been building AI-powered developer tools solo for the past few months, and I want to share some of the architecture decisions behind my latest one: ResumeIQ AI, a resume analyzer and interview prep tool.&lt;/p&gt;

&lt;p&gt;The core problem I wanted to solve&lt;/p&gt;

&lt;p&gt;Most AI resume tools are SaaS products tied to one AI provider, usually OpenAI. That means:&lt;/p&gt;

&lt;p&gt;You're locked into their pricing&lt;br&gt;
If you're privacy-conscious, your resume data goes through a service you don't control&lt;br&gt;
You can't swap providers if a cheaper or better one comes along&lt;/p&gt;

&lt;p&gt;I wanted something a developer could self-host and plug in their own choice of provider — OpenAI, Gemini, or a local Ollama instance.&lt;/p&gt;

&lt;p&gt;Design decision: config-only provider switching&lt;/p&gt;

&lt;p&gt;Instead of hardcoding model names anywhere in business logic, every model name lives in application.properties. Swapping from gpt-4 to gemini-1.5-pro to a local Ollama model is a config change, not a code change. This also made it trivial to add new providers later without touching the analysis logic.&lt;/p&gt;

&lt;p&gt;A subtle bug this caught: forcing JSON mode where it doesn't belong&lt;/p&gt;

&lt;p&gt;Some endpoints need structured JSON output (resume scoring breakdowns), others need free-text generation (interview prep questions, feedback). Early on I had JSON mode forced globally on the AI provider interface — which silently broke the free-text responses, since forcing JSON mode on a prompt that wants prose either truncates or garbles the output.&lt;/p&gt;

&lt;p&gt;Fix was a jsonMode boolean on the provider interface itself, set per-call rather than globally. Small change, but it's the kind of thing that's invisible until you're staring at broken output wondering why your prompt is fine but the response isn't.&lt;/p&gt;

&lt;p&gt;What's actually in it&lt;/p&gt;

&lt;p&gt;Full auth system with user history and resume versioning&lt;br&gt;
Side-by-side resume comparison across versions&lt;br&gt;
AI-generated interview prep tied to the resume + target role&lt;br&gt;
Freemium gating built in, so it's ready to sell as-is&lt;br&gt;
Admin panel for managing users/tiers&lt;/p&gt;

&lt;p&gt;Where it's at now&lt;/p&gt;

&lt;p&gt;It's live and for sale as source code on Gumroad — self-hosted, one-time purchase, bring your own API key. &lt;a href="https://javacoder716.gumroad.com/l/resumeiq-ai" rel="noopener noreferrer"&gt;https://javacoder716.gumroad.com/l/resumeiq-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still very early — this is my first real push on distribution after building solo for a while. If you've built anything similar or have thoughts on the provider-switching approach, I'd love to hear it in the comments.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>ai</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>How to Handle External API Failures in Spring Boot: Retries, Timeouts and Resilience</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Fri, 18 Sep 2026 16:30:49 +0000</pubDate>
      <link>https://dev.to/sweety717/how-to-handle-external-api-failures-in-spring-boot-retries-timeouts-and-resilience-3g7m</link>
      <guid>https://dev.to/sweety717/how-to-handle-external-api-failures-in-spring-boot-retries-timeouts-and-resilience-3g7m</guid>
      <description>&lt;p&gt;TL;DR: When a Spring Boot application depends on an external API, failures are inevitable. In this article, I'll walk through how to think about timeouts, retries, backoff, rate limits, and fallback handling when building a resilient backend.&lt;/p&gt;

&lt;p&gt;When I was building an AI-powered GitHub Pull Request reviewer, one thing became very clear:&lt;/p&gt;

&lt;p&gt;The AI API is not under my control.&lt;/p&gt;

&lt;p&gt;My application can be perfectly healthy, but an external service can still:&lt;/p&gt;

&lt;p&gt;Take too long to respond&lt;br&gt;
Return a 500&lt;br&gt;
Temporarily become unavailable&lt;br&gt;
Reject requests because of rate limits&lt;br&gt;
Return an unexpected response&lt;br&gt;
Have a network failure&lt;/p&gt;

&lt;p&gt;So this raises an important backend question:&lt;/p&gt;

&lt;p&gt;What should my Spring Boot application do when an external API fails?&lt;/p&gt;

&lt;p&gt;Simply calling the API and returning the exception to the user isn't enough.&lt;/p&gt;

&lt;p&gt;Let's look at a better approach.&lt;/p&gt;

&lt;p&gt;The Problem&lt;/p&gt;

&lt;p&gt;Imagine this simple flow:&lt;/p&gt;

&lt;p&gt;Client&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
External API&lt;br&gt;
   |&lt;br&gt;
   X&lt;br&gt;
  Failure&lt;/p&gt;

&lt;p&gt;If the external API fails, our application needs to decide:&lt;/p&gt;

&lt;p&gt;Should we retry?&lt;/p&gt;

&lt;p&gt;How many times?&lt;/p&gt;

&lt;p&gt;How long should we wait?&lt;/p&gt;

&lt;p&gt;What if the API is still unavailable?&lt;/p&gt;

&lt;p&gt;What response should our client receive?&lt;/p&gt;

&lt;p&gt;These are resilience questions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Always Set a Timeout&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the first mistakes that can happen with external API calls is forgetting about timeouts.&lt;/p&gt;

&lt;p&gt;Imagine:&lt;/p&gt;

&lt;p&gt;Spring Boot&lt;br&gt;
     |&lt;br&gt;
     | Request&lt;br&gt;
     v&lt;br&gt;
External API&lt;br&gt;
     |&lt;br&gt;
     | .............&lt;br&gt;
     | .............&lt;br&gt;
     | .............&lt;/p&gt;

&lt;p&gt;If the external service doesn't respond, you don't want your application waiting indefinitely.&lt;/p&gt;

&lt;p&gt;A timeout gives your application a clear boundary.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Request&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
External API&lt;br&gt;
   |&lt;br&gt;
   |---- Response within timeout → Continue&lt;br&gt;
   |&lt;br&gt;
   |---- Timeout → Handle failure&lt;/p&gt;

&lt;p&gt;The exact timeout depends on the API and the operation.&lt;/p&gt;

&lt;p&gt;A request that normally takes 200 ms shouldn't necessarily have a 5-minute timeout.&lt;/p&gt;

&lt;p&gt;The important idea is:&lt;/p&gt;

&lt;p&gt;Every external network call should have an intentional timeout strategy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Should We Retry?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not every failure should be retried.&lt;/p&gt;

&lt;p&gt;For example, suppose the external API returns:&lt;/p&gt;

&lt;p&gt;500 Internal Server Error&lt;/p&gt;

&lt;p&gt;A retry might make sense because the failure could be temporary.&lt;/p&gt;

&lt;p&gt;But imagine the API returns:&lt;/p&gt;

&lt;p&gt;400 Bad Request&lt;/p&gt;

&lt;p&gt;Retrying the exact same request probably won't fix anything.&lt;/p&gt;

&lt;p&gt;The request itself is invalid.&lt;/p&gt;

&lt;p&gt;So we need to distinguish between failures.&lt;/p&gt;

&lt;p&gt;Potentially retryable&lt;br&gt;
Connection failure&lt;br&gt;
Timeout&lt;br&gt;
Temporary 5xx response&lt;br&gt;
429 Too Many Requests&lt;br&gt;
Usually not retryable&lt;br&gt;
400 Bad Request&lt;br&gt;
401 Unauthorized&lt;br&gt;
403 Forbidden&lt;br&gt;
404 Not Found&lt;br&gt;
Invalid request data&lt;/p&gt;

&lt;p&gt;The exact retry policy depends on the API and the operation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't Retry Immediately&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suppose an external API is temporarily unavailable.&lt;/p&gt;

&lt;p&gt;A naive implementation might do:&lt;/p&gt;

&lt;p&gt;Request&lt;br&gt;
   ↓&lt;br&gt;
Failure&lt;br&gt;
   ↓&lt;br&gt;
Retry immediately&lt;br&gt;
   ↓&lt;br&gt;
Failure&lt;br&gt;
   ↓&lt;br&gt;
Retry immediately&lt;br&gt;
   ↓&lt;br&gt;
Failure&lt;/p&gt;

&lt;p&gt;This can make the situation worse.&lt;/p&gt;

&lt;p&gt;Instead, we can introduce a delay between attempts.&lt;/p&gt;

&lt;p&gt;This is called backoff.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Attempt 1 → Failure&lt;br&gt;
             ↓&lt;br&gt;
          Wait 1 sec&lt;br&gt;
             ↓&lt;br&gt;
Attempt 2 → Failure&lt;br&gt;
             ↓&lt;br&gt;
          Wait 2 sec&lt;br&gt;
             ↓&lt;br&gt;
Attempt 3 → Failure&lt;/p&gt;

&lt;p&gt;A common approach is exponential backoff, where the delay increases after each failed attempt.&lt;/p&gt;

&lt;p&gt;In production systems, adding some jitter to the delay can also help prevent many clients from retrying at exactly the same time.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Example Using Spring Retry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One way to implement retries in a Spring application is with Spring Retry.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;@Retryable(&lt;br&gt;
    retryFor = ExternalApiException.class,&lt;br&gt;
    maxAttempts = 3,&lt;br&gt;
    backoff = @Backoff(delay = 1000)&lt;br&gt;
)&lt;br&gt;
public String callExternalApi() {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return externalApiClient.call();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;The basic idea is:&lt;/p&gt;

&lt;p&gt;Maximum attempts = 3&lt;br&gt;
Initial delay = 1000 ms&lt;/p&gt;

&lt;p&gt;So if the call fails with the configured exception, the application can attempt the operation again according to the retry configuration.&lt;/p&gt;

&lt;p&gt;But there's an important question:&lt;/p&gt;

&lt;p&gt;What happens after all retry attempts fail?&lt;/p&gt;

&lt;p&gt;That's where fallback handling becomes useful.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fallback Handling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suppose all retry attempts fail:&lt;/p&gt;

&lt;p&gt;Attempt 1 → Failure&lt;br&gt;
Attempt 2 → Failure&lt;br&gt;
Attempt 3 → Failure&lt;/p&gt;

&lt;p&gt;At this point, continuing to retry isn't useful.&lt;/p&gt;

&lt;p&gt;The application needs to fail gracefully.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Client&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
External API&lt;br&gt;
   |&lt;br&gt;
   X&lt;br&gt;
Failure&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Retry&lt;br&gt;
   |&lt;br&gt;
   X&lt;br&gt;
Failure&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Fallback / Error Response&lt;/p&gt;

&lt;p&gt;Depending on the application, the fallback could:&lt;/p&gt;

&lt;p&gt;Return a meaningful error&lt;br&gt;
Use cached data&lt;br&gt;
Queue the request for later processing&lt;br&gt;
Mark the operation as pending&lt;br&gt;
Use an alternative service&lt;/p&gt;

&lt;p&gt;The correct fallback depends heavily on the business requirement.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handling Rate Limits&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Another interesting failure scenario is:&lt;/p&gt;

&lt;p&gt;429 Too Many Requests&lt;/p&gt;

&lt;p&gt;This usually means the client has exceeded the API's allowed request rate.&lt;/p&gt;

&lt;p&gt;Immediately sending more requests isn't a good strategy.&lt;/p&gt;

&lt;p&gt;Instead, the application should respect the API's rate-limit behavior.&lt;/p&gt;

&lt;p&gt;Some APIs provide information such as:&lt;/p&gt;

&lt;p&gt;Retry-After&lt;/p&gt;

&lt;p&gt;which can indicate when the client should try again.&lt;/p&gt;

&lt;p&gt;This is particularly important when building applications that make frequent calls to third-party APIs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What About the AI Code Reviewer?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This became particularly relevant to the AI code reviewer I was building.&lt;/p&gt;

&lt;p&gt;The workflow looks roughly like:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Webhook&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Get PR Diff&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
AI API&lt;br&gt;
   |&lt;br&gt;
   X&lt;br&gt;
Possible failure&lt;/p&gt;

&lt;p&gt;What happens if the AI service doesn't respond?&lt;/p&gt;

&lt;p&gt;I don't want the entire application to simply crash.&lt;/p&gt;

&lt;p&gt;A better design would be something like:&lt;/p&gt;

&lt;p&gt;GitHub Webhook&lt;br&gt;
       |&lt;br&gt;
       v&lt;br&gt;
Spring Boot&lt;br&gt;
       |&lt;br&gt;
       v&lt;br&gt;
Create Review Job&lt;br&gt;
       |&lt;br&gt;
       v&lt;br&gt;
Process Review&lt;br&gt;
       |&lt;br&gt;
       v&lt;br&gt;
AI API&lt;br&gt;
       |&lt;br&gt;
   +---+---+&lt;br&gt;
   |       |&lt;br&gt;
Success   Failure&lt;br&gt;
   |       |&lt;br&gt;
   v       v&lt;br&gt;
Review   Retry&lt;br&gt;
           |&lt;br&gt;
           v&lt;br&gt;
        Backoff&lt;br&gt;
           |&lt;br&gt;
           v&lt;br&gt;
       Try Again&lt;br&gt;
           |&lt;br&gt;
           v&lt;br&gt;
    Still failing?&lt;br&gt;
       /       \&lt;br&gt;
     Yes        No&lt;br&gt;
      |          |&lt;br&gt;
      v          v&lt;br&gt;
   Mark       Review&lt;br&gt;
   Failed&lt;/p&gt;

&lt;p&gt;This is where resilience becomes more than just adding a retry annotation.&lt;/p&gt;

&lt;p&gt;It becomes an architectural decision.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Synchronous vs Asynchronous Processing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suppose the GitHub webhook directly waits for the AI response:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Webhook&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
AI API&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Response&lt;/p&gt;

&lt;p&gt;The webhook request remains open while the AI request is being processed.&lt;/p&gt;

&lt;p&gt;A more scalable approach could be:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Webhook&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Queue&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Worker&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
AI API&lt;/p&gt;

&lt;p&gt;Now the webhook can be acknowledged quickly while the actual review happens asynchronously.&lt;/p&gt;

&lt;p&gt;This also makes it easier to implement:&lt;/p&gt;

&lt;p&gt;Retries&lt;br&gt;
Delayed processing&lt;br&gt;
Failure tracking&lt;br&gt;
Dead-letter queues&lt;br&gt;
Multiple workers&lt;br&gt;
Horizontal scaling&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't Retry Everything&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is probably the most important lesson.&lt;/p&gt;

&lt;p&gt;Adding:&lt;/p&gt;

&lt;p&gt;retry = 5&lt;/p&gt;

&lt;p&gt;doesn't automatically make an application resilient.&lt;/p&gt;

&lt;p&gt;Imagine five application instances all calling the same unavailable API.&lt;/p&gt;

&lt;p&gt;If every instance retries aggressively, we could end up with:&lt;/p&gt;

&lt;p&gt;Application 1 → Retry&lt;br&gt;
Application 2 → Retry&lt;br&gt;
Application 3 → Retry&lt;br&gt;
Application 4 → Retry&lt;br&gt;
Application 5 → Retry&lt;/p&gt;

&lt;p&gt;The external service is already struggling.&lt;/p&gt;

&lt;p&gt;Our retries could make the situation worse.&lt;/p&gt;

&lt;p&gt;This is sometimes called a retry storm.&lt;/p&gt;

&lt;p&gt;That's why retry policies need to consider:&lt;/p&gt;

&lt;p&gt;Which errors are retryable&lt;br&gt;
Maximum attempts&lt;br&gt;
Backoff&lt;br&gt;
Jitter&lt;br&gt;
Rate limits&lt;br&gt;
Request volume&lt;br&gt;
Idempotency&lt;br&gt;
Overall system behavior&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What Is Idempotency and Why Does It Matter?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is another important consideration when implementing retries.&lt;/p&gt;

&lt;p&gt;Suppose we have:&lt;/p&gt;

&lt;p&gt;POST /payments&lt;/p&gt;

&lt;p&gt;and the first request actually succeeds, but the response is lost because of a network problem.&lt;/p&gt;

&lt;p&gt;Our application doesn't know whether the operation succeeded.&lt;/p&gt;

&lt;p&gt;If we blindly retry:&lt;/p&gt;

&lt;p&gt;POST /payments&lt;/p&gt;

&lt;p&gt;we could potentially create the operation twice.&lt;/p&gt;

&lt;p&gt;That's why retrying a request isn't simply a technical decision.&lt;/p&gt;

&lt;p&gt;We also need to understand whether the operation is safe to repeat.&lt;/p&gt;

&lt;p&gt;For operations that can have side effects, idempotency mechanisms may be necessary.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Circuit Breakers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Retries aren't always enough.&lt;/p&gt;

&lt;p&gt;Imagine an external service has been unavailable for several minutes.&lt;/p&gt;

&lt;p&gt;Our application keeps sending requests.&lt;/p&gt;

&lt;p&gt;Each request waits for a timeout.&lt;/p&gt;

&lt;p&gt;Then it retries.&lt;/p&gt;

&lt;p&gt;Then another request does the same thing.&lt;/p&gt;

&lt;p&gt;We're wasting resources while the dependency is clearly unhealthy.&lt;/p&gt;

&lt;p&gt;This is where a circuit breaker can help.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         Normal
           |
           v
    +--------------+
    |    CLOSED    |
    +--------------+
           |
    Too many failures
           |
           v
    +--------------+
    |     OPEN     |
    +--------------+
           |
    Wait / test
           |
           v
    +--------------+
    | HALF-OPEN    |
    +--------------+
      /          \
 Success        Failure
   |               |
   v               v
CLOSED            OPEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The circuit breaker temporarily stops calls to an unhealthy dependency.&lt;/p&gt;

&lt;p&gt;This prevents our application from continuously hammering an unavailable service.&lt;/p&gt;

&lt;p&gt;Libraries such as Resilience4j can be used to implement patterns like:&lt;/p&gt;

&lt;p&gt;Retry&lt;br&gt;
Circuit breaker&lt;br&gt;
Rate limiter&lt;br&gt;
Bulkhead&lt;br&gt;
Time limiter&lt;br&gt;
A Resilient External API Flow&lt;/p&gt;

&lt;p&gt;Putting the concepts together:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Client
                |
                v
          Spring Boot
                |
                v
         External API
                |
      +---------+---------+
      |                   |
   Success              Failure
      |                   |
      v                   v
   Continue            Is it
                       retryable?
                       /      \
                     Yes       No
                      |         |
                      v         v
                   Backoff    Fail
                      |
                      v
                    Retry
                      |
                Still failing?
                   /      \
                 Yes       No
                  |         |
                  v         v
               Fallback   Success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the kind of flow I now think about whenever my backend depends on an external service.&lt;/p&gt;

&lt;p&gt;What I Learned&lt;/p&gt;

&lt;p&gt;Before working on projects involving external APIs, it was easy to think:&lt;/p&gt;

&lt;p&gt;"I'll just call the API and handle the response."&lt;/p&gt;

&lt;p&gt;But real backend systems aren't that simple.&lt;/p&gt;

&lt;p&gt;External dependencies can fail.&lt;/p&gt;

&lt;p&gt;Networks can fail.&lt;/p&gt;

&lt;p&gt;Services can become slow.&lt;/p&gt;

&lt;p&gt;Rate limits can be reached.&lt;/p&gt;

&lt;p&gt;Responses can change.&lt;/p&gt;

&lt;p&gt;And your application needs to behave predictably when those things happen.&lt;/p&gt;

&lt;p&gt;The goal isn't to make failures impossible.&lt;/p&gt;

&lt;p&gt;The goal is to make failures manageable.&lt;/p&gt;

&lt;p&gt;My Spring Boot Resilience Checklist&lt;/p&gt;

&lt;p&gt;When I integrate an external API now, these are some of the questions I ask:&lt;/p&gt;

&lt;p&gt;✓ Do I have a connection timeout?&lt;br&gt;
✓ Do I have a response timeout?&lt;br&gt;
✓ Which failures are retryable?&lt;br&gt;
✓ How many retries should I allow?&lt;br&gt;
✓ Do I need exponential backoff?&lt;br&gt;
✓ Should I add jitter?&lt;br&gt;
✓ How do I handle 429 responses?&lt;br&gt;
✓ Is the operation safe to retry?&lt;br&gt;
✓ Do I need a circuit breaker?&lt;br&gt;
✓ Should this operation be asynchronous?&lt;br&gt;
✓ What happens after all retries fail?&lt;br&gt;
✓ How will I monitor failures?&lt;/p&gt;

&lt;p&gt;Thinking about these questions early can prevent a lot of problems later.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;While building my AI-powered GitHub Pull Request reviewer, I initially focused mostly on the AI part.&lt;/p&gt;

&lt;p&gt;But the more I thought about the architecture, the more I realized:&lt;/p&gt;

&lt;p&gt;The AI call is just another external dependency.&lt;/p&gt;

&lt;p&gt;The same principles apply whether you're calling:&lt;/p&gt;

&lt;p&gt;An AI API&lt;br&gt;
A payment gateway&lt;br&gt;
A notification service&lt;br&gt;
A database service&lt;br&gt;
A third-party REST API&lt;/p&gt;

&lt;p&gt;Your application needs to assume that external dependencies can fail.&lt;/p&gt;

&lt;p&gt;That's one of the differences between a backend that works in a demo and one that is designed to handle real-world conditions.&lt;/p&gt;

&lt;p&gt;What would you add?&lt;/p&gt;

&lt;p&gt;If your Spring Boot application depends heavily on an external API, what resilience strategy do you usually use?&lt;/p&gt;

&lt;p&gt;Retries? Circuit breakers? Async processing? Queues? Caching?&lt;/p&gt;

&lt;p&gt;I'd love to hear how other developers approach this.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>backend</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I Built an AI Code Reviewer for GitHub Pull Requests with Spring Boot</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Tue, 08 Sep 2026 17:04:07 +0000</pubDate>
      <link>https://dev.to/sweety717/how-i-built-an-ai-code-reviewer-for-github-pull-requests-with-spring-boot-la8</link>
      <guid>https://dev.to/sweety717/how-i-built-an-ai-code-reviewer-for-github-pull-requests-with-spring-boot-la8</guid>
      <description>&lt;p&gt;How I Built an AI Code Reviewer for GitHub Pull Requests with Spring Boot&lt;/p&gt;

&lt;p&gt;TL;DR: I built an AI-powered GitHub Pull Request reviewer with Spring Boot that receives GitHub webhooks, fetches code changes, sends relevant context to an AI model, and generates an automated first-pass code review.&lt;/p&gt;

&lt;p&gt;Code reviews are one of those things every development team needs.&lt;/p&gt;

&lt;p&gt;But they're also repetitive.&lt;/p&gt;

&lt;p&gt;A developer opens a Pull Request.&lt;/p&gt;

&lt;p&gt;Someone reviews it.&lt;/p&gt;

&lt;p&gt;They look for bugs, security issues, code quality problems, performance concerns, and possible improvements.&lt;/p&gt;

&lt;p&gt;So I started wondering:&lt;/p&gt;

&lt;p&gt;What if AI could perform the first round of review before a human reviewer even looks at the PR?&lt;/p&gt;

&lt;p&gt;That idea led me to build an AI-powered GitHub Pull Request Code Reviewer using Spring Boot, GitHub APIs, and an AI model.&lt;/p&gt;

&lt;p&gt;The goal wasn't to replace human code reviews.&lt;/p&gt;

&lt;p&gt;It was to automate the boring first pass and give developers useful feedback earlier.&lt;/p&gt;

&lt;p&gt;The Architecture&lt;/p&gt;

&lt;p&gt;The basic workflow looks like this:&lt;/p&gt;

&lt;p&gt;Developer creates Pull Request&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
      GitHub Webhook&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
      Spring Boot API&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
   Fetch Pull Request data&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
      Extract code diff&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
      Build AI prompt&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
       AI API call&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
       Generate review&lt;br&gt;
            |&lt;br&gt;
            v&lt;br&gt;
      Store / return result&lt;/p&gt;

&lt;p&gt;The interesting part wasn't simply calling an AI API.&lt;/p&gt;

&lt;p&gt;The real challenge was connecting multiple systems and making the workflow reliable as a backend service.&lt;/p&gt;

&lt;p&gt;Why Spring Boot?&lt;/p&gt;

&lt;p&gt;I chose Spring Boot because it provides a clean way to build REST APIs and integrate external services.&lt;/p&gt;

&lt;p&gt;The backend is responsible for:&lt;/p&gt;

&lt;p&gt;Receiving GitHub webhook events&lt;br&gt;
Processing Pull Request information&lt;br&gt;
Communicating with GitHub APIs&lt;br&gt;
Extracting code changes&lt;br&gt;
Communicating with the AI service&lt;br&gt;
Handling failures and timeouts&lt;br&gt;
Processing the generated review&lt;/p&gt;

&lt;p&gt;A simplified architecture looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             GitHub
               |
               | Webhook
               v
    +-----------------------+
    |      Spring Boot      |
    |        Backend        |
    +-----------------------+
          |           |
          |           |
          v           v
    GitHub API       AI API
          |           |
          +-----+-----+
                |
                v
          Review Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Step 1: Receiving the GitHub Webhook&lt;/p&gt;

&lt;p&gt;Instead of continuously polling GitHub for new Pull Requests, I wanted GitHub to notify my application whenever something happened.&lt;/p&gt;

&lt;p&gt;For example, when a Pull Request is opened or updated, GitHub can send a webhook request to the Spring Boot application.&lt;/p&gt;

&lt;p&gt;A simplified controller looks like this:&lt;/p&gt;

&lt;p&gt;@RestController&lt;br&gt;
@RequestMapping("/webhook")&lt;br&gt;
public class GithubWebhookController {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping("/pull-request")
public ResponseEntity&amp;lt;String&amp;gt; handlePullRequest(
        @RequestBody String payload) {

    // Process GitHub webhook

    return ResponseEntity.ok("Webhook received");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Of course, a production implementation shouldn't simply accept any incoming request.&lt;/p&gt;

&lt;p&gt;The webhook should be validated, the payload should be parsed properly, and the event type should be handled accordingly.&lt;/p&gt;

&lt;p&gt;This gave me an important reminder when working with external integrations:&lt;/p&gt;

&lt;p&gt;Never blindly trust incoming webhook requests.&lt;/p&gt;

&lt;p&gt;Step 2: Getting Pull Request Details&lt;/p&gt;

&lt;p&gt;Once the webhook is received, the application needs information about the Pull Request.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Repository&lt;br&gt;
Pull Request number&lt;br&gt;
Source branch&lt;br&gt;
Target branch&lt;br&gt;
Author&lt;br&gt;
Changed files&lt;/p&gt;

&lt;p&gt;The backend can then communicate with GitHub's API to retrieve the required information.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;Webhook&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Repository + PR Number&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
GitHub API&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Pull Request Details&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Changed Files / Diff&lt;/p&gt;

&lt;p&gt;This is where the project starts becoming more than a simple CRUD application.&lt;/p&gt;

&lt;p&gt;We're integrating with an external system, transforming its data, and feeding it into another service.&lt;/p&gt;

&lt;p&gt;Step 3: Extracting the Code Changes&lt;/p&gt;

&lt;p&gt;One thing I didn't want to do was send an entire repository to the AI model.&lt;/p&gt;

&lt;p&gt;That would introduce unnecessary context and potentially increase processing cost.&lt;/p&gt;

&lt;p&gt;Instead, the application focuses primarily on the changes introduced by the Pull Request.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;return user.getName();&lt;/li&gt;
&lt;li&gt;return user.getName().trim();&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI doesn't always need the entire application.&lt;/p&gt;

&lt;p&gt;It needs enough relevant context to understand:&lt;/p&gt;

&lt;p&gt;What changed?&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;Could this change introduce a problem?&lt;/p&gt;

&lt;p&gt;This makes the review more focused.&lt;/p&gt;

&lt;p&gt;Step 4: Building the AI Prompt&lt;/p&gt;

&lt;p&gt;This turned out to be one of the most important parts.&lt;/p&gt;

&lt;p&gt;Simply sending:&lt;/p&gt;

&lt;p&gt;Review this code.&lt;/p&gt;

&lt;p&gt;doesn't give the AI enough direction.&lt;/p&gt;

&lt;p&gt;Instead, I give it a specific role and review criteria.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;You are a senior Java code reviewer.&lt;/p&gt;

&lt;p&gt;Review the following Pull Request changes.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bugs&lt;/li&gt;
&lt;li&gt;Security vulnerabilities&lt;/li&gt;
&lt;li&gt;Performance problems&lt;/li&gt;
&lt;li&gt;Exception handling issues&lt;/li&gt;
&lt;li&gt;Code quality problems&lt;/li&gt;
&lt;li&gt;Maintainability issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For every significant issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explain the problem&lt;/li&gt;
&lt;li&gt;Explain why it matters&lt;/li&gt;
&lt;li&gt;Suggest a possible improvement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there are no significant issues, say so clearly.&lt;/p&gt;

&lt;p&gt;Focus only on meaningful issues.&lt;br&gt;
Do not suggest unnecessary changes.&lt;/p&gt;

&lt;p&gt;Pull Request diff:&lt;/p&gt;

&lt;p&gt;[DIFF HERE]&lt;/p&gt;

&lt;p&gt;The important lesson here was:&lt;/p&gt;

&lt;p&gt;The quality of an AI response depends heavily on the quality of the context and instructions you provide.&lt;/p&gt;

&lt;p&gt;Prompting isn't just about asking a question.&lt;/p&gt;

&lt;p&gt;It's about giving the model the right context to reason about.&lt;/p&gt;

&lt;p&gt;Step 5: Calling the AI Service&lt;/p&gt;

&lt;p&gt;From Spring Boot, the application can communicate with an external AI API using an HTTP client.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;public String reviewCode(String codeDiff) {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String prompt = buildPrompt(codeDiff);

// Send prompt to AI service
// Receive generated review
// Return review

return review;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;But the backend responsibility doesn't end with making the API call.&lt;/p&gt;

&lt;p&gt;A real application also needs to think about:&lt;/p&gt;

&lt;p&gt;API failures&lt;br&gt;
Timeouts&lt;br&gt;
Invalid responses&lt;br&gt;
Rate limits&lt;br&gt;
Authentication&lt;br&gt;
Logging&lt;br&gt;
Retry strategies&lt;/p&gt;

&lt;p&gt;This is where the project became more interesting from a backend engineering perspective.&lt;/p&gt;

&lt;p&gt;The Complete Flow&lt;/p&gt;

&lt;p&gt;Putting everything together:&lt;/p&gt;

&lt;p&gt;Developer&lt;br&gt;
    |&lt;br&gt;
    | Creates / updates PR&lt;br&gt;
    v&lt;br&gt;
GitHub&lt;br&gt;
    |&lt;br&gt;
    | Webhook&lt;br&gt;
    v&lt;br&gt;
Spring Boot&lt;br&gt;
    |&lt;br&gt;
    | Validate event&lt;br&gt;
    v&lt;br&gt;
Extract PR information&lt;br&gt;
    |&lt;br&gt;
    | GitHub API&lt;br&gt;
    v&lt;br&gt;
Get changed files / diff&lt;br&gt;
    |&lt;br&gt;
    v&lt;br&gt;
Build AI prompt&lt;br&gt;
    |&lt;br&gt;
    | AI API&lt;br&gt;
    v&lt;br&gt;
Generate review&lt;br&gt;
    |&lt;br&gt;
    v&lt;br&gt;
Process response&lt;br&gt;
    |&lt;br&gt;
    v&lt;br&gt;
Store / return review&lt;/p&gt;

&lt;p&gt;What started as an idea for an AI code reviewer became a backend workflow involving multiple systems.&lt;/p&gt;

&lt;p&gt;The Biggest Thing I Learned&lt;/p&gt;

&lt;p&gt;The most interesting part of this project wasn't actually the AI API.&lt;/p&gt;

&lt;p&gt;It was everything around it.&lt;/p&gt;

&lt;p&gt;AI is only one component of the system.&lt;/p&gt;

&lt;p&gt;A production-style application still needs:&lt;/p&gt;

&lt;p&gt;Clean API design&lt;br&gt;
Authentication&lt;br&gt;
Input validation&lt;br&gt;
Error handling&lt;br&gt;
External API integration&lt;br&gt;
Logging&lt;br&gt;
Security&lt;br&gt;
Rate limiting&lt;br&gt;
Observability&lt;br&gt;
Good database design when persistence is required&lt;/p&gt;

&lt;p&gt;You can have a powerful AI model, but if your backend fails when GitHub sends a webhook, the application isn't very useful.&lt;/p&gt;

&lt;p&gt;AI doesn't remove backend engineering. It makes good backend engineering even more important.&lt;/p&gt;

&lt;p&gt;What I'd Improve Next&lt;/p&gt;

&lt;p&gt;There are several things I'd add if I continued developing this project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asynchronous Processing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI requests can take time.&lt;/p&gt;

&lt;p&gt;Instead of keeping the webhook request waiting, I'd move the review process into an asynchronous workflow.&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Webhook&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Spring Boot&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Queue&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
Worker&lt;br&gt;
   |&lt;br&gt;
   v&lt;br&gt;
AI Review&lt;/p&gt;

&lt;p&gt;This would make the webhook endpoint faster and provide a better foundation for scaling.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Review History&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'd store previous reviews so developers could see:&lt;/p&gt;

&lt;p&gt;Previous issues&lt;br&gt;
Repeated problems&lt;br&gt;
Review history&lt;br&gt;
Changes in code quality over time&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configurable Review Rules&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Different teams care about different things.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Java&lt;br&gt;
Spring Boot&lt;br&gt;
Security&lt;br&gt;
Performance&lt;br&gt;
Clean Code&lt;br&gt;
Architecture&lt;/p&gt;

&lt;p&gt;The review criteria could be configurable depending on the project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Better Context Management&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is one of the biggest challenges with AI-based developer tools.&lt;/p&gt;

&lt;p&gt;Send too little context and the AI may misunderstand the change.&lt;/p&gt;

&lt;p&gt;Send too much context and the response becomes less focused while increasing processing cost.&lt;/p&gt;

&lt;p&gt;So the real engineering question becomes:&lt;/p&gt;

&lt;p&gt;What is the minimum context the AI needs to produce a useful review?&lt;/p&gt;

&lt;p&gt;I think that's a much more interesting problem than simply connecting an application to an AI API.&lt;/p&gt;

&lt;p&gt;AI Doesn't Replace the Developer&lt;/p&gt;

&lt;p&gt;I don't see AI code review as a replacement for human developers.&lt;/p&gt;

&lt;p&gt;I see it as a first-pass reviewer.&lt;/p&gt;

&lt;p&gt;AI can quickly identify potential problems.&lt;/p&gt;

&lt;p&gt;But a human developer still needs to ask:&lt;/p&gt;

&lt;p&gt;Is this actually a problem for our application?&lt;/p&gt;

&lt;p&gt;That's particularly important for business logic and architectural decisions, where the AI may not have enough context.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;Building this project changed the way I think about AI applications.&lt;/p&gt;

&lt;p&gt;The interesting part isn't:&lt;/p&gt;

&lt;p&gt;"I connected Spring Boot to an AI API."&lt;/p&gt;

&lt;p&gt;The interesting part is building a reliable backend system around that AI capability.&lt;/p&gt;

&lt;p&gt;For me, the combination of:&lt;/p&gt;

&lt;p&gt;Java + Spring Boot + APIs + AI + real-world automation&lt;/p&gt;

&lt;p&gt;is much more interesting than building another basic CRUD application.&lt;/p&gt;

&lt;p&gt;And that's the kind of backend engineering I want to keep exploring.&lt;/p&gt;

&lt;p&gt;What would you add?&lt;/p&gt;

&lt;p&gt;If you were building an AI-powered Pull Request reviewer, what would you prioritize?&lt;/p&gt;

&lt;p&gt;Security vulnerabilities? Performance issues? Architecture? Code quality?&lt;/p&gt;

&lt;p&gt;I'd love to hear what other developers would add.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>ai</category>
      <category>github</category>
    </item>
    <item>
      <title>I Built 3 AI Products with Spring Boot — Here’s What I Learned</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Fri, 14 Aug 2026 15:32:45 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-3-ai-products-with-spring-boot-heres-what-i-learned-26em</link>
      <guid>https://dev.to/sweety717/i-built-3-ai-products-with-spring-boot-heres-what-i-learned-26em</guid>
      <description>&lt;p&gt;I got tired of building the same CRUD applications.&lt;/p&gt;

&lt;p&gt;So instead of creating another simple Employee Management System or To-Do application, I decided to build something that felt closer to a real product.&lt;/p&gt;

&lt;p&gt;Over the last few weeks, I built three AI-powered applications using Spring Boot:&lt;/p&gt;

&lt;p&gt;🤖 AI Code Reviewer for GitHub Pull Requests&lt;br&gt;
📄 AI Resume Analyzer&lt;br&gt;
💬 Self-Hosted AI Support Widget&lt;/p&gt;

&lt;p&gt;Each project started with a simple idea:&lt;/p&gt;

&lt;p&gt;Can I build something useful with the backend technologies I already know instead of just building projects for a tutorial?&lt;/p&gt;

&lt;p&gt;The answer turned out to be yes.&lt;/p&gt;

&lt;p&gt;But the most valuable part wasn't actually finishing the applications.&lt;/p&gt;

&lt;p&gt;It was everything I learned while building them.&lt;/p&gt;

&lt;p&gt;Why I Chose Spring Boot&lt;/p&gt;

&lt;p&gt;I've been working with Java and Spring Boot, so I wanted to see how far I could take the stack when combined with AI.&lt;/p&gt;

&lt;p&gt;When people talk about AI applications, the conversation often revolves around Python, machine learning models, notebooks, and data science.&lt;/p&gt;

&lt;p&gt;But there is another side to AI:&lt;/p&gt;

&lt;p&gt;The application layer.&lt;/p&gt;

&lt;p&gt;You still need:&lt;/p&gt;

&lt;p&gt;REST APIs&lt;br&gt;
Authentication&lt;br&gt;
Database integration&lt;br&gt;
External API communication&lt;br&gt;
Request validation&lt;br&gt;
Error handling&lt;br&gt;
File processing&lt;br&gt;
Business logic&lt;br&gt;
Logging&lt;br&gt;
Configuration&lt;br&gt;
Deployment&lt;/p&gt;

&lt;p&gt;And that's where Spring Boot becomes extremely useful.&lt;/p&gt;

&lt;p&gt;The AI model might generate the intelligence, but the backend is what turns that intelligence into an actual product.&lt;/p&gt;

&lt;p&gt;Product 1: AI Code Reviewer for GitHub Pull Requests&lt;/p&gt;

&lt;p&gt;The first product I built was an AI-powered code reviewer for GitHub Pull Requests.&lt;/p&gt;

&lt;p&gt;The idea was simple:&lt;/p&gt;

&lt;p&gt;Instead of manually going through every changed file in a Pull Request, why not let an AI analyze the changes and provide useful feedback?&lt;/p&gt;

&lt;p&gt;The basic flow&lt;br&gt;
GitHub Pull Request&lt;br&gt;
        ↓&lt;br&gt;
Fetch PR information&lt;br&gt;
        ↓&lt;br&gt;
Get changed code&lt;br&gt;
        ↓&lt;br&gt;
Prepare review prompt&lt;br&gt;
        ↓&lt;br&gt;
AI analysis&lt;br&gt;
        ↓&lt;br&gt;
Generate review&lt;br&gt;
        ↓&lt;br&gt;
Return useful feedback&lt;/p&gt;

&lt;p&gt;The AI isn't just being asked:&lt;/p&gt;

&lt;p&gt;"Is this code good?"&lt;/p&gt;

&lt;p&gt;The goal is to make the review more useful by looking for things developers actually care about.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Potential bugs&lt;br&gt;
Code quality problems&lt;br&gt;
Security concerns&lt;br&gt;
Performance issues&lt;br&gt;
Maintainability&lt;br&gt;
Bad practices&lt;br&gt;
Possible improvements&lt;br&gt;
What I Learned From This Project&lt;/p&gt;

&lt;p&gt;The biggest lesson was:&lt;/p&gt;

&lt;p&gt;AI output is only as good as the context you give it.&lt;/p&gt;

&lt;p&gt;Initially, it is tempting to simply send a piece of code to an AI model and ask:&lt;/p&gt;

&lt;p&gt;"Review this code."&lt;/p&gt;

&lt;p&gt;But real code doesn't exist in isolation.&lt;/p&gt;

&lt;p&gt;A method might depend on another class.&lt;/p&gt;

&lt;p&gt;A variable might have a specific business meaning.&lt;/p&gt;

&lt;p&gt;A change might only make sense when you look at the entire Pull Request.&lt;/p&gt;

&lt;p&gt;So building an AI application isn't simply about calling an AI API.&lt;/p&gt;

&lt;p&gt;It's about collecting the right context and presenting it in the right way.&lt;/p&gt;

&lt;p&gt;That was one of my first major lessons.&lt;/p&gt;

&lt;p&gt;Product 2: AI Resume Analyzer&lt;/p&gt;

&lt;p&gt;The second product was an AI Resume Analyzer built with Spring Boot.&lt;/p&gt;

&lt;p&gt;The idea came from something very familiar to anyone who has applied for jobs:&lt;/p&gt;

&lt;p&gt;You spend hours creating a resume...&lt;/p&gt;

&lt;p&gt;Then send it to a company...&lt;/p&gt;

&lt;p&gt;And never know why it didn't get shortlisted.&lt;/p&gt;

&lt;p&gt;So I wanted to build a tool that could analyze a resume and provide useful feedback.&lt;/p&gt;

&lt;p&gt;The basic idea&lt;br&gt;
Resume&lt;br&gt;
  ↓&lt;br&gt;
Upload&lt;br&gt;
  ↓&lt;br&gt;
Backend processing&lt;br&gt;
  ↓&lt;br&gt;
Extract resume content&lt;br&gt;
  ↓&lt;br&gt;
AI analysis&lt;br&gt;
  ↓&lt;br&gt;
Generate feedback&lt;br&gt;
  ↓&lt;br&gt;
Return analysis&lt;/p&gt;

&lt;p&gt;The application can analyze areas such as:&lt;/p&gt;

&lt;p&gt;Skills&lt;br&gt;
Experience&lt;br&gt;
Keywords&lt;br&gt;
Resume structure&lt;br&gt;
Job relevance&lt;br&gt;
Missing information&lt;br&gt;
Potential improvements&lt;/p&gt;

&lt;p&gt;The interesting part was that this project introduced a completely different backend problem compared with the GitHub reviewer.&lt;/p&gt;

&lt;p&gt;Now the application had to deal with documents and unstructured information.&lt;/p&gt;

&lt;p&gt;What I Learned From This Project&lt;/p&gt;

&lt;p&gt;This project taught me something important:&lt;/p&gt;

&lt;p&gt;Building an AI application is often more about data preparation than the AI call itself.&lt;/p&gt;

&lt;p&gt;You can't just throw a document at an AI model and expect perfect results.&lt;/p&gt;

&lt;p&gt;The application needs to:&lt;/p&gt;

&lt;p&gt;Receive the file&lt;br&gt;
Process the content&lt;br&gt;
Extract useful information&lt;br&gt;
Organize that information&lt;br&gt;
Send the right context to the AI&lt;br&gt;
Process the response&lt;br&gt;
Present the result in a useful format&lt;/p&gt;

&lt;p&gt;The backend therefore becomes the bridge between the user's raw input and the AI model.&lt;/p&gt;

&lt;p&gt;That made me appreciate Spring Boot even more.&lt;/p&gt;

&lt;p&gt;Product 3: Self-Hosted AI Support Widget&lt;/p&gt;

&lt;p&gt;This is the project I'm currently most excited about.&lt;/p&gt;

&lt;p&gt;I built a self-hosted AI support widget using Spring Boot.&lt;/p&gt;

&lt;p&gt;The idea was to create an AI-powered support experience without forcing someone to depend on an expensive monthly SaaS subscription.&lt;/p&gt;

&lt;p&gt;The important word here is:&lt;/p&gt;

&lt;p&gt;Self-hosted.&lt;/p&gt;

&lt;p&gt;Instead of thinking:&lt;/p&gt;

&lt;p&gt;"I need to subscribe to another SaaS product."&lt;/p&gt;

&lt;p&gt;The idea becomes:&lt;/p&gt;

&lt;p&gt;"I can run this myself."&lt;/p&gt;

&lt;p&gt;The basic concept&lt;br&gt;
User&lt;br&gt;
 ↓&lt;br&gt;
Support Widget&lt;br&gt;
 ↓&lt;br&gt;
Spring Boot Backend&lt;br&gt;
 ↓&lt;br&gt;
AI Service&lt;br&gt;
 ↓&lt;br&gt;
Response&lt;br&gt;
 ↓&lt;br&gt;
Support Widget&lt;/p&gt;

&lt;p&gt;The backend handles the communication between the widget and the AI service.&lt;/p&gt;

&lt;p&gt;That means the frontend doesn't need to contain all the business logic.&lt;/p&gt;

&lt;p&gt;Spring Boot becomes the central layer responsible for the application's behavior.&lt;/p&gt;

&lt;p&gt;Why I Like This Project&lt;/p&gt;

&lt;p&gt;This project felt different from my previous applications because I wasn't just thinking about whether an API worked.&lt;/p&gt;

&lt;p&gt;I started thinking about:&lt;/p&gt;

&lt;p&gt;How would another developer use this?&lt;br&gt;
How can the application be self-hosted?&lt;br&gt;
What should the API look like?&lt;br&gt;
How should errors be handled?&lt;br&gt;
How should configuration work?&lt;br&gt;
How can the application be extended later?&lt;br&gt;
How can I make this feel like an actual product?&lt;/p&gt;

&lt;p&gt;That's when I realized something:&lt;/p&gt;

&lt;p&gt;There is a big difference between building an application and building a product.&lt;br&gt;
What These 3 Projects Taught Me&lt;/p&gt;

&lt;p&gt;After building all three, I noticed that the AI itself was not the hardest part.&lt;/p&gt;

&lt;p&gt;Calling an AI API is relatively straightforward.&lt;/p&gt;

&lt;p&gt;The difficult part is everything around it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI Doesn't Replace Backend Engineering&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was probably my biggest takeaway.&lt;/p&gt;

&lt;p&gt;AI can generate an answer.&lt;/p&gt;

&lt;p&gt;But someone still has to build the system around it.&lt;/p&gt;

&lt;p&gt;You still need to think about:&lt;/p&gt;

&lt;p&gt;Authentication&lt;br&gt;
      ↓&lt;br&gt;
API Design&lt;br&gt;
      ↓&lt;br&gt;
Validation&lt;br&gt;
      ↓&lt;br&gt;
Business Logic&lt;br&gt;
      ↓&lt;br&gt;
Database&lt;br&gt;
      ↓&lt;br&gt;
External Services&lt;br&gt;
      ↓&lt;br&gt;
AI Integration&lt;br&gt;
      ↓&lt;br&gt;
Error Handling&lt;br&gt;
      ↓&lt;br&gt;
Deployment&lt;/p&gt;

&lt;p&gt;That's backend engineering.&lt;/p&gt;

&lt;p&gt;And AI becomes another service that the backend integrates with.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt Engineering Is Only One Piece&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before building these projects, I thought a lot about prompts.&lt;/p&gt;

&lt;p&gt;After building them, I realized that prompt engineering is only one part of the problem.&lt;/p&gt;

&lt;p&gt;A better mental model is:&lt;/p&gt;

&lt;p&gt;Good Input&lt;br&gt;
    +&lt;br&gt;
Good Context&lt;br&gt;
    +&lt;br&gt;
Good Prompt&lt;br&gt;
    +&lt;br&gt;
Good Backend Logic&lt;br&gt;
    =&lt;br&gt;
Better AI Application&lt;/p&gt;

&lt;p&gt;If the application sends poor or incomplete context, even a great model can produce a poor result.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Product Thinking Matters&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you're following a tutorial, the goal is usually:&lt;/p&gt;

&lt;p&gt;Make the application work.&lt;/p&gt;

&lt;p&gt;When you're building your own product, the questions change.&lt;/p&gt;

&lt;p&gt;You start asking:&lt;/p&gt;

&lt;p&gt;Who is going to use this?&lt;br&gt;
What problem does it solve?&lt;br&gt;
Why would someone use this instead of another tool?&lt;br&gt;
What happens when something fails?&lt;br&gt;
How can I make it easier to use?&lt;br&gt;
What features should I add later?&lt;/p&gt;

&lt;p&gt;Those questions changed the way I approach development.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't Build Features Just Because You Can&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One of the easiest mistakes when building side projects is adding too many features.&lt;/p&gt;

&lt;p&gt;You start with:&lt;/p&gt;

&lt;p&gt;"I'll build an AI code reviewer."&lt;/p&gt;

&lt;p&gt;Then suddenly you're planning:&lt;/p&gt;

&lt;p&gt;Authentication&lt;br&gt;
Teams&lt;br&gt;
Billing&lt;br&gt;
Analytics&lt;br&gt;
Notifications&lt;br&gt;
Dashboards&lt;br&gt;
Admin panels&lt;br&gt;
Multiple AI providers&lt;br&gt;
Ten different integrations&lt;/p&gt;

&lt;p&gt;And the original product never gets finished.&lt;/p&gt;

&lt;p&gt;I've learned to ask:&lt;/p&gt;

&lt;p&gt;Does this feature solve the core problem?&lt;/p&gt;

&lt;p&gt;If the answer is no, it can wait.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Working Product Is More Valuable Than a Huge Project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would rather have:&lt;/p&gt;

&lt;p&gt;3 small working products&lt;/p&gt;

&lt;p&gt;than:&lt;/p&gt;

&lt;p&gt;1 huge unfinished application.&lt;/p&gt;

&lt;p&gt;These projects also taught me that a project doesn't need 50 features to demonstrate engineering ability.&lt;/p&gt;

&lt;p&gt;A relatively small application can demonstrate:&lt;/p&gt;

&lt;p&gt;API design&lt;br&gt;
Backend architecture&lt;br&gt;
External integrations&lt;br&gt;
AI integration&lt;br&gt;
File processing&lt;br&gt;
Error handling&lt;br&gt;
Business logic&lt;br&gt;
Deployment&lt;br&gt;
Product thinking&lt;/p&gt;

&lt;p&gt;That's already a lot.&lt;/p&gt;

&lt;p&gt;The Tech Stack&lt;/p&gt;

&lt;p&gt;Across these projects, my focus was primarily on the backend ecosystem I'm comfortable with.&lt;/p&gt;

&lt;p&gt;Backend&lt;br&gt;
Java&lt;br&gt;
Spring Boot&lt;br&gt;
REST APIs&lt;br&gt;
Spring-based backend architecture&lt;br&gt;
AI&lt;br&gt;
AI APIs / LLM integration&lt;br&gt;
Prompt design&lt;br&gt;
Context preparation&lt;br&gt;
AI-generated responses&lt;br&gt;
Integrations&lt;br&gt;
GitHub APIs&lt;br&gt;
File/document processing&lt;br&gt;
External services&lt;br&gt;
Development&lt;br&gt;
Maven&lt;br&gt;
Git/GitHub&lt;br&gt;
API testing&lt;br&gt;
Logging&lt;br&gt;
Configuration management&lt;/p&gt;

&lt;p&gt;The exact implementation differs between the projects, but the common idea is the same:&lt;/p&gt;

&lt;p&gt;Use Spring Boot as the application layer that connects users, business logic, external services, and AI.&lt;/p&gt;

&lt;p&gt;What I Would Do Differently Next Time&lt;/p&gt;

&lt;p&gt;If I started these projects again, I would spend more time on architecture before writing the first line of code.&lt;/p&gt;

&lt;p&gt;I'd ask:&lt;/p&gt;

&lt;p&gt;What is the core problem?&lt;br&gt;
        ↓&lt;br&gt;
What is the minimum useful product?&lt;br&gt;
        ↓&lt;br&gt;
What APIs do I need?&lt;br&gt;
        ↓&lt;br&gt;
What data do I need?&lt;br&gt;
        ↓&lt;br&gt;
Where does AI actually add value?&lt;br&gt;
        ↓&lt;br&gt;
How should the components communicate?&lt;br&gt;
        ↓&lt;br&gt;
How will I deploy it?&lt;/p&gt;

&lt;p&gt;This prevents a project from turning into a collection of random features.&lt;/p&gt;

&lt;p&gt;What's Next?&lt;/p&gt;

&lt;p&gt;I'm not planning to stop at these three.&lt;/p&gt;

&lt;p&gt;The next step is to take what I learned from these projects and build more practical backend tools around Java, Spring Boot, AI, and databases.&lt;/p&gt;

&lt;p&gt;I'm particularly interested in projects that solve problems developers actually face.&lt;/p&gt;

&lt;p&gt;Because my goal isn't simply:&lt;/p&gt;

&lt;p&gt;"Build another AI project."&lt;/p&gt;

&lt;p&gt;My goal is:&lt;/p&gt;

&lt;p&gt;Build useful software and learn the engineering behind it.&lt;/p&gt;

&lt;p&gt;Final Takeaway&lt;/p&gt;

&lt;p&gt;Building these three products changed the way I look at AI development.&lt;/p&gt;

&lt;p&gt;I started with:&lt;/p&gt;

&lt;p&gt;"How do I integrate AI into a Spring Boot application?"&lt;/p&gt;

&lt;p&gt;And ended up thinking much more about:&lt;/p&gt;

&lt;p&gt;"How do I build a useful product where AI is actually part of the solution?"&lt;/p&gt;

&lt;p&gt;That's a much more interesting question.&lt;/p&gt;

&lt;p&gt;The AI model is only one component.&lt;/p&gt;

&lt;p&gt;The real engineering challenge is everything around it.&lt;/p&gt;

&lt;p&gt;And that's exactly the part I want to keep exploring.&lt;/p&gt;

&lt;p&gt;The 3 Products&lt;/p&gt;

&lt;p&gt;🤖 AI Code Reviewer for GitHub Pull Requests&lt;br&gt;
Analyze Pull Request changes and generate AI-powered code review feedback.&lt;/p&gt;

&lt;p&gt;📄 AI Resume Analyzer&lt;br&gt;
Analyze resumes and provide AI-powered feedback and improvement suggestions.&lt;/p&gt;

&lt;p&gt;💬 Self-Hosted AI Support Widget&lt;br&gt;
Build an AI-powered support experience that can be self-hosted without relying entirely on a monthly SaaS platform.&lt;/p&gt;

&lt;p&gt;If you're also a Java/Spring Boot developer experimenting with AI, I'd love to hear what you're building.&lt;/p&gt;

&lt;p&gt;What would you build with Spring Boot + AI?&lt;/p&gt;

&lt;p&gt;Drop it in the comments 👇&lt;/p&gt;

&lt;p&gt;🔗 Projects&lt;/p&gt;

&lt;p&gt;GitHub: [&lt;a href="https://github.com/Sweety717/" rel="noopener noreferrer"&gt;https://github.com/Sweety717/&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Project 1 — AI Code Reviewer: [&lt;a href="https://swarnalata25.gumroad.com/l/codeguard-ai" rel="noopener noreferrer"&gt;https://swarnalata25.gumroad.com/l/codeguard-ai&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Project 2 — AI Resume Analyzer: [&lt;a href="https://swarnalata25.gumroad.com/l/resumeiq-ai" rel="noopener noreferrer"&gt;https://swarnalata25.gumroad.com/l/resumeiq-ai&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;Project 3 — Self-Hosted AI Support Widget: [&lt;a href="https://swarnalata25.gumroad.com/l/supportai-springboot" rel="noopener noreferrer"&gt;https://swarnalata25.gumroad.com/l/supportai-springboot&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>springboot</category>
      <category>backend</category>
    </item>
    <item>
      <title>I Built My Own AI Code Reviewer for GitHub Pull Requests</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Tue, 11 Aug 2026 10:33:47 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-my-own-ai-code-reviewer-for-github-pull-requests-4icc</link>
      <guid>https://dev.to/sweety717/i-built-my-own-ai-code-reviewer-for-github-pull-requests-4icc</guid>
      <description>&lt;p&gt;&lt;strong&gt;# I Built My Own AI Code Reviewer for GitHub Pull Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code reviews are important.&lt;/p&gt;

&lt;p&gt;But let's be honest — they can also become repetitive.&lt;/p&gt;

&lt;p&gt;Someone opens a pull request.&lt;/p&gt;

&lt;p&gt;A reviewer has to go through dozens of changed files.&lt;/p&gt;

&lt;p&gt;Then comes the usual checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is there an obvious bug?&lt;/li&gt;
&lt;li&gt;Is there a security issue?&lt;/li&gt;
&lt;li&gt;Is this database query going to cause a performance problem?&lt;/li&gt;
&lt;li&gt;Is there duplicated or unnecessary code?&lt;/li&gt;
&lt;li&gt;Is there a better way to implement this?&lt;/li&gt;
&lt;li&gt;Did we introduce something that will break later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when the PR is large, reviewing everything carefully becomes difficult.&lt;/p&gt;

&lt;p&gt;So I decided to build something for this problem.&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;CodeGuard AI&lt;/strong&gt; — a self-hosted AI code reviewer for GitHub Pull Requests.&lt;/p&gt;

&lt;p&gt;The idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Give it a GitHub PR → let AI inspect the diff → get a structured code review directly on GitHub.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And because I wanted this to be a developer-owned tool, it is designed to run on your own infrastructure and use your own AI provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## What is CodeGuard AI?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CodeGuard AI is a Spring Boot application that automatically reviews GitHub Pull Requests using an AI model.&lt;/p&gt;

&lt;p&gt;It can analyze a PR for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐛 Bugs&lt;/li&gt;
&lt;li&gt;🔐 Security issues&lt;/li&gt;
&lt;li&gt;⚡ Performance problems&lt;/li&gt;
&lt;li&gt;📐 Best-practice violations&lt;/li&gt;
&lt;li&gt;🗄️ Database-related issues&lt;/li&gt;
&lt;li&gt;💡 Improvement suggestions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of returning a huge block of AI-generated text, the review is structured around findings.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;CRITICAL&lt;br&gt;
SecurityConfig.java&lt;/p&gt;

&lt;p&gt;Disabled CSRF on Session-Cookie Authentication&lt;/p&gt;

&lt;p&gt;CSRF protection is disabled while the application&lt;br&gt;
uses session cookies for authentication.&lt;/p&gt;

&lt;p&gt;Suggested fix:&lt;br&gt;
Enable CSRF protection using a CookieCsrfTokenRepository&lt;br&gt;
or switch to stateless header-based authentication.&lt;br&gt;
The goal isn't to replace human reviewers.&lt;/p&gt;

&lt;p&gt;The goal is to give them a useful first pass before they spend time going through the PR themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ktqkdqs4myctq4jucy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ktqkdqs4myctq4jucy0.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2yoki18lc3nqsbwfnb6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2yoki18lc3nqsbwfnb6u.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7keg6b6ktawlpyx4a32l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7keg6b6ktawlpyx4a32l.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffsbdapfhaquou8auy9ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffsbdapfhaquou8auy9ow.png" alt=" " width="799" height="408"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4326m5ar928qptid2n4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4326m5ar928qptid2n4k.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I built it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are already many AI coding tools.&lt;/p&gt;

&lt;p&gt;AI can write code.&lt;/p&gt;

&lt;p&gt;AI can explain code.&lt;/p&gt;

&lt;p&gt;AI can generate tests.&lt;/p&gt;

&lt;p&gt;So I was interested in a slightly different question:&lt;/p&gt;

&lt;p&gt;What happens if AI becomes the first reviewer instead of the programmer?&lt;/p&gt;

&lt;p&gt;A pull request already contains something extremely valuable for an AI model:&lt;br&gt;
the change itself.&lt;/p&gt;

&lt;p&gt;You don't necessarily need to understand the entire application to start finding potential problems.&lt;/p&gt;

&lt;p&gt;You can start with:&lt;br&gt;
PR&lt;br&gt;
 ↓&lt;br&gt;
Changed files&lt;br&gt;
 ↓&lt;br&gt;
Diff&lt;br&gt;
 ↓&lt;br&gt;
AI analysis&lt;br&gt;
 ↓&lt;br&gt;
Structured findings&lt;br&gt;
 ↓&lt;br&gt;
Developer&lt;br&gt;
That became the core idea behind CodeGuard AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How CodeGuard AI works&lt;/strong&gt;&lt;br&gt;
The architecture is intentionally simple.&lt;br&gt;
                 GitHub&lt;br&gt;
                    │&lt;br&gt;
                    │ Pull Request&lt;br&gt;
                    ▼&lt;br&gt;
          ┌─────────────────────┐&lt;br&gt;
          │ GitHub Webhook       │&lt;br&gt;
          │ Receiver             │&lt;br&gt;
          └──────────┬──────────┘&lt;br&gt;
                     │&lt;br&gt;
                     ▼&lt;br&gt;
          ┌─────────────────────┐&lt;br&gt;
          │ PR / Diff Fetcher   │&lt;br&gt;
          │ GitHub API          │&lt;br&gt;
          └──────────┬──────────┘&lt;br&gt;
                     │&lt;br&gt;
                     ▼&lt;br&gt;
          ┌─────────────────────┐&lt;br&gt;
          │ Code Review Service │&lt;br&gt;
          └──────────┬──────────┘&lt;br&gt;
                     │&lt;br&gt;
                     ▼&lt;br&gt;
        ┌─────────────────────────┐&lt;br&gt;
        │ AI Provider Abstraction │&lt;br&gt;
        └──────┬──────┬──────┬───┘&lt;br&gt;
               │      │      │&lt;br&gt;
            OpenAI  Gemini  Ollama&lt;br&gt;
               │      │      │&lt;br&gt;
               └──────┴──────┘&lt;br&gt;
                     │&lt;br&gt;
                     ▼&lt;br&gt;
          ┌─────────────────────┐&lt;br&gt;
          │ Structured Review   │&lt;br&gt;
          │ Findings            │&lt;br&gt;
          └──────────┬──────────┘&lt;br&gt;
                     │&lt;br&gt;
              ┌──────┴───────┐&lt;br&gt;
              ▼              ▼&lt;br&gt;
          Dashboard       GitHub PR&lt;/p&gt;

&lt;p&gt;The application is built with:&lt;/p&gt;

&lt;p&gt;Java 17&lt;br&gt;
Spring Boot&lt;br&gt;
Spring Security&lt;br&gt;
GitHub REST API&lt;br&gt;
REST APIs&lt;br&gt;
HTML/CSS/Vanilla JavaScript&lt;br&gt;
OpenAI / Gemini / Ollama integrations&lt;br&gt;
Maven&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: GitHub sends the Pull Request&lt;/strong&gt;&lt;br&gt;
CodeGuard AI exposes a GitHub webhook endpoint.&lt;br&gt;
For example:&lt;br&gt;
POST /webhook/github&lt;br&gt;
When a pull request is opened, reopened, or updated, GitHub sends an event to CodeGuard AI.&lt;br&gt;
The webhook signature is verified using HMAC-SHA256 before processing the request.&lt;br&gt;
This is important because you don't want arbitrary requests triggering your review pipeline.&lt;br&gt;
&lt;strong&gt;Step 2: Fetch the Pull Request&lt;/strong&gt;&lt;br&gt;
Once the webhook is verified, CodeGuard AI uses the GitHub API to retrieve information about the PR.&lt;/p&gt;

&lt;p&gt;This includes things such as:&lt;/p&gt;

&lt;p&gt;Repository&lt;br&gt;
Pull request number&lt;br&gt;
Author&lt;br&gt;
Changed files&lt;br&gt;
Diff&lt;br&gt;
Added lines&lt;br&gt;
Deleted lines&lt;/p&gt;

&lt;p&gt;The important part is the diff.&lt;/p&gt;

&lt;p&gt;Instead of blindly sending an entire repository to an AI model, the reviewer focuses on the code that actually changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Send the changes to the AI&lt;/strong&gt;&lt;br&gt;
The diff is then passed to the configured AI provider with a structured review prompt.&lt;br&gt;
CodeGuard AI supports multiple providers:&lt;br&gt;
OpenAI&lt;br&gt;
Google Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;The provider can be selected through configuration.&lt;br&gt;
For example&lt;br&gt;
ai.provider=openai&lt;br&gt;
or:&lt;br&gt;
ai.provider=gemini&lt;br&gt;
or:&lt;br&gt;
ai.provider=ollama&lt;br&gt;
This provider abstraction was an important design decision.&lt;br&gt;
I didn't want the entire application tightly coupled to a single AI vendor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Generate structured findings&lt;/strong&gt;&lt;br&gt;
The AI isn't simply asked:&lt;br&gt;
"Review this code."&lt;br&gt;
Instead, the review is structured around useful information.&lt;br&gt;
A finding contains concepts such as:&lt;br&gt;
Severity&lt;br&gt;
Category&lt;br&gt;
File&lt;br&gt;
Location&lt;br&gt;
Problem&lt;br&gt;
Suggested Fix&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
Severity: HIGH&lt;/p&gt;

&lt;p&gt;Category: SECURITY&lt;/p&gt;

&lt;p&gt;File:&lt;br&gt;
src/main/java/com/example/config/SecurityConfig.java&lt;br&gt;
Problem:&lt;br&gt;
CSRF protection is disabled while session cookies&lt;br&gt;
are used for authentication.&lt;br&gt;
Suggested Fix:&lt;br&gt;
Enable CSRF protection or switch to stateless&lt;br&gt;
authentication.&lt;br&gt;
This makes the result much easier to consume in a dashboard or GitHub comment.&lt;br&gt;
&lt;strong&gt;Step 5: Post the review back to GitHub&lt;/strong&gt;&lt;br&gt;
One of the things I wanted from the beginning was:&lt;br&gt;
Don't make developers open another dashboard just to read the review.&lt;br&gt;
So CodeGuard AI can post the generated review directly to the Pull Request.&lt;br&gt;
The result looks something like:&lt;br&gt;
🤖 CodeGuard AI Review&lt;/p&gt;

&lt;p&gt;✅ SAFE TO MERGE&lt;/p&gt;

&lt;p&gt;Quality score: 9/10&lt;br&gt;
Risk: Low&lt;br&gt;
Confidence: 95%&lt;/p&gt;

&lt;p&gt;No issues found.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;What's good:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean implementation&lt;/li&gt;
&lt;li&gt;Backward-compatible configuration&lt;/li&gt;
&lt;li&gt;Clear separation of concerns
If problems are found, the review instead highlights them with severity and suggested fixes.
The dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dashboard provides a second way to run and inspect reviews.&lt;/p&gt;

&lt;p&gt;You can manually enter:&lt;/p&gt;

&lt;p&gt;owner/repository&lt;br&gt;
PR number&lt;/p&gt;

&lt;p&gt;and run a review.&lt;/p&gt;

&lt;p&gt;This is useful before setting up the webhook because you can test the entire pipeline manually:&lt;/p&gt;

&lt;p&gt;GitHub&lt;br&gt;
   ↓&lt;br&gt;
Fetch PR&lt;br&gt;
   ↓&lt;br&gt;
Analyze diff&lt;br&gt;
   ↓&lt;br&gt;
AI&lt;br&gt;
   ↓&lt;br&gt;
Generate review&lt;br&gt;
   ↓&lt;br&gt;
Post comment&lt;/p&gt;

&lt;p&gt;No webhook is required for the initial test.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Review history&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I also wanted the application to remember previous reviews.&lt;/p&gt;

&lt;p&gt;The dashboard therefore keeps review history containing information such as:&lt;/p&gt;

&lt;p&gt;Repository&lt;br&gt;
PR number&lt;br&gt;
Review score&lt;br&gt;
Risk&lt;br&gt;
Number of findings&lt;br&gt;
Files reviewed&lt;br&gt;
Lines changed&lt;br&gt;
Review timestamp&lt;/p&gt;

&lt;p&gt;This makes it possible to see how a codebase is progressing over time.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Review #1     6/10    3 issues&lt;br&gt;
Review #2     7/10    2 issues&lt;br&gt;
Review #3     9/10    0 issues&lt;/p&gt;

&lt;p&gt;The dashboard can also visualize review trends.&lt;/p&gt;

&lt;p&gt;One interesting feature: merge recommendation&lt;/p&gt;

&lt;p&gt;I added a simple high-level verdict to make the review easier to understand.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;┌──────────────────────────────┐&lt;br&gt;
│       ✅ SAFE TO MERGE       │&lt;br&gt;
└──────────────────────────────┘&lt;/p&gt;

&lt;p&gt;Quality Score: 9/10&lt;br&gt;
AI Confidence: 95%&lt;br&gt;
Critical Issues: 0&lt;br&gt;
Suggestions: 0&lt;/p&gt;

&lt;p&gt;Or, when the PR has serious issues:&lt;/p&gt;

&lt;p&gt;┌──────────────────────────────┐&lt;br&gt;
│       ⚠️ REVIEW REQUIRED     │&lt;br&gt;
└──────────────────────────────┘&lt;/p&gt;

&lt;p&gt;Quality Score: 6/10&lt;br&gt;
Risk: Medium&lt;br&gt;
Critical Issues: 1&lt;/p&gt;

&lt;p&gt;This isn't intended to replace a team's merge policy.&lt;/p&gt;

&lt;p&gt;It's simply a quick signal for the developer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Why self-hosted?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This was probably the most important product decision.&lt;/p&gt;

&lt;p&gt;There are already hosted AI code-review products.&lt;/p&gt;

&lt;p&gt;So why build another one?&lt;/p&gt;

&lt;p&gt;Because some developers and teams don't want their source code going through another hosted SaaS platform.&lt;/p&gt;

&lt;p&gt;With a self-hosted architecture:&lt;/p&gt;

&lt;p&gt;Your GitHub&lt;br&gt;
     ↓&lt;br&gt;
Your CodeGuard instance&lt;br&gt;
     ↓&lt;br&gt;
Your AI provider&lt;/p&gt;

&lt;p&gt;You control the infrastructure and credentials.&lt;/p&gt;

&lt;p&gt;You can use:&lt;/p&gt;

&lt;p&gt;OpenAI&lt;br&gt;
Google Gemini&lt;br&gt;
Ollama&lt;/p&gt;

&lt;p&gt;And with Ollama, you can even run a local model.&lt;/p&gt;

&lt;p&gt;The application doesn't require a CodeGuard-managed AI subscription.&lt;/p&gt;

&lt;p&gt;Private repositories&lt;/p&gt;

&lt;p&gt;CodeGuard AI isn't limited to public repositories.&lt;/p&gt;

&lt;p&gt;The GitHub Personal Access Token used by the application determines which repositories it can access.&lt;/p&gt;

&lt;p&gt;For example, a fine-grained token can be configured with the required permissions for the repositories that need to be reviewed.&lt;/p&gt;

&lt;p&gt;This makes the same architecture usable for private projects and internal repositories.&lt;/p&gt;

&lt;p&gt;Handling large Pull Requests&lt;/p&gt;

&lt;p&gt;There is an obvious problem with AI-based code review:&lt;/p&gt;

&lt;p&gt;What happens when a PR contains hundreds of files?&lt;/p&gt;

&lt;p&gt;Sending an enormous diff to an AI model isn't practical.&lt;/p&gt;

&lt;p&gt;CodeGuard AI therefore truncates large per-file diffs to keep the review within a reasonable token budget.&lt;/p&gt;

&lt;p&gt;That means extremely large PRs may receive a partial review rather than causing the entire review process to fail.&lt;/p&gt;

&lt;p&gt;This is one area I want to improve further.&lt;/p&gt;

&lt;p&gt;What I deliberately didn't build yet&lt;/p&gt;

&lt;p&gt;One thing I intentionally kept out of the first version is inline GitHub review comments.&lt;/p&gt;

&lt;p&gt;Currently, CodeGuard AI posts a structured summary comment to the Pull Request.&lt;/p&gt;

&lt;p&gt;Inline comments are more complicated because GitHub's review API requires calculating the appropriate diff positions.&lt;/p&gt;

&lt;p&gt;So a future version could potentially do this:&lt;/p&gt;

&lt;p&gt;src/main/java/UserService.java:42&lt;/p&gt;

&lt;p&gt;🔴 HIGH&lt;/p&gt;

&lt;p&gt;Potential authorization bypass.&lt;/p&gt;

&lt;p&gt;Suggested fix:&lt;br&gt;
Verify that the authenticated user owns&lt;br&gt;
the requested resource before updating it.&lt;/p&gt;

&lt;p&gt;That would make the tool much closer to a traditional human code review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What I learned building it&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The interesting part of this project wasn't actually calling an AI API.&lt;/p&gt;

&lt;p&gt;That part is relatively straightforward.&lt;/p&gt;

&lt;p&gt;The harder part is building the system around it.&lt;/p&gt;

&lt;p&gt;A useful AI developer tool needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reliable input&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model is only as useful as the code context you provide.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Structured output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A giant paragraph isn't particularly useful during a code review.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provider abstraction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI providers change quickly, so coupling the application to one provider isn't ideal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub tokens, webhook secrets and AI API keys need to be handled carefully.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Failure handling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub API failures, AI timeouts, invalid model responses and huge diffs all need to be considered.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A useful UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Developers shouldn't have to dig through logs to understand what happened.&lt;br&gt;
**&lt;br&gt;
Current feature set**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The current version includes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✅ GitHub Pull Request integration&lt;br&gt;
✅ GitHub webhook support&lt;br&gt;
✅ HMAC webhook verification&lt;br&gt;
✅ Manual PR review&lt;br&gt;
✅ AI-powered bug detection&lt;br&gt;
✅ Security analysis&lt;br&gt;
✅ Performance analysis&lt;br&gt;
✅ Best-practice analysis&lt;br&gt;
✅ Risk assessment&lt;br&gt;
✅ Quality scoring&lt;br&gt;
✅ AI confidence score&lt;br&gt;
✅ Structured findings&lt;br&gt;
✅ Suggested fixes&lt;br&gt;
✅ GitHub review comments&lt;br&gt;
✅ Review history&lt;br&gt;
✅ Review trend visualization&lt;br&gt;
✅ Markdown export&lt;br&gt;
✅ PDF export&lt;br&gt;
✅ OpenAI support&lt;br&gt;
✅ Google Gemini support&lt;br&gt;
✅ Ollama support&lt;br&gt;
✅ Light/dark mode&lt;br&gt;
✅ Self-hosted deployment&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's next?&lt;/strong&gt;&lt;br&gt;
There are several things I want to explore next.&lt;/p&gt;

&lt;p&gt;Inline review comments&lt;/p&gt;

&lt;p&gt;Instead of one summary comment, report findings directly on changed lines.&lt;/p&gt;

&lt;p&gt;GitHub App support&lt;/p&gt;

&lt;p&gt;The current version uses a Personal Access Token because it keeps the self-hosted setup simple.&lt;/p&gt;

&lt;p&gt;A GitHub App would be a better architecture for multi-repository and multi-organization deployments.&lt;/p&gt;

&lt;p&gt;Better repository configuration&lt;/p&gt;

&lt;p&gt;Allow teams to define their own review rules.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;security:&lt;br&gt;
  enabled: true&lt;/p&gt;

&lt;p&gt;performance:&lt;br&gt;
  enabled: true&lt;/p&gt;

&lt;p&gt;tests:&lt;br&gt;
  required: true&lt;/p&gt;

&lt;p&gt;style:&lt;br&gt;
  enabled: false&lt;br&gt;
Custom review prompts&lt;/p&gt;

&lt;p&gt;Different teams care about different things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Spring Boot backend team may care heavily about:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;N+1 queries&lt;br&gt;
transaction boundaries&lt;br&gt;
authentication&lt;br&gt;
authorization&lt;br&gt;
database indexes&lt;br&gt;
API design&lt;/p&gt;

&lt;p&gt;A frontend team may care about completely different things.&lt;/p&gt;

&lt;p&gt;CI/CD integration&lt;/p&gt;

&lt;p&gt;Another direction is running CodeGuard AI directly inside CI pipelines.&lt;/p&gt;

&lt;p&gt;Final thoughts&lt;/p&gt;

&lt;p&gt;I started CodeGuard AI with a simple idea:&lt;/p&gt;

&lt;p&gt;AI shouldn't only help us write code. It can also help us question the code we just wrote.&lt;/p&gt;

&lt;p&gt;The goal isn't to replace experienced engineers.&lt;/p&gt;

&lt;p&gt;A good human reviewer can understand business context, architecture and trade-offs that an AI model may completely miss.&lt;/p&gt;

&lt;p&gt;But an AI reviewer can be a useful first layer.&lt;/p&gt;

&lt;p&gt;It can catch obvious issues.&lt;/p&gt;

&lt;p&gt;It can point out suspicious code.&lt;/p&gt;

&lt;p&gt;It can identify things worth discussing.&lt;/p&gt;

&lt;p&gt;And it can do that before the human reviewer spends 30 minutes reconstructing what changed.&lt;/p&gt;

&lt;p&gt;That's what I'm trying to build with CodeGuard AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it / explore the project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CodeGuard AI is built as a self-hosted Spring Boot application with the complete source code included.&lt;/p&gt;

&lt;p&gt;If you want to run your own instance, you can configure it with your own OpenAI, Gemini, or Ollama setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;&lt;strong&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://swarnalata25.gumroad.com/l/codeguard-ai" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-files.gumroad.com%2Fxx9gwek95wrye7pw6g799oq554in" height="517" class="m-0" width="1005"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://swarnalata25.gumroad.com/l/codeguard-ai" rel="noopener noreferrer" class="c-link"&gt;
            CodeGuard AI — Self-Hosted GitHub AI Code Reviewer
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            # CodeGuard AI### Self-hosted AI code review for GitHub Pull Requests — built with Spring Boot.CodeGuard AI automatically reviews your GitHub Pull Requests using AI and identifies potential bugs, security issues, performance problems, and best-practice violations.Instead of paying for another monthly SaaS subscription, run CodeGuard AI on your own infrastructure using your own AI provider credentials.## 🚀 What You Get- 🤖 AI-powered GitHub Pull Request reviews- 🐛 Bug and logic issue detection- 🔐 Security issue detection- ⚡ Performance analysis- ✅ Best-practice checks- 📊 Quality score and risk assessment- 🎯 AI confidence score- 💬 Automatic review comments posted directly to GitHub- 🔄 Automatic reviews through GitHub webhooks- 📝 Manual PR review from the dashboard- 📚 Review history- 📈 Review trend tracking- 📄 Export reviews to Markdown and PDF- 🌙 Light and dark mode- 🔌 Multiple AI providers## 🔌 Supported AI ProvidersChoose the provider that works best for you:- OpenAI- Google Gemini- Ollama (local AI)Your AI provider can be changed through configuration without changing the core review architecture.## 🛠️ Technology Stack- Java 17+- Spring Boot- Spring Security- GitHub REST API- AI provider integrations- REST APIs- HTML / CSS / Vanilla JavaScript- Maven## 🔐 Self-Hosted &amp;amp;amp; PrivateCodeGuard AI is designed to run in your own environment.Your GitHub credentials and AI API keys stay under your control.It can be used with repositories your GitHub token has permission to access, including private repositories when the token has the required permissions.## 📦 What's IncludedThe download includes:- Complete Spring Boot source code- Installation Guide- User Manual- API Documentation- Architecture Diagram- Database Schema- SQL database script- Postman Collection- Environment Configuration Guide- Sample Repository Guide- Changelog- License## ⚡ How It WorksGitHub Pull Request↓GitHub Webhook↓CodeGuard AI↓Fetch PR Changes↓AI Analysis↓Security / Bug / Performance Review↓Quality &amp;amp;amp; Risk Assessment↓GitHub Review Comment## 🎯 Who Is This For?CodeGuard AI is ideal for:- Java / Spring Boot developers- Backend developers- Solo developers- Small development teams- Freelancers- Developers building internal developer tools- Anyone who wants an AI-assisted code review system they can run themselves## 💡 Why Buy the Source Code?This isn't just a demo UI.You get the complete backend implementation and supporting documentation so you can:- Run it locally- Deploy it on your own server- Customize the review logic- Change the AI provider- Modify the dashboard- Extend the GitHub integration- Build additional features on top of it## ⚠️ Requirements- Java 17+- Maven 3.8+- GitHub Personal Access Token- OpenAI, Gemini, or Ollama- A GitHub repository/PR accessible by your configured tokenDetailed setup instructions are included in the download.---### Build on top of it. Customize it. Self-host it.One-time purchase. No CodeGuard AI subscription required.
          &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;div class="color-secondary fs-s flex items-center"&amp;gt;
        &amp;lt;img
          alt="favicon"
          class="c-embed__favicon m-0 mr-2 radius-0"
          src="https://public-files.gumroad.com/v56byb8cpoecdju06otk8bb7y66g"
          loading="lazy" /&amp;gt;
      swarnalata25.gumroad.com
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;I'd especially love feedback on:&lt;/p&gt;

&lt;p&gt;What should an AI code reviewer detect?&lt;br&gt;
Would you use a self-hosted reviewer?&lt;br&gt;
Which AI provider would you prefer?&lt;br&gt;
Are inline GitHub comments more useful than a single summary?&lt;br&gt;
What would make this useful for your team?&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🚀&lt;/p&gt;
&lt;/div&gt;
&lt;/strong&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>springboot</category>
      <category>github</category>
    </item>
    <item>
      <title>I Built an AI Resume Analyzer in Spring Boot Instead of Another CRUD Project</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Sat, 08 Aug 2026 05:17:44 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-an-ai-resume-analyzer-in-spring-boot-instead-of-another-crud-project-237o</link>
      <guid>https://dev.to/sweety717/i-built-an-ai-resume-analyzer-in-spring-boot-instead-of-another-crud-project-237o</guid>
      <description>&lt;h1&gt;
  
  
  I Built an AI Resume Analyzer in Spring Boot Instead of Another CRUD Project
&lt;/h1&gt;

&lt;p&gt;After finishing my previous AI Support Widget project, I wanted to build something that solved a different real-world problem.&lt;/p&gt;

&lt;p&gt;Most developers have built a Todo app, an Employee Management System, or another CRUD project.&lt;/p&gt;

&lt;p&gt;I wanted to build something people could actually use.&lt;/p&gt;

&lt;p&gt;So I spent the last few weeks building an AI-powered Resume Analyzer using Spring Boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## The idea&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whenever I apply for jobs, I usually wonder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is my resume ATS friendly?&lt;/li&gt;
&lt;li&gt;Which keywords am I missing?&lt;/li&gt;
&lt;li&gt;Which resume version is better?&lt;/li&gt;
&lt;li&gt;How can I improve my chances before applying?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are plenty of online tools, but I wanted a self-hosted application that I fully controlled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Tech Stack&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 17&lt;/li&gt;
&lt;li&gt;Spring Boot 3&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;Thymeleaf&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;OpenAI API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;## What it does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of simply uploading a resume and getting one score, the application provides multiple AI-powered features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### ATS Resume Analysis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application analyzes a resume against a job description and generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ATS score&lt;/li&gt;
&lt;li&gt;Resume strengths&lt;/li&gt;
&lt;li&gt;Weaknesses&lt;/li&gt;
&lt;li&gt;Missing keywords&lt;/li&gt;
&lt;li&gt;Resume improvement suggestions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm8ll13nnpbsjqi02blgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm8ll13nnpbsjqi02blgs.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkjjshculop4lma7jj08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqkjjshculop4lma7jj08.png" alt=" " width="799" height="399"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feyensdilz88f2j8627gy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feyensdilz88f2j8627gy.png" alt=" " width="800" height="461"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F76z03r8wh4p2rbd51muh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F76z03r8wh4p2rbd51muh.png" alt=" " width="800" height="431"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fadasn5d70u4d4owinq6h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fadasn5d70u4d4owinq6h.png" alt=" " width="799" height="422"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj6gg6c5ge5shxl253jhh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj6gg6c5ge5shxl253jhh.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fclyim56emlg1ptc5afky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fclyim56emlg1ptc5afky.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### AI Resume Rewrite&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of manually editing bullet points, the application rewrites the resume while preserving the candidate's actual experience.&lt;/p&gt;

&lt;p&gt;The goal isn't to invent achievements.&lt;/p&gt;

&lt;p&gt;It's to improve clarity and ATS readability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jnvz239hq0asyc4oba9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jnvz239hq0asyc4oba9.png" alt=" " width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### Resume Comparison&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One feature I personally found useful was comparing two versions of the same resume.&lt;/p&gt;

&lt;p&gt;Sometimes changing only a few bullet points increased the ATS score significantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmesv1u8weiyzbhxvxnm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmesv1u8weiyzbhxvxnm1.png" alt=" " width="799" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### Resume Versioning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rather than replacing previous analyses, every analysis is saved.&lt;/p&gt;

&lt;p&gt;This allows users to compare improvements over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8i1uciej4d3eol4fgu8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8i1uciej4d3eol4fgu8q.png" alt=" " width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### AI Interview Preparation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After analyzing the resume, the application can generate interview questions based on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resume&lt;/li&gt;
&lt;li&gt;Skills&lt;/li&gt;
&lt;li&gt;Experience&lt;/li&gt;
&lt;li&gt;Job Description&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the tool useful even after the ATS analysis is complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4mpq6f5n1ox27v7xrrlr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4mpq6f5n1ox27v7xrrlr.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application also includes a dashboard showing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Previous analyses&lt;/li&gt;
&lt;li&gt;Average ATS score&lt;/li&gt;
&lt;li&gt;Highest score&lt;/li&gt;
&lt;li&gt;Resume history&lt;/li&gt;
&lt;li&gt;Trends over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz46o4k64qs0r8eny7bi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz46o4k64qs0r8eny7bi8.png" alt=" " width="800" height="492"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41a035o2g8lwack6n89m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41a035o2g8lwack6n89m.png" alt=" " width="799" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Challenges&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One interesting challenge was balancing AI output with predictable scoring.&lt;/p&gt;

&lt;p&gt;Large Language Models are creative, but ATS scoring should feel consistent.&lt;/p&gt;

&lt;p&gt;I ended up combining deterministic scoring with AI-generated explanations so that users receive both a measurable score and useful feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## What I intentionally didn't build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One thing I deliberately left out was payment gateway integration.&lt;/p&gt;

&lt;p&gt;The application already supports usage limits and user plans, but checkout integration (Stripe/Razorpay) is something I'd rather let developers integrate based on their own business needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building AI products isn't just about calling an LLM.&lt;/p&gt;

&lt;p&gt;Most of the work is actually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompt engineering&lt;/li&gt;
&lt;li&gt;Designing good workflows&lt;/li&gt;
&lt;li&gt;Managing user data&lt;/li&gt;
&lt;li&gt;Producing useful outputs&lt;/li&gt;
&lt;li&gt;Creating a smooth user experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those parts took far longer than integrating the OpenAI API itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;## Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This project taught me much more than another CRUD application ever could.&lt;/p&gt;

&lt;p&gt;I'm now building a collection of AI-powered Spring Boot applications focused on solving real business problems instead of tutorial-style examples.&lt;/p&gt;

&lt;p&gt;If you're building AI products with Java or Spring Boot, I'd love to hear what you're working on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### Source Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I packaged this project as a complete Spring Boot source code product with documentation, database scripts, API collection, installation guide, and production-ready architecture.&lt;/p&gt;

&lt;p&gt;If you'd like to build on top of it instead of starting from scratch, you can check it out here:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://swarnalata25.gumroad.com/l/resumeiq-ai" rel="noopener noreferrer"&gt;https://swarnalata25.gumroad.com/l/resumeiq-ai&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd also love your feedback on what features you'd add next.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built a Self-Hosted AI Support Widget with Spring Boot (No Monthly SaaS Fees)</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Fri, 07 Aug 2026 15:19:16 +0000</pubDate>
      <link>https://dev.to/sweety717/i-built-a-self-hosted-ai-support-widget-with-spring-boot-no-monthly-saas-fees-53m2</link>
      <guid>https://dev.to/sweety717/i-built-a-self-hosted-ai-support-widget-with-spring-boot-no-monthly-saas-fees-53m2</guid>
      <description>&lt;p&gt;Every new SaaS seems to embed ChatGPT these days.&lt;/p&gt;

&lt;p&gt;Most AI support solutions rely on third-party platforms, monthly subscriptions, and vendor lock-in. While they're great products, I wanted something different.&lt;/p&gt;

&lt;p&gt;I wanted complete ownership.&lt;/p&gt;

&lt;p&gt;I wanted to deploy everything on my own server, use my own OpenAI API key, customize every part of the experience, and embed the widget into any website with a single script tag.&lt;/p&gt;

&lt;p&gt;So I built my own self-hosted AI support widget using Spring Boot and Vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Built It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When building small products and websites, I realized that customer support quickly becomes a problem.&lt;/p&gt;

&lt;p&gt;Users have questions about pricing, features, returns, or simply get stuck.&lt;/p&gt;

&lt;p&gt;Most developers solve this by integrating services like Intercom, Crisp, or Tidio.&lt;/p&gt;

&lt;p&gt;Those platforms are excellent, but they also mean:&lt;/p&gt;

&lt;p&gt;Monthly subscription costs&lt;br&gt;
Vendor lock-in&lt;br&gt;
Customer conversations stored on third-party platforms&lt;br&gt;
Limited customization&lt;br&gt;
Another external dependency&lt;/p&gt;

&lt;p&gt;I wanted something that developers could completely own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Goal&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal was simple.&lt;/p&gt;

&lt;p&gt;Build an AI-powered customer support widget that developers can deploy on their own server and integrate into any website in less than a minute.&lt;/p&gt;

&lt;p&gt;The widget should:&lt;/p&gt;

&lt;p&gt;Answer customer questions using AI&lt;br&gt;
Learn from a custom knowledge base&lt;br&gt;
Match the company's branding&lt;br&gt;
Store conversation history&lt;br&gt;
Allow human handoff&lt;br&gt;
Be easy to deploy&lt;br&gt;
Require only one script tag to embed&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technology Stack&lt;/strong&gt;&lt;br&gt;
Java 17&lt;br&gt;
Spring Boot 3&lt;br&gt;
Spring Security&lt;br&gt;
Spring Data JPA&lt;br&gt;
Thymeleaf&lt;br&gt;
Vanilla JavaScript&lt;br&gt;
H2 Database (MySQL supported)&lt;br&gt;
OpenAI API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The overall architecture is intentionally simple.&lt;br&gt;
Visitor&lt;br&gt;
      │&lt;br&gt;
      ▼&lt;br&gt;
AI Chat Widget&lt;br&gt;
(Vanilla JavaScript)&lt;br&gt;
      │&lt;br&gt;
      ▼&lt;br&gt;
Spring Boot REST API&lt;br&gt;
      │&lt;br&gt;
      ▼&lt;br&gt;
OpenAI API&lt;br&gt;
      │&lt;br&gt;
      ▼&lt;br&gt;
Database&lt;br&gt;
(H2 / MySQL)&lt;br&gt;
Keeping the frontend framework-free makes the widget lightweight and easy to embed into virtually any website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-Line Integration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding the widget to a website only requires a single script.&lt;br&gt;
&lt;code&gt;&amp;lt;script src="/widget/widget.js" data-api-base=""&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br&gt;
No React.&lt;/p&gt;

&lt;p&gt;No Vue.&lt;/p&gt;

&lt;p&gt;No npm packages.&lt;/p&gt;

&lt;p&gt;Just one script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project includes:&lt;/p&gt;

&lt;p&gt;✅ AI-powered customer support&lt;/p&gt;

&lt;p&gt;✅ Spring Boot backend&lt;/p&gt;

&lt;p&gt;✅ Secure admin authentication&lt;/p&gt;

&lt;p&gt;✅ Custom knowledge base&lt;/p&gt;

&lt;p&gt;✅ Conversation history&lt;/p&gt;

&lt;p&gt;✅ Brand customization&lt;/p&gt;

&lt;p&gt;✅ Human handoff with email notification&lt;/p&gt;

&lt;p&gt;✅ OpenAI API configuration&lt;/p&gt;

&lt;p&gt;✅ H2 support with MySQL production configuration&lt;/p&gt;

&lt;p&gt;✅ One-line website integration&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Admin Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of hardcoding prompts inside the application, administrators can configure everything from the dashboard.&lt;/p&gt;

&lt;p&gt;They can update:&lt;/p&gt;

&lt;p&gt;Company name&lt;br&gt;
Greeting message&lt;br&gt;
Brand color&lt;br&gt;
OpenAI API key&lt;br&gt;
Knowledge base&lt;br&gt;
Notification email&lt;/p&gt;

&lt;p&gt;Changes take effect immediately without restarting the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Didn't Use RAG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One interesting design decision was intentionally not implementing Retrieval-Augmented Generation (RAG).&lt;/p&gt;

&lt;p&gt;Instead, administrators maintain a simple knowledge base that is included in the AI's system prompt.&lt;/p&gt;

&lt;p&gt;For small and medium-sized businesses, this approach keeps deployment extremely simple while still delivering accurate responses.&lt;/p&gt;

&lt;p&gt;If the project grows, adding vector search later is straightforward.&lt;/p&gt;

&lt;p&gt;Sometimes simplicity is the better engineering decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human Handoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI can't answer everything.&lt;/p&gt;

&lt;p&gt;Whenever visitors need human assistance, they can submit their email.&lt;/p&gt;

&lt;p&gt;The system:&lt;/p&gt;

&lt;p&gt;Stores the lead in the database&lt;br&gt;
Sends an email notification (if SMTP is configured)&lt;br&gt;
Lets administrators continue the conversation manually&lt;/p&gt;

&lt;p&gt;This ensures users never hit a dead end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building the OpenAI integration wasn't actually the hardest part.&lt;/p&gt;

&lt;p&gt;The real engineering challenges were:&lt;/p&gt;

&lt;p&gt;Designing a flexible architecture&lt;br&gt;
Authentication and authorization&lt;br&gt;
Conversation persistence&lt;br&gt;
Prompt management&lt;br&gt;
Making the widget framework-independent&lt;br&gt;
Creating an admin experience that non-developers can use&lt;/p&gt;

&lt;p&gt;Those pieces ended up being much more interesting than simply calling an AI API.&lt;/p&gt;

&lt;p&gt;Things I Intentionally Left Out&lt;/p&gt;

&lt;p&gt;Every project needs boundaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I intentionally skipped:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Multi-tenancy&lt;br&gt;
Stripe subscriptions&lt;br&gt;
Vector databases&lt;br&gt;
Multiple AI providers&lt;br&gt;
Complex AI orchestration&lt;/p&gt;

&lt;p&gt;The goal was to build a clean, understandable codebase that developers can deploy quickly and extend however they like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm considering adding:&lt;/p&gt;

&lt;p&gt;Streaming AI responses&lt;br&gt;
Multiple AI providers&lt;br&gt;
RAG support&lt;br&gt;
File uploads&lt;br&gt;
Conversation analytics&lt;br&gt;
Multi-tenant architecture&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This project reminded me that building AI products isn't just about connecting to an LLM.&lt;/p&gt;

&lt;p&gt;The real engineering happens around it:&lt;/p&gt;

&lt;p&gt;authentication&lt;br&gt;
configuration&lt;br&gt;
deployment&lt;br&gt;
usability&lt;br&gt;
persistence&lt;br&gt;
developer experience&lt;/p&gt;

&lt;p&gt;Those are the parts that transform an API call into a real product.&lt;/p&gt;

&lt;p&gt;I'd love to hear how you're building AI applications with Java or Spring Boot, and what features you would add to a self-hosted support widget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interested in the Full Project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built this as a complete, production-ready Spring Boot project. If you'd like the full source code, setup guide, and deployment instructions, you can find it here:&lt;/p&gt;

&lt;p&gt;👉(&lt;a href="https://swarnalata25.gumroad.com/l/supportai-springboot" rel="noopener noreferrer"&gt;https://swarnalata25.gumroad.com/l/supportai-springboot&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I'm also building more self-hosted Java &amp;amp; Spring Boot products, so feedback and suggestions are always welcome.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
