A Modern Angular + Spring Boot Template for human and AI-Assisted Development
TL;DR
I created a reusable Angular 22 and Spring Boot 4 template with Java 25, PostgreSQL, Flyway, OpenAPI, Docker, generated Angular API clients and project conventions that make the application easier to maintain by humans and AI coding agents.
Here you have the link: https://github.com/marco76/spring-angular-template
From basic to quality setup
In the last years I created many Angular + Java applications and I wanted to share the experience of the initial setup I created and updated some strategies: e.g.https://www.marmo.dev/deploy-java-angular-one/ at the time the problem was to find a suitable setup, the quick demo on YouTube had more than 10k views and many developers reached me asking help and information.
The goal at the time was to have an example of a basic architecture working. Maven was the orchestrator responsible to compile and build the different layers.
Now AI helps with this and we can go to the next step: build a startup template that is more powerful and it helps maintainig good standards and quality of the code. This is can be used by human developers or AI agents.
The goal is simple: start a professional Angular and Spring Boot application without losing the first hours or days on the same decisions every time and let it grow trying to maintain consistency and quality.
flowchart LR
Browser["Browser"]
subgraph Frontend["Angular"]
UI["Standalone components"]
AuthInterceptor["authCredentialsInterceptor"]
ErrorInterceptor["httpErrorInterceptor"]
end
subgraph Backend["Spring Boot"]
Security["Security filter chain"]
Controllers["Controllers"]
Services["Services"]
Repos["Repositories"]
ErrorHandler["GlobalExceptionHandler"]
end
DB[("PostgreSQL / H2")]
Browser --> UI
UI --> AuthInterceptor
AuthInterceptor --> ErrorInterceptor
ErrorInterceptor -- "/api/**" --> Security
Security --> Controllers
Controllers --> Services
Services --> Repos
Repos --> DB
Controllers -. "exceptions" .-> ErrorHandler
Security -. "access denied / unauthenticated" .-> ErrorHandler
ErrorHandler -. "ApiError JSON" .-> ErrorInterceptor
No more a single JAR / WAR
The single fat JAR that contains Angular and Java presents many advantages, but the enterprise reality can require separate deployements (e.g. one frontend instance and multiple backend) or let the build pipeline create a Docker with the merge of the backend and frontend.
In the past we tried to have a full artifact, now with Kubernetes we tend to separate the layers. Build a fat JAR is simply an extra step.
With this architecture:
In development, Angular and Spring Boot can run separately. In Docker, Nginx serves the Angular build and proxies API calls to Spring Boot. PostgreSQL runs as its own service.
This is closer to what you probably see in production.
There is no universal best solution.
If your team deploys a single artifact to a Java application server, the one-JAR or WAR approach can be the correct one.
The stack
This template uses:
- Angular 22
- Angular Material
- Standalone Angular components
- Strict TypeScript
- Spring Boot 4.1
- Java 25
- PostgreSQL
- H2 for lightweight local development
- Flyway migrations
- Spring Security
- Spring Validation
- Spring Actuator
- OpenAPI
- A generated Angular API client
- Docker and Nginx for the local production-like stack
The versions will be updated using the latest available versions.
Probably I'll use the latest Java even if it's not LTS ... change it if you want to use this template for a serious project.
Create a new project
From the template directory:
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub
This creates a new project, replaces the Java package and application name, initializes Git, and installs the Angular dependencies.
You can also choose the initial UI and theme:
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub --ui=basic
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub --ui=minimal
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub --theme=ft
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub --theme=gl
The generated application includes three themes. The initial one can be selected when the project is created, and later changed from the admin page.
Run the application locally
The easiest local mode is Docker:
./scripts/deploy-local.sh up
This starts:
- PostgreSQL
- Spring Boot
- Angular served by Nginx
Then open:
http://localhost:4200
The backend health endpoint is available here:
http://localhost:8080/actuator/health
For local development, there is also an interactive launcher:
./scripts/dev.sh
It can start:
- the full Docker stack
- Spring Boot with H2 and Angular dev server
- Spring Boot against a local PostgreSQL and Angular dev server
The PostgreSQL mode is my favorite for serious development. It keeps the backend running natively with Spring Boot DevTools, but still uses a real PostgreSQL database.
docker compose up -d postgres
./scripts/dev.sh postgres
This gives a fast inner loop without pretending that H2 is PostgreSQL.
What is already included?
The template contains a small but useful application shell.
There is a home page, an admin page, HTTP Basic authentication for local development, database-backed users, and a basic admin user management UI.
The default local users are:
admin / admin
user / user
Of course, these are only local starter credentials. Replace them before using the project as the base for a real application.
The backend already follows a feature-based structure:
feature/
FeatureController.java
FeatureService.java
db/
FeatureRepository.java
FeatureEntity.java
model/
FeatureResponse.java
types/
FeatureStatus.java
Controllers expose request and response models. Services own transactions and business decisions. Repositories and entities stay in the persistence layer.
This is not revolutionary, but it avoids the classic empty-project problem where the first real feature invents the architecture by accident.
API contract
The backend owns the API contract.
OpenAPI is generated from Spring Boot, and the Angular client is generated from that contract.
The rule is simple: Angular should not duplicate backend models manually.
When an endpoint changes:
./scripts/generate-api.sh
The generated Angular client is committed with the rest of the change, so the frontend can build without a running backend.
This is a choice, I usually see and prefer to have manually generated models, but sometimes the application is so complex that is simply not possible to do this. Again, we try to have an 'enterprise' template, the enterprise project is more restrictive than many internal projects.
The template also standardizes API errors. Spring Security errors, validation errors, and application errors use the same JSON shape, and Angular normalizes them in one interceptor.
Database migrations
Flyway owns the schema.
Migrations live here:
backend/src/main/resources/db/migration
Example:
V1__initial_schema.sql
V2__create_app_user.sql
Local sample data and automated test fixtures are kept separate from schema migrations. This is important. A migration should describe the database structure, not silently inject local development data into production.
Built for AI-assisted development
This template also includes something I now consider important: instructions for coding agents.
There are architecture notes, conventions, project state, API contract documentation, and task checklists under .agent/tasks.
The idea is that your Agent will try to follow these instructions, but don't trust them the result is not deterministic, you will need to read the generated result and validate it.
We try to explain AI agent what kind of architecture we want. Which package structure should be used? Where do DTOs live? How are migrations named? When should the OpenAPI client be regenerated? Which checks must run before a change is done?
Without these rules, agents improvise. Sometimes they improvise well. Sometimes they create a small museum of technical debt.
With explicit rules, they become much more predictable.
I added ArchUnit to do a static check of the generated code structure. You can easily add your own rules. This is another quality check to be sure that the developer (human or not) follows the design.
Checks
The template includes scripts for the usual verification steps:
./scripts/check-backend.sh
./scripts/check-frontend.sh
./scripts/check.sh
./scripts/smoke.sh
./scripts/doctor.sh
doctor.sh is especially useful after generating a new project. It checks for leftover placeholders, required tooling, and common setup problems.
Optional MCP support
There is optional Spring AI / MCP support, but it is disabled by default.
This is intentional to avoid exposing runtime MCP endpoints without authentication.
If you need it:
./create-project.sh invoice-hub com.acme.invoice ../invoice-hub --mcp
Then read the MCP setup documentation before exposing anything.
Which AI Agent?
I tried to have a template that is generic enough to be used with the most common AI agent. Claude plays with its own rules for this reason there is a re-direct that should help the multi AI compatibility and avoid the duplication of the instructions.
Spring Tools MCP plugin is currently compatible only with Claude, it won't work with other AI agents.
Which IDE?
Technically you don't need an IDE to use the template, but there are some optimisations prepared for IntellJ IDEA (e.g. shortcut starter).
Conclusion
This is a starting point for a new project without re-inventing the wheel each time. I didn't use it often, it was a small project for a demo. I will try to improve it with the latests AI discoveries.
I'm thinking to add some features like WebSockets, file uploads, OAuth, CI/CD and Kubernetes. I use these features in real-world project, but I know that many project simply don't need them.