GitHub · LinkedIn · About · YouTube
Last updated by Kindson Munonye — July 1, 2026
📚 Tutorial hubs:
AI Developer Tutorials ·
Spring Boot ·
Angular ·
CRUD + REST guide
Source code: munonye-ai-chat-spring-angular on GitHub
Estimated reading time: 12–15 minutes · Last updated: July 1, 2026
The fastest way to ship AI in 2026 is not a greenfield chatbot — it is extending software you already run. If you completed our Angular CRUD tutorial series or the complete CRUD guide, you have FriendsAPI (Spring Boot) and FriendsUI (Angular). We will add an AI assistant that understands your domain.
Part of the AI Developer Tutorials hub. Builds on Spring AI agents with tool calling.
Time: one weekend (~6–8 hours) · Prerequisites: CRUD app running locally, OpenAI API key
Table of contents

Before you start {#before-you-start}
Confirm your stack matches the CRUD series:
| App | Port | Tech |
|---|---|---|
| FriendsAPI | 9001 | Spring Boot, JPA, /api/friends |
| FriendsUI | 9002 | Angular 19, HttpClient, standalone components |
Refresh Angular 19 patterns in Part 1 setup if needed. For forms in the AI panel, reuse patterns from reactive forms validation (M6).

Architecture: CRUD + AI layer {#architecture}
FriendsUI (Angular)
├── Existing CRUD screens (unchanged)
└── NEW: AiAssistantPanel → POST /api/agent
FriendsAPI (Spring Boot)
├── Existing FriendController (/api/friends)
└── NEW: AgentController + FriendTools (@Tool)
└── FriendService (shared)
This mirrors the agent pattern from our Spring AI agents tutorial but grounded in your CRUD domain.

Saturday AM — Backend tools {#backend}
Add Spring AI to FriendsAPI pom.xml:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
Expose CRUD operations as tools — reuse your service:
@Component
public class FriendTools {
private final FriendService friendService;
public FriendTools(FriendService friendService) {
this.friendService = friendService;
}
@Tool(description = "List all friends with id, first name, and email")
public List<FriendSummary> listFriends() {
return friendService.findAll().stream()
.map(f -> new FriendSummary(f.getId(), f.getFirstName(), f.getEmail()))
.toList();
}
@Tool(description = "Find friends whose first name contains the search text")
public List<FriendSummary> searchFriendsByName(String namePart) {
return friendService.findAll().stream()
.filter(f -> f.getFirstName().toLowerCase().contains(namePart.toLowerCase()))
.map(f -> new FriendSummary(f.getId(), f.getFirstName(), f.getEmail()))
.toList();
}
@Tool(description = "Get friend details by numeric id")
public FriendSummary getFriendById(long id) {
return friendService.findById(id)
.map(f -> new FriendSummary(f.getId(), f.getFirstName(), f.getEmail()))
.orElse(new FriendSummary(id, "NOT_FOUND", ""));
}
public record FriendSummary(long id, String firstName, String email) {}
}
Saturday PM — Agent endpoint {#agent-endpoint}
@Configuration
public class AiConfig {
@Bean
ChatClient friendAgent(ChatClient.Builder builder, FriendTools tools) {
return builder
.defaultSystem("""
You help users manage their Friends database.
Use tools for all factual answers. Be concise.
If asked to modify data, explain which CRUD screen to use for now.
""")
.defaultTools(tools)
.build();
}
}
@RestController
@RequestMapping("/api/agent")
@CrossOrigin(origins = "http://localhost:9002")
public class AgentController {
private final ChatClient agent;
public AgentController(ChatClient friendAgent) {
this.agent = friendAgent;
}
@PostMapping
public AgentResponse ask(@RequestBody AgentRequest req) {
String answer = agent.prompt().user(req.message()).call().content();
return new AgentResponse(answer);
}
public record AgentRequest(String message) {}
public record AgentResponse(String answer) {}
}
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4o-mini
New to Spring AI? Start with M7-A first REST endpoint.
Sunday AM — Angular chat panel {#angular-panel}
Add a floating panel to FriendsUI — no routing changes to CRUD pages:
// ai-assistant.component.ts
import { Component, inject, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-ai-assistant',
standalone: true,
imports: [FormsModule],
template: `
<button type="button" class="fab" (click)="open.set(!open())">AI</button>
@if (open()) {
<div class="panel">
<h3>Friends Assistant</h3>
@for (m of messages(); track $index) {
<p [class]="m.role">{{ m.text }}</p>
}
<form (ngSubmit)="send()">
<input [(ngModel)]="input" name="q" placeholder="Ask about your friends…" />
<button type="submit">Send</button>
</form>
</div>
}
`,
styles: [`
.fab { position: fixed; bottom: 24px; right: 24px; z-index: 1000;
border-radius: 50%; width: 56px; height: 56px; font-weight: bold; }
.panel { position: fixed; bottom: 90px; right: 24px; width: 340px;
max-height: 420px; overflow: auto; background: #fff;
border: 1px solid #ccc; border-radius: 12px; padding: 16px;
box-shadow: 0 8px 24px rgba(0,0,0,.12); z-index: 1000; }
.user { color: #1565c0; } .bot { color: #2e7d32; }
`],
})
export class AiAssistantComponent {
private http = inject(HttpClient);
open = signal(false);
messages = signal<{ role: string; text: string }[]>([]);
input = '';
send(): void {
const q = this.input.trim();
if (!q) return;
this.messages.update(m => [...m, { role: 'user', text: q }]);
this.input = '';
this.http.post<{ answer: string }>('http://localhost:9001/api/agent', { message: q })
.subscribe({
next: res => this.messages.update(m => [...m, { role: 'bot', text: res.answer }]),
error: () => this.messages.update(m => [...m, { role: 'bot', text: 'Agent unavailable.' }]),
});
}
}
Import AiAssistantComponent in your root AppComponent. For streaming UX later, see Angular 19 chat UI (M7-B).
Sunday PM — Wire up and test {#wire-up}
Terminal 1 — API:
cd friends-api
export OPENAI_API_KEY=sk-...
./mvnw spring-boot:run
Terminal 2 — UI:
cd friends-ui
ng serve --port 9002
Try these prompts:
| User says | Expected behavior |
|---|---|
| “How many friends do I have?” | listFriends → count |
| “Find friends named Ann” | searchFriendsByName |
| “Show details for friend 3” | getFriendById |
Before production {#production}
| Step | Guide |
|---|---|
JWT + rate limits on /api/agent | Secure AI features |
| Ground answers in docs | Documentation RAG bot |
| Local LLM option | Ollama + Spring Boot |
| Full AI learning path | Full-stack AI starter kit |
Related hubs: Angular tutorials · Spring Boot tutorials · AI Developer Tutorials
Source code: munonye-ai-chat-spring-angular on GitHub
- ← Spring AI agents + tool calling
- ← CRUD complete guide
- → MCP for developers (next advanced step)
Related:
AI Developer Tutorials hub ·
Angular CRUD Part 1 ·
Spring AI overview
