<?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>Testing an AI Code Reviewer With an Intentionally Failing JUnit Test</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Thu, 29 Oct 2026 17:07:39 +0000</pubDate>
      <link>https://dev.to/sweety717/testing-an-ai-code-reviewer-with-an-intentionally-failing-junit-test-529f</link>
      <guid>https://dev.to/sweety717/testing-an-ai-code-reviewer-with-an-intentionally-failing-junit-test-529f</guid>
      <description>&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%2Fvdx2sufog2zefsns3pjq.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%2Fvdx2sufog2zefsns3pjq.png" alt=" " width="800" height="452"&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%2F1ugo0q17j7jle4guf5ip.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%2F1ugo0q17j7jle4guf5ip.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
An AI code reviewer should do more than identify suspicious code. It should also report validation results accurately.&lt;/p&gt;

&lt;p&gt;For this test, I added the following JUnit assertion to a GitHub pull request:&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/test"&gt;@test&lt;/a&gt;&lt;br&gt;
void shouldDetectIncorrectExpectedValue() {&lt;br&gt;
    assertEquals(5, 2 + 2);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The test is intentionally incorrect.&lt;/p&gt;

&lt;p&gt;What CodeGuard AI reported:&lt;/p&gt;

&lt;p&gt;Test execution: FAILED&lt;/p&gt;

&lt;p&gt;Tests executed: 1&lt;/p&gt;

&lt;p&gt;Tests failed: 1&lt;/p&gt;

&lt;p&gt;Expected: 5&lt;/p&gt;

&lt;p&gt;Actual: 4&lt;/p&gt;

&lt;p&gt;Suggested fix: change the expected value to 4&lt;/p&gt;

&lt;p&gt;It also identified the failing assertion in the changed file.&lt;/p&gt;

&lt;p&gt;One finding isn't enough to establish overall reliability, so I'm testing CodeGuard against 100 scenarios covering failure detection, test-result evidence, false positives, merge policies, and more.&lt;/p&gt;

&lt;p&gt;The next question is just as important: should a failing test automatically block a merge?&lt;/p&gt;

&lt;p&gt;I'm building CodeGuard AI with Java 21 and Spring Boot. The source code is available on Gumroad.&lt;/p&gt;

&lt;p&gt;What behavior would you expect from an AI reviewer when a test suite fails?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>codereview</category>
      <category>java</category>
    </item>
    <item>
      <title>My AI Code Reviewer Found the Failure. Is Its Fix Actually Safe?</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Tue, 27 Oct 2026 09:39:12 +0000</pubDate>
      <link>https://dev.to/sweety717/building-codeguard-ai-in-public-the-ai-fix-that-made-a-failing-test-pass-eg7</link>
      <guid>https://dev.to/sweety717/building-codeguard-ai-in-public-the-ai-fix-that-made-a-failing-test-pass-eg7</guid>
      <description>&lt;p&gt;I’m testing CodeGuard AI, my AI-powered GitHub PR reviewer, and today I caught an interesting failure.&lt;/p&gt;

&lt;p&gt;Here’s the test scenario.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The original failing test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Discount calculation is incorrect"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test expects &lt;code&gt;2&lt;/code&gt;, but the actual result is &lt;code&gt;1&lt;/code&gt;. So it fails, as intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CodeGuard detected the failure
&lt;/h3&gt;

&lt;p&gt;Good news: CodeGuard correctly identified that the test was failing.&lt;/p&gt;

&lt;p&gt;But then came the problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The suggested fix
&lt;/h3&gt;

&lt;p&gt;The AI suggested changing the assertion to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Discount calculation is incorrect"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the test passes.&lt;/p&gt;

&lt;p&gt;But did we fix the underlying problem?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No. We changed the expectation to match the actual result.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The test no longer checks whether the code produces the intended result. It simply confirms that &lt;code&gt;1&lt;/code&gt; equals &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What this tells me
&lt;/h3&gt;

&lt;p&gt;Detecting a failing test is not enough. An AI reviewer must also ensure that its suggested fix preserves the test’s original intent.&lt;/p&gt;

&lt;p&gt;I’ve logged this as a bug and will address it after completing the current testing batches. For now, I’m continuing to test the other features and record the failures before fixing them together.&lt;/p&gt;

&lt;p&gt;That’s the reality of building in public: sometimes the most useful update is what your own product gets wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you want CodeGuard to validate before allowing an AI-suggested test fix?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm building CodeGuard AI for developers who want more trustworthy AI-assisted code reviews.&lt;/p&gt;

&lt;p&gt;If you'd like to explore the source code, you can find it here: &lt;strong&gt;&lt;a href="https://javacoder716.gumroad.com/l/codeguard-ai" rel="noopener noreferrer"&gt;CodeGuard AI on Gumroad&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm continuing to test it, document the failures, and improve it based on what I learn.&lt;/p&gt;

&lt;h1&gt;
  
  
  BuildInPublic #Java #SpringBoot #AI #CodeReview
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>How Do You Find Your First Buyers for a Source-Code Product?</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Mon, 26 Oct 2026 11:00:23 +0000</pubDate>
      <link>https://dev.to/sweety717/how-do-you-find-your-first-buyers-for-a-source-code-product-564l</link>
      <guid>https://dev.to/sweety717/how-do-you-find-your-first-buyers-for-a-source-code-product-564l</guid>
      <description>&lt;p&gt;I’ve built two self-hosted developer products and listed them on Gumroad, but I’m still figuring out how to reach people who will actually pay for them.&lt;/p&gt;

&lt;p&gt;One is CodeGuard AI, an AI-powered GitHub PR reviewer. The other is ResumeIQ AI, an AI resume analyzer.&lt;/p&gt;

&lt;p&gt;Both are sold as source code, not hosted SaaS products.&lt;/p&gt;

&lt;p&gt;I’m curious about the business side of building software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where do people find their first paying customers?&lt;/li&gt;
&lt;li&gt;Which channels have actually worked for selling source code?&lt;/li&gt;
&lt;li&gt;What do buyers expect beyond the code itself?&lt;/li&gt;
&lt;li&gt;Is it better to keep selling the source code or eventually turn the product into SaaS?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers who have sold source code, boilerplates, templates, or developer tools: &lt;strong&gt;what helped you get your first few sales?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’d especially appreciate real experiences and lessons from things that didn’t work. I want to learn how to build a sustainable business around software, not just keep shipping projects.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>freelance</category>
    </item>
    <item>
      <title>AI Can Find a Bug. But Can You Trust Its Fix?</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Sat, 24 Oct 2026 15:42:01 +0000</pubDate>
      <link>https://dev.to/sweety717/ai-can-find-a-bug-but-can-you-trust-its-fix-290f</link>
      <guid>https://dev.to/sweety717/ai-can-find-a-bug-but-can-you-trust-its-fix-290f</guid>
      <description>&lt;p&gt;AI coding tools are getting better every day. They can write functions, generate tests, review pull requests, and even suggest fixes in seconds.&lt;/p&gt;

&lt;p&gt;But there’s a problem I keep thinking about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if the AI identifies a real bug but gives you a fix that introduces another one?&lt;/strong&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;An AI reviewer flags a security vulnerability.&lt;/li&gt;
&lt;li&gt;It suggests a patch that looks convincing.&lt;/li&gt;
&lt;li&gt;The developer applies it.&lt;/li&gt;
&lt;li&gt;The code appears fine, but the fix is incomplete—or the tests have been changed to accommodate the bug.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now what?&lt;/p&gt;

&lt;p&gt;A green test suite doesn't automatically mean the bug is fixed. A confident explanation doesn't prove the patch is correct. And a suggested fix that looks good in a code diff still needs independent verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I'm exploring
&lt;/h2&gt;

&lt;p&gt;While building &lt;strong&gt;CodeGuard AI&lt;/strong&gt;, I've been exploring how to evaluate AI code reviews beyond simply counting the number of issues they detect.&lt;/p&gt;

&lt;p&gt;Some questions I'm trying to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can an AI reviewer distinguish real bugs from false positives?&lt;/li&gt;
&lt;li&gt;Can it identify incorrect test expectations?&lt;/li&gt;
&lt;li&gt;Does its suggested patch actually address the original problem?&lt;/li&gt;
&lt;li&gt;Can we verify a fix without letting the patch generator simply change the goalposts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm particularly interested in the gap between &lt;strong&gt;finding a problem&lt;/strong&gt; and &lt;strong&gt;proving that the proposed solution works&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's where I think developer tools have a lot of room to improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  I'd love to hear from other developers
&lt;/h2&gt;

&lt;p&gt;If you use AI coding assistants or AI-powered code reviewers, I'm curious about your experience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have you ever accepted an AI-generated fix that later caused another bug?&lt;/li&gt;
&lt;li&gt;Do you trust AI-generated patches, or do you always verify them independently?&lt;/li&gt;
&lt;li&gt;What would convince you that an AI code review is reliable enough to use in a real project?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm building in this space, so honest criticism and real-world examples would be especially valuable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the biggest thing stopping you from fully trusting AI-generated code?&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  discuss #ai #programming #webdev
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>java</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Do developers actually need an AI code reviewer? What features would make it worth paying for?</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Wed, 21 Oct 2026 10:00:23 +0000</pubDate>
      <link>https://dev.to/sweety717/do-developers-actually-need-an-ai-code-reviewer-what-features-would-make-it-worth-paying-for-30f5</link>
      <guid>https://dev.to/sweety717/do-developers-actually-need-an-ai-code-reviewer-what-features-would-make-it-worth-paying-for-30f5</guid>
      <description>&lt;h1&gt;
  
  
  Do developers actually need an AI code reviewer? What features would make it worth paying for?
&lt;/h1&gt;

&lt;p&gt;I'm exploring whether there's genuine demand for an AI code reviewer that goes beyond simply generating comments on GitHub pull requests.&lt;/p&gt;

&lt;p&gt;I'm building &lt;strong&gt;CodeGuard AI&lt;/strong&gt;, a Java 17 and Spring Boot-based AI code reviewer for GitHub PRs. Before spending more time developing it, I want honest feedback from developers, agency owners, and startup founders about whether this solves a problem worth paying for.&lt;/p&gt;

&lt;h3&gt;
  
  
  What CodeGuard AI already has
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI-powered PR reviews&lt;/strong&gt; to identify potential bugs and code-quality issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule-based security and code-quality checks&lt;/strong&gt; for common problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test-quality analysis&lt;/strong&gt; to identify issues such as trivial assertions, duplicate tests, and incorrect expectations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggested fixes and patch previews&lt;/strong&gt; to help developers understand potential corrections before applying them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository-impact analysis&lt;/strong&gt; to help identify potentially affected code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review history&lt;/strong&gt; to keep track of previous reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm currently auditing and improving the system, particularly around false positives, consistency between reviews, the reliability of suggested fixes, and validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  I'd like your honest feedback on a few things
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Is there genuine demand for a tool like this?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Would you use a dedicated AI code reviewer in your current workflow, or do existing tools and AI coding assistants already meet your needs?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What's missing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Looking at the features above, what would make this genuinely useful in your day-to-day work? What would you remove, add, or improve? For example, would you prioritize fewer false positives, better repository context, reliable automated fixes, security analysis, or something else?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What would you realistically pay?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a tool like this consistently saved time and caught meaningful issues, what pricing would make sense to you? Would you prefer per-developer pricing, a small-team subscription, usage-based pricing, or a free tier with paid upgrades?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What would make you trust it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before relying on an AI reviewer, what evidence would you need? For example, verified fixes, reproducible results, fewer irrelevant findings, or successful results on your own repositories?&lt;/p&gt;

&lt;p&gt;I'm not assuming that everyone needs another code review tool. If your current workflow works well, I'd genuinely like to understand why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you're a developer, freelancer, agency owner, or startup founder, I'd appreciate your perspective.&lt;/strong&gt; Your feedback will help me decide whether to continue investing in this and which features deserve priority.&lt;/p&gt;

&lt;p&gt;I'm looking for honest feedback, not validation for the sake of it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Before Optimizing Your Resume, Should You Trust the Job Posting?</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Mon, 19 Oct 2026 08:02:36 +0000</pubDate>
      <link>https://dev.to/sweety717/before-optimizing-your-resume-should-you-trust-the-job-posting-57pd</link>
      <guid>https://dev.to/sweety717/before-optimizing-your-resume-should-you-trust-the-job-posting-57pd</guid>
      <description>&lt;p&gt;When applying for jobs, we usually focus on one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can I make my resume a better match for this job?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We optimize keywords, improve our summaries, highlight relevant skills, and prepare for interviews.&lt;/p&gt;

&lt;p&gt;But there's another question we don't always ask:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this job posting worth our time and personal information in the first place?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question inspired me to build a new feature in ResumeIQ AI called &lt;strong&gt;Job Posting Health&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with focusing only on resumes
&lt;/h2&gt;

&lt;p&gt;A well-written job description can still contain warning signs.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A recruiter asks candidates to pay a registration or verification fee.&lt;/li&gt;
&lt;li&gt;A posting pressures applicants to act immediately without a reasonable explanation.&lt;/li&gt;
&lt;li&gt;Candidates are told they must purchase equipment from a specified seller.&lt;/li&gt;
&lt;li&gt;The role description and hiring requirements contain suspicious inconsistencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every unusual requirement means a job is fraudulent. However, these signals deserve closer investigation before someone shares sensitive information or spends hours preparing an application.&lt;/p&gt;

&lt;p&gt;Resume optimization tools generally focus on improving the candidate's side of the process. I wanted to explore the other side: evaluating the opportunity itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Job Posting Health
&lt;/h2&gt;

&lt;p&gt;I implemented Job Posting Health in ResumeIQ AI to analyze a pasted job description and highlight potential warning signs.&lt;/p&gt;

&lt;p&gt;The feature produces a health assessment and identifies signals that may deserve further investigation.&lt;/p&gt;

&lt;p&gt;During testing, I used a sample posting containing several suspicious elements, including a registration fee, pressure to act quickly, and a mandatory company-approved laptop purchase.&lt;/p&gt;

&lt;p&gt;The feature flagged these warning signs rather than treating the posting as an ordinary job opportunity.&lt;/p&gt;

&lt;p&gt;The goal isn't to claim that an algorithm can definitively determine whether every job is legitimate. It's to give job seekers specific reasons to pause, investigate, and make a more informed decision.&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%2Fct2o4cgp5om828nb5qc9.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%2Fct2o4cgp5om828nb5qc9.png" alt=" " width="800" height="377"&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%2Fh41cksycohdi88g2ua5b.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%2Fh41cksycohdi88g2ua5b.png" alt=" " width="800" height="430"&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%2Frrt5vp4x47ecgzxv6p3y.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%2Frrt5vp4x47ecgzxv6p3y.png" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why I think this feature matters
&lt;/h2&gt;

&lt;p&gt;Job seekers already spend considerable effort tailoring applications.&lt;/p&gt;

&lt;p&gt;If a posting is suspicious, that effort may be wasted—and sharing personal information can create additional risks.&lt;/p&gt;

&lt;p&gt;I believe job-search tools should help people make better decisions before applying, not just help them optimize their resumes after choosing a job.&lt;/p&gt;

&lt;p&gt;That's the thinking behind Job Posting Health.&lt;/p&gt;
&lt;h2&gt;
  
  
  Another feature: Resume Freshness
&lt;/h2&gt;

&lt;p&gt;I also implemented Resume Freshness, which looks at the evidence in a resume for the skills mentioned in a job description and highlights areas where recent evidence may be missing.&lt;/p&gt;

&lt;p&gt;For example, listing a technology is different from demonstrating recent experience with it through a project, practical work, or relevant learning.&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%2Fkpsmbun3turx2st6bu7c.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%2Fkpsmbun3turx2st6bu7c.png" alt=" " width="799" height="398"&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%2Ffnty7gx7rwc4m9yg43gi.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%2Ffnty7gx7rwc4m9yg43gi.png" alt=" " width="800" height="428"&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%2Fvdddzglqs76dto10oivk.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%2Fvdddzglqs76dto10oivk.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Together, these features explore two complementary questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Job Posting Health:&lt;/strong&gt; Are there warning signs worth investigating before applying?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resume Freshness:&lt;/strong&gt; Does my resume demonstrate recent, relevant evidence of the skills this role requires?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;I'm continuing to develop ResumeIQ AI and explore how it can provide more useful information to job seekers.&lt;/p&gt;

&lt;p&gt;One thing I've learned while building it is that a feature doesn't need to be complicated to address a meaningful problem. Sometimes, asking a different question is what makes it useful.&lt;/p&gt;

&lt;p&gt;I'd be interested to hear from other developers and job seekers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When evaluating a job opportunity, what warning signs do you check before applying? And what would make you trust a tool that analyzes job postings?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ResumeIQ AI is available as a source-code product for developers interested in exploring or customizing the application.&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://javacoder716.gumroad.com/l/resumeiq-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%2Fy8iqcd6td1coqdc8i73uddxdl2kn" height="605" class="m-0" width="984"&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://javacoder716.gumroad.com/l/resumeiq-ai" rel="noopener noreferrer" class="c-link"&gt;
            ResumeIQ AI — AI Resume Analyzer &amp;amp; ATS SaaS Starter | Spring Boot Source Code
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            BUILD YOUR OWN AI RESUME ANALYZER SAAS Launch your own AI-powered resume analysis platform without building everything from scratch. ResumeIQ AI is a...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic-files.gumroad.com%2F4fmugce06aihfnl69grlvwrywepb" width="400" height="133"&gt;
          javacoder716.gumroad.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>java</category>
      <category>springboot</category>
      <category>ai</category>
      <category>career</category>
    </item>
    <item>
      <title>A Green Test Suite Can Still Hide a Broken PR: 5 Questions to Ask Before Merging</title>
      <dc:creator>JavaCoder7</dc:creator>
      <pubDate>Sat, 17 Oct 2026 16:27:50 +0000</pubDate>
      <link>https://dev.to/sweety717/a-green-test-suite-can-still-hide-a-broken-pr-5-questions-to-ask-before-merging-fe1</link>
      <guid>https://dev.to/sweety717/a-green-test-suite-can-still-hide-a-broken-pr-5-questions-to-ask-before-merging-fe1</guid>
      <description>&lt;p&gt;AI coding assistants can write implementation code and tests in minutes. The problem is that both can look correct while the behavior that matters remains untested.&lt;/p&gt;

&lt;p&gt;A passing test suite is useful evidence, but it isn't proof that a change is correct.&lt;/p&gt;

&lt;p&gt;I've been thinking about this problem while building a Java-focused, AI-powered pull request reviewer. These are five questions I believe developers should ask before approving a PR, especially when AI helped write the code or its tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What behavior is this test actually verifying?
&lt;/h2&gt;

&lt;p&gt;Start with the expected behavior, not the number of assertions.&lt;/p&gt;

&lt;p&gt;Imagine a service that should reject a payment when the account has insufficient funds. A test might call the service and verify that it returns a response.&lt;/p&gt;

&lt;p&gt;But what if the test never checks whether the payment was rejected?&lt;/p&gt;

&lt;p&gt;The test can execute successfully without verifying the important business rule.&lt;/p&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What behavior should this test protect?&lt;/li&gt;
&lt;li&gt;What result would prove that behavior?&lt;/li&gt;
&lt;li&gt;Would the test fail if the behavior were broken?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot answer these questions, the test may provide less confidence than its green status suggests.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Could this test pass without checking anything meaningful?
&lt;/h2&gt;

&lt;p&gt;Consider this JUnit example:&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/test"&gt;@test&lt;/a&gt;&lt;br&gt;
void shouldRejectInvalidPayment() {&lt;br&gt;
    paymentService.processPayment(invalidPayment);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assertTrue(true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;The test passes as long as execution reaches the assertion. It doesn't establish that the payment was rejected.&lt;/p&gt;

&lt;p&gt;A more meaningful test would verify the expected outcome, using the appropriate assertion for the application's behavior.&lt;/p&gt;

&lt;p&gt;For example, if the contract requires an exception:&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/test"&gt;@test&lt;/a&gt;&lt;br&gt;
void shouldRejectInvalidPayment() {&lt;br&gt;
    assertThrows(&lt;br&gt;
        InvalidPaymentException.class,&lt;br&gt;
        () -&amp;gt; paymentService.processPayment(invalidPayment)&lt;br&gt;
    );&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This is only an illustration. The correct assertion depends on the actual application contract.&lt;/p&gt;

&lt;p&gt;The important principle is simple: an assertion should verify the behavior the test claims to protect.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Are mocks hiding the behavior we need to verify?
&lt;/h2&gt;

&lt;p&gt;Mocks are valuable when testing dependencies, failure conditions, and isolated units of code. But excessive mocking can make a test appear meaningful while avoiding the behavior that matters.&lt;/p&gt;

&lt;p&gt;Suppose a test claims to verify that an order is saved correctly, but it mocks the repository and only verifies that &lt;code&gt;save()&lt;/code&gt; was called.&lt;/p&gt;

&lt;p&gt;That may establish that a method was invoked. It doesn't necessarily establish that the order was persisted correctly or that the resulting state is correct.&lt;/p&gt;

&lt;p&gt;Before approving a heavily mocked test, ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the test checking an outcome or just an interaction?&lt;/li&gt;
&lt;li&gt;Is the mocked dependency the behavior being tested?&lt;/li&gt;
&lt;li&gt;Would an incorrect implementation still satisfy the assertions?&lt;/li&gt;
&lt;li&gt;Should an integration test verify the real interaction between components?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't remove mocks indiscriminately. Choose the test boundary that matches the behavior you're trying to protect.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Does the test cover the change described in the PR?
&lt;/h2&gt;

&lt;p&gt;A PR can change behavior without changing the test that originally covered it.&lt;/p&gt;

&lt;p&gt;For example, a developer might change the conditions under which a user can access a resource. The existing test may still verify the successful access path while failing to check the newly introduced restriction.&lt;/p&gt;

&lt;p&gt;Compare the change with the tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which behavior changed?&lt;/li&gt;
&lt;li&gt;Which existing tests exercise that behavior?&lt;/li&gt;
&lt;li&gt;What new failure scenario could the change introduce?&lt;/li&gt;
&lt;li&gt;Are the expected outcomes explicit?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also where repository context matters. The affected behavior might involve callers or related files that aren't part of the diff.&lt;/p&gt;

&lt;p&gt;A reviewer should consider those relationships rather than treating each changed line as an isolated unit.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Would the test catch a deliberately broken implementation?
&lt;/h2&gt;

&lt;p&gt;This is a useful thought experiment.&lt;/p&gt;

&lt;p&gt;Imagine the implementation contains a defect that violates the requirement. Would the test fail?&lt;/p&gt;

&lt;p&gt;If the answer is no, the test may not protect that requirement.&lt;/p&gt;

&lt;p&gt;Mutation testing takes this idea further by making deliberate changes to the implementation and checking whether the tests detect them. It can provide stronger evidence than simply counting assertions, although it has its own limitations and costs.&lt;/p&gt;

&lt;p&gt;You don't need a full mutation-testing setup to start asking the question during code review. But actually running tests against controlled mutations is a separate validation step, not something a normal passing test run proves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical takeaway
&lt;/h2&gt;

&lt;p&gt;Before merging a PR, especially one produced with AI assistance, ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the test verify the intended behavior?&lt;/li&gt;
&lt;li&gt;Could it pass without a meaningful assertion?&lt;/li&gt;
&lt;li&gt;Are mocks hiding the behavior that matters?&lt;/li&gt;
&lt;li&gt;Do the tests cover the changed behavior and relevant regression scenarios?&lt;/li&gt;
&lt;li&gt;Would the tests detect a broken implementation?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These checks won't guarantee that every defect is caught. They can, however, help identify tests that create confidence without providing enough evidence.&lt;/p&gt;

&lt;p&gt;AI can help write code and tests faster. The review process still needs to establish what those tests actually prove.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I'm building CodeGuard AI, a self-hosted AI-powered pull request reviewer for GitHub. It reviews PR changes alongside repository context and supports custom team review rules. It does not currently run mutation testing or guarantee detection of every weak test assertion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javacoder716.gumroad.com/l/codeguard-ai?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=codeguard_ai&amp;amp;utm_content=test_quality_article" rel="noopener noreferrer"&gt;Learn more about CodeGuard AI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>java</category>
      <category>testing</category>
    </item>
    <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>
  </channel>
</rss>
