Build the SCM Backend Foundation
Build a Spring Boot and MySQL API for database-backed product inventory.
Introduction
30 Second Summary
A stock count is only useful when people can trust where it came from. Hard-coded sample values fall apart as soon as real inventory starts changing.
In this project, you will build a Supply Chain Management backend foundation with Spring Boot and MySQL. A browser request will return product inventory stored in the database.
What You'll Build
Your browser shows the seeded Safety Gloves inventory as JSON from MySQL.
By the end of this project, you'll have:
- A status endpoint that shows {"status":"SCM backend is running"} in your browser.
- A database-backed products endpoint that returns the seeded inventory through Spring Data JPA as JSON.
- A scoped first release recorded in README.md. A sanitized Git history keeps the local database password uncommitted.
- Secret Mission: Add a low-stock endpoint whose threshold is supplied by the caller.
Are there any prerequisites?
This project assumes you have completed the Product Catalog REST API.
You also need the listed development tools installed on Windows. Step 1 verifies their versions before you build.
Before We Start
Before the hands-on work begins, define a focused first release so the project stays manageable. You are building a database-backed product inventory foundation for a Supply Chain Management system while leaving warehouses, suppliers, purchase orders, receiving, security, testing, and React for future work.
Verify and Scaffold Your Windows Project
Your SCM foundation is about to become a real Spring Boot project. Spring Boot 4.1.1 requires Java 17 or later.
Checking the local toolchain now prevents version failures during development. You will finish with a Maven scaffold that builds successfully.
In this step, get ready to:
- Confirm the installed development tools.
- Generate the Spring Boot Maven scaffold.
- Import the scaffold into IntelliJ IDEA and build it.
Verify the installed tools
A reliable toolchain starts with visible version checks. The JDK compiles your application against the Java version required by Spring Boot.
- Press the Windows key to open Windows search.
- Type Command Prompt into the search field.
- Press Enter to open Windows Command Prompt.
- Check the installed Java version by running this command:
java -version
What does this command check?
The command prints the Java runtime release available through your Windows path. Spring Boot 4.1.1 needs a major version of 17 or later.
✔️ I see a supported Java version
Your Java runtime meets the Spring Boot requirement. That removes the first major source of build failures.
ⓧ I see an older Java version
Your current JDK is below 17. Upgrade it before generating the project.
- Open the official Oracle JDK installation guide.
- Follow its link to the Java downloads page.
- Download the Windows x64 installer for JDK 17 or later.
- Run the downloaded installer with administrator privileges.
- Follow the installer instructions to complete the upgrade.
- Close the current Command Prompt window.
- Open a fresh Command Prompt through Windows search.
- Run the Java version check above again.
ⓧ Command not found
Windows cannot currently find a Java runtime. Install a supported JDK before continuing.
- Open the official Oracle JDK installation guide.
- Follow its link to the Java downloads page.
- Download the Windows x64 installer for JDK 17 or later.
- Run the downloaded installer with administrator privileges.
- Follow the installer instructions to complete the installation.
- Open a fresh Command Prompt through Windows search.
- Run the Java version check above again.
Your source history depends on Git. Its version check confirms that Windows can run the command you will use for commits later.
- Check the Git installation in the same Command Prompt window by running:
git --version
What does this command check?
The command prints the installed Git release. A version result confirms that Git is available from Command Prompt.
✔️ I see a Git version
Git is ready to track the SCM foundation when you reach the commit step.
ⓧ Command not found
Git needs to be installed before the project can be versioned.
- Download the installer from the official Git for Windows page.
- Run the downloaded installer.
- Follow the installer prompts to complete the installation.
- Close the current Command Prompt window.
- Open a fresh Command Prompt through Windows search.
- Run the Git version check above again.
Git still is not recognized?
A Command Prompt window opened before the installation cannot see the updated Windows path. Close every Command Prompt window before trying the check again.
Help me diagnose why Windows Command Prompt cannot find Git after installation.
The final tool check proves that MySQL Workbench can reach your local MySQL Server. The version query produces a response directly from the server.
- Press the Windows key to open Windows search.
- Type MySQL Workbench into the search field.
- Press Enter to open MySQL Workbench.
- Select your local server connection from the MySQL Workbench Home screen.
- Enter your local server password if MySQL Workbench requests it.
- Paste this version query into the SQL Query Tab:
SELECT VERSION();
What does this query check?
The query asks the connected MySQL server for its release information. A returned value proves that MySQL Workbench has an active server connection.
- Execute the current statement from the SQL Query Tab toolbar.
You should see one row containing the MySQL server version. Your local database toolchain is now reachable.
Cannot run the version query?
Confirm that you selected the local server connection from the Home screen. Start the local MySQL service if the connection reports that the server is unavailable.
Help me troubleshoot why MySQL Workbench cannot run a version query against my local server.
Generate the Maven scaffold
Spring Initializr creates a consistent project structure from a small set of choices. Maven then uses the generated project definition to resolve dependencies and build the application.
- Open the Spring Initializr website in your browser.
- Select Maven for the project type.
- Select Java for the language.
- Select Spring Boot 4.1.1.
- Enter com.nextwork in the Group field.
- Enter scm-foundation in the Artifact field.
- Enter scm-foundation in the Name field.
- Enter Supply Chain Management backend foundation in the Description field.
Why do these project details matter?
The group identifies the organization namespace. The artifact becomes the project name used by Maven.
The description records the purpose of this first SCM release inside the generated project definition.
- Enter com.nextwork.scm in the Package Name field.
- Select Jar for Packaging.
- Select 17 for Java Version.
- Click Add Dependencies.
- Search for web.
- Select Spring Web from the results.
- Click Generate to download the project archive.
Good progress. The downloaded archive contains the project structure plus the Maven Wrapper scripts needed to build without a separate Maven installation.
- Press Windows+E to open File Explorer.
- Select Downloads in the File Explorer sidebar.
- Right-click the downloaded ZIP archive for scm-foundation.
- Select Extract All... from the context menu.
- Set the extraction destination to a scm-foundation folder on your Desktop.
- Click Extract to unpack the project.
- Open the extracted scm-foundation folder in File Explorer.
- Confirm that mvnw.cmd appears beside pom.xml and the src folder.
The extracted folder now has its own Windows Maven Wrapper. That script keeps the build tied to the project.
Import and build the scaffold
IntelliJ IDEA reads pom.xml to recognize the Maven project. Importing that file gives the editor the same dependency model used by the command-line build.
- Press the Windows key to open Windows search.
- Type IntelliJ IDEA into the search field.
- Press Enter to open IntelliJ IDEA.
- Click File in the top menu.
- Click Open.
- Select the top-level pom.xml inside your Desktop's scm-foundation folder.
- Choose Open as Project.
The first Maven synchronization can take a few minutes while IntelliJ IDEA resolves the project. A moving progress indicator means the import is still working.
- Wait for the Maven synchronization to finish.
- Confirm that the Project sidebar shows pom.xml plus the src folder.
Testing belongs to a later SCM project with an isolated database strategy. Removing the generated test source keeps this foundation aligned with the current build definition.
- Right-click src/test in the Project sidebar.
- Select Delete from the context menu.
- Confirm the deletion when IntelliJ IDEA asks.
- Open pom.xml from the Project sidebar.
- Replace the complete dependencies section with this block:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
</dependencies>
What does this dependency do?
The MVC starter provides Spring MVC plus the embedded web server used by the status endpoint in the next step. Spring Boot 4.1.1 prefers spring-boot-starter-webmvc for this application type.
- Save pom.xml with Ctrl+S.
Use this checkpoint to compare the two project files that define the scaffold.
✔️ Awesome, I've got everything!
Your Maven definition and application entry point match the scaffold checkpoint. The project is ready for its first build.
ⓧ I'd like to double check the full code
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>com.nextwork</groupId>
<artifactId>scm-foundation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>scm-foundation</name>
<description>Supply Chain Management backend foundation</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
What does this file control?
- The parent pins Spring Boot to 4.1.1.
- The project properties compile the application for Java 17.
- The dependency section adds the Spring MVC web foundation.
- The build plugin prepares Spring Boot packaging for later steps.
package com.nextwork.scm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ScmFoundationApplication {
public static void main(String[] args) {
SpringApplication.run(ScmFoundationApplication.class, args);
}
}
What does this class do?
The @SpringBootApplication annotation activates configuration plus auto-configuration for the package. The main() method is the application entry point.
Spring scans from com.nextwork.scm when the application starts. Future controllers under this package can be discovered automatically.
Before you run the build, do you expect the wrapper to finish successfully with the verified Java version and updated dependency?
The first build can take a few minutes while the wrapper downloads Maven components and project dependencies. The download output shows that the process is still active.
- Switch back to the Windows Command Prompt window from earlier.
- Move into the extracted project folder and build the scaffold by running these commands:
cd "%USERPROFILE%\Desktop\scm-foundation"
mvnw.cmd clean install
What does this build do?
- The first command makes the Desktop's scm-foundation folder the current Command Prompt directory.
- The Maven Wrapper cleans previous build output before compiling the project.
- The install phase packages the application after the build checks pass.
You should see BUILD SUCCESS near the end of the Maven output. Strong start. Your Spring Boot scaffold now builds through its own Windows wrapper.
Build did not finish successfully?
Confirm that the Command Prompt path ends with Desktop\scm-foundation. Confirm that mvnw.cmd is visible in that folder.
Check that your Java result still reports major version 17 or later. Compare pom.xml with the checkpoint if Maven reports a project-definition problem.
Help me diagnose why mvnw.cmd clean install fails in my Spring Boot project.
Your Windows toolchain and Maven scaffold are ready. Next, you will define the first SCM release and launch a status response in the browser.
Define the SCM Slice and Launch a Status API
Your Spring Boot scaffold builds successfully through the Maven Wrapper. You can now turn that scaffold into the first visible slice of your SCM backend.
A focused requirements slice keeps the first release small enough to finish. A status response proves the web application works before database complexity enters the project.
In this step, get ready to:
- Document the first-release scope and architecture boundary.
- Create a status controller for the SCM backend.
- Run the application and verify its first JSON response.
Write the first-release requirements
A requirements document defines who the first release serves. It also separates the inventory foundation from features planned for later projects.
- Return to the IntelliJ IDEA project from the previous step.
- Locate HELP.md at the top level of the scm-foundation project.
- Right-click HELP.md.
- Select Rename.
- Enter README.md.
- Press Enter.
The project pane now lists README.md in place of HELP.md.
- Select the generated contents of README.md by pressing Ctrl+A.
- Remove the selected text.
- Add the problem statement and first-release criteria by pasting this content:
# SCM Backend Foundation
## Problem
Supply chain teams need a reliable base for tracking products and their current quantities before warehouses, suppliers, purchase orders, and receiving workflows are added.
## First-release user
An inventory coordinator who needs to confirm that the backend is running and retrieve product inventory from a relational database.
## In scope
- Report backend status.
- Persist a product with SKU, name, and quantity.
- Return all products through a REST endpoint.
- Keep local database credentials outside Git.
## Acceptance criteria
- `GET /api/status` returns a running status.
- `GET /api/products` returns product data stored in MySQL.
- The application starts through the Maven Wrapper on Windows.
- The local password file is ignored by Git.
What Does This Scope Capture?
- The problem statement names the inventory gap that this foundation addresses.
- The first-release user gives every feature a specific audience.
- The in-scope list limits this release to status reporting and product inventory.
- The acceptance criteria turn the scope into results you can verify.
- Save README.md by pressing Ctrl+S.
- Check the project pane for the renamed file.
You should see README.md at the top level of scm-foundation. The old HELP.md name should be gone.
Still Seeing HELP.md?
Check that you renamed the top-level generated file inside scm-foundation. Make sure the new name includes the .md extension.
If both files exist, move your new content into README.md. Remove the generated HELP.md file afterward.
Help me fix the README rename in IntelliJ IDEA.
The release also needs a clear stopping point. Deferred features protect this project from growing into the entire SCM platform.
- Place your cursor after the final acceptance criterion in README.md.
- Press Enter twice to create a blank line.
- Add the deferred features and architecture boundary by pasting this content:
## Deferred
- Warehouses and per-warehouse stock
- Suppliers
- Purchase orders and receiving
- Validation and centralized errors
- Authentication and authorization
- Automated tests
- React frontend
- Containerization and deployment
## Architecture boundary
Browser -> Spring MVC controller -> Spring Data JPA repository -> MySQL
Why Draw an Architecture Boundary?
The deferred list records which capabilities belong in later releases. This keeps the current work centered on product inventory.
The architecture boundary traces requests from the browser through Spring MVC and Spring Data JPA to MySQL.
- Save README.md by pressing Ctrl+S.
- Scroll to the bottom of README.md to check the architecture boundary.
You should see the boundary finish with Browser -> Spring MVC controller -> Spring Data JPA repository -> MySQL.
Missing Part of the Scope?
Confirm the second chunk starts with ## Deferred. It should appear after the acceptance criteria.
Check that each Markdown heading begins with two hash characters. A missing hash can make a section blend into ordinary text.
Help me compare my README with the required SCM scope.
✔️ Awesome, I've got everything!
Your requirements now define the first-release user and the limits of this SCM foundation.
ⓧ I'd like to double check the full code
# SCM Backend Foundation
## Problem
Supply chain teams need a reliable base for tracking products and their current quantities before warehouses, suppliers, purchase orders, and receiving workflows are added.
## First-release user
An inventory coordinator who needs to confirm that the backend is running and retrieve product inventory from a relational database.
## In scope
- Report backend status.
- Persist a product with SKU, name, and quantity.
- Return all products through a REST endpoint.
- Keep local database credentials outside Git.
## Acceptance criteria
- `GET /api/status` returns a running status.
- `GET /api/products` returns product data stored in MySQL.
- The application starts through the Maven Wrapper on Windows.
- The local password file is ignored by Git.
## Deferred
- Warehouses and per-warehouse stock
- Suppliers
- Purchase orders and receiving
- Validation and centralized errors
- Authentication and authorization
- Automated tests
- React frontend
- Containerization and deployment
## Architecture boundary
Browser -> Spring MVC controller -> Spring Data JPA repository -> MySQL
Add the status endpoint
A REST controller receives an HTTP request and chooses the Java method that handles it. This controller returns a small status response without needing database infrastructure.
- Expand src/main/java in the IntelliJ IDEA project pane.
- Expand the com.nextwork.scm package.
- Right-click the com.nextwork.scm package.
- Select New.
- Select Package.
- Enter status.
- Press Enter.
The project pane now shows a status package beneath com.nextwork.scm.
- Right-click the new status package.
- Select New.
- Select Java Class.
- Enter StatusController.
- Press Enter.
IntelliJ IDEA now opens StatusController.java inside the new package.
- Replace the generated class contents by pasting this code:
package com.nextwork.scm.status;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/status")
public class StatusController {
@GetMapping
public Map<String, String> status() {
return Map.of("status", "SCM backend is running");
}
}
What Does This Controller Do?
- The @RestController annotation makes the class available for web requests.
- The @RequestMapping("/api/status") annotation assigns the controller its URL path.
- The @GetMapping annotation sends GET requests to status().
- The Map.of("status", "SCM backend is running") expression supplies one key-value pair for the response.
- Save StatusController.java by pressing Ctrl+S.
- Check the editor for red syntax indicators in StatusController.java.
You should see the completed class with its imports resolved. The file should contain no red syntax indicators.
Seeing Red Syntax Indicators?
Confirm the file sits at src/main/java/com/nextwork/scm/status/StatusController.java. Its package declaration must match that location.
Check that the imports use org.springframework.web.bind.annotation exactly. The existing Maven dependency supplies those annotations.
Help me diagnose the red syntax indicators in StatusController.java.
✔️ Awesome, I've got everything!
Your status controller is saved in the package scanned by the application entry point.
ⓧ I'd like to double check the full code
package com.nextwork.scm.status;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/status")
public class StatusController {
@GetMapping
public Map<String, String> status() {
return Map.of("status", "SCM backend is running");
}
}
Run the first visible version
The Maven Wrapper starts the same project configuration on any machine. Spring Boot then discovers StatusController through the package beneath ScmFoundationApplication.
Before you run the application, do you think the new status path is ready to answer a browser request?
- Return to the Windows Command Prompt already positioned in the extracted scm-foundation directory.
- Start the application by running this command:
mvnw.cmd spring-boot:run
You should see startup logs finish without a failure. Leave this Command Prompt process running while you test the endpoint.
Application Did Not Start?
Confirm the Command Prompt is positioned in the extracted scm-foundation directory. That directory contains mvnw.cmd and pom.xml.
If compilation fails, compare StatusController.java with the full-file reference above. A missing brace or import prevents the application from starting.
Help me diagnose why my Spring Boot application does not start.
Before you open the endpoint, what response do you expect the status controller to return?
- Open http://localhost:8080/api/status in your browser.
You should see {"status":"SCM backend is running"}. That is your first visible SCM slice working from a browser request through the controller.
The application keeps the Command Prompt process busy while its server is running. Stopping that process leaves the project ready for the next code change.
- Return to the Windows Command Prompt running the application.
- Stop the application by pressing Ctrl+C.
The running logs should stop. Your command prompt is now ready for another command.
Your SCM foundation now has a deliberate scope and a working status endpoint. Next, you will add persistence and discover which database infrastructure Spring Boot still needs.
Add Persistence and Diagnose the Missing DataSource
Your status endpoint proved that the Spring MVC request path works. Your next architecture boundary is persistence.
Spring Data JPA maps Java objects to database rows. Spring Boot still needs a JDBC URL plus credentials before its DataSource auto-configuration can create a connection.
In this step, get ready to:
- Add the Spring Data JPA and MySQL Connector/J dependencies.
- Model the product data through a JPA entity and repository.
- Run the application to diagnose the planned DataSource startup failure.
Add the persistence dependencies
Maven uses the dependencies in pom.xml to assemble the capabilities available to your application. The Spring Boot parent manages compatible library versions for this project.
- Switch back to pom.xml in IntelliJ IDEA.
- Find the existing spring-boot-starter-webmvc dependency.
- Add the persistence dependencies immediately below it by pasting this code:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
What do these dependencies add?
- The spring-boot-starter-data-jpa starter adds repository support plus persistence integration.
- The mysql-connector-j dependency gives the application a driver for MySQL connections.
- The runtime scope keeps the driver available when the application runs.
- The Spring Boot parent remains pinned to 4.1.1. It manages Spring Data JPA 4.1.1 plus MySQL Connector/J 9.7.0.
- Save pom.xml.
- Confirm IntelliJ IDEA resolves both new artifact IDs after Maven synchronization finishes.
Good. Maven now has every library needed to model product data through JPA and connect through the MySQL driver.
Dependencies still unresolved?
Check that both new dependency blocks remain inside the dependencies element. Confirm that each XML tag has a matching closing tag.
If synchronization still fails, inspect IntelliJ IDEA's Maven output for the first dependency resolution error.
Help me diagnose unresolved Maven dependencies in this Spring Boot project.
✔️ Awesome, I've got everything!
Great. Double-check that you saved pom.xml before continuing.
ⓧ I'd like to double check the full code
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>com.nextwork</groupId>
<artifactId>scm-foundation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>scm-foundation</name>
<description>Supply Chain Management backend foundation</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Model the product and repository
A JPA entity describes how one Java object maps to one database row. The Product entity gives each inventory item a SKU plus a name plus a quantity.
- Switch back to the IntelliJ IDEA project from earlier.
- Select src/main/java in the Project tool window.
- Press Alt+Insert.
- Select Java Class.
- Enter com.nextwork.scm.product.Product.
- Press Enter.
You will see Product.java open inside the new com.nextwork.scm.product package.
- Replace the generated contents of Product.java with the entity mapping below:
package com.nextwork.scm.product;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "products")
public class Product {
@Id
@Column(name = "sku", nullable = false, length = 50)
private String sku;
@Column(name = "name", nullable = false, length = 120)
private String name;
@Column(name = "quantity", nullable = false)
private int quantity;
protected Product() {
}
}
How does this mapping work?
- The Entity annotation marks Product as a persistent type.
- The Table annotation maps that type to the products table.
- The Id annotation makes sku the primary key.
- Each Column annotation defines the matching database column rules.
- The protected no-argument constructor lets the persistence provider create entity instances.
- Save Product.java.
- Confirm the four persistence imports appear without red error highlighting.
Persistence imports still red?
Return to pom.xml and confirm the JPA starter block is inside dependencies. Allow Maven synchronization to finish before checking the imports again.
Help me resolve the Jakarta Persistence imports in Product.java.
The entity also needs an application-facing constructor plus getters. These methods let later code create products and read their mapped values.
- Find the protected constructor in Product.java.
- Add the following code below that constructor before the final class brace:
public Product(String sku, String name, int quantity) {
this.sku = sku;
this.name = name;
this.quantity = quantity;
}
public String getSku() {
return sku;
}
public String getName() {
return name;
}
public int getQuantity() {
return quantity;
}
Why add these methods?
The public constructor creates a fully populated product from a SKU plus a name plus a quantity. Each getter exposes one mapped value without making the fields public.
- Save Product.java.
- Confirm getSku() plus getName() plus getQuantity() appear inside the Product class.
Seeing a Java syntax error?
Check that the new constructor plus getters sit before the final brace of the Product class. Confirm that every method has its own opening brace plus closing brace.
Help me find the brace or method placement error in Product.java.
✔️ Awesome, I've got everything!
Your product mapping is complete. Double-check that Product.java is saved.
ⓧ I'd like to double check the full code
package com.nextwork.scm.product;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "products")
public class Product {
@Id
@Column(name = "sku", nullable = false, length = 50)
private String sku;
@Column(name = "name", nullable = false, length = 120)
private String name;
@Column(name = "quantity", nullable = false)
private int quantity;
protected Product() {
}
public Product(String sku, String name, int quantity) {
this.sku = sku;
this.name = name;
this.quantity = quantity;
}
public String getSku() {
return sku;
}
public String getName() {
return name;
}
public int getQuantity() {
return quantity;
}
}
A repository connects the entity model to Spring Data's persistence operations. Extending JpaRepository supplies operations for retrieving plus saving product rows.
- Select com.nextwork.scm.product in the Project tool window.
- Press Alt+Insert.
- Select Java Class.
- Enter ProductRepository.
- Press Enter.
You will see ProductRepository.java open beside Product.java.
- Replace the generated class with this repository interface:
package com.nextwork.scm.product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, String> {
}
What does this repository provide?
- The first generic type tells Spring Data that this repository manages Product entities.
- The second generic type identifies String as the type of the sku primary key.
- The empty interface inherits standard persistence operations from JpaRepository.
- Save ProductRepository.java.
- Confirm IntelliJ IDEA resolves JpaRepository plus Product without red error highlighting.
Repository types unresolved?
Confirm ProductRepository.java uses the same com.nextwork.scm.product package as Product.java. Check the JPA starter dependency if JpaRepository remains unresolved.
Help me diagnose unresolved ProductRepository types.
✔️ Awesome, I've got everything!
Your repository is ready. Double-check that ProductRepository.java is saved.
ⓧ I'd like to double check the full code
package com.nextwork.scm.product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, String> {
}
Trigger the missing DataSource failure
The project now requests database persistence during startup. Spring Boot inspects the classpath plus the current configuration to determine whether it can create a DataSource.
Before you run the application, do you think Spring Boot can build that connection from the current project state?
- Return to the Windows Command Prompt from earlier.
- Confirm the prompt points to the extracted scm-foundation project directory.
- Test the persistence configuration by running this command:
mvnw.cmd spring-boot:run
What happened during startup?
The application stops during startup with a DataSource configuration error. Spring Boot sees JPA plus the MySQL driver but cannot infer a JDBC URL or database credentials.
This is the planned shortfall. The final cause points directly to the infrastructure the next step must supply.
- Scroll to the final cause in the startup output.
- Confirm the cause identifies missing DataSource connection configuration.
That failed startup is useful evidence. You have proved that the persistence layer is active enough to request a database connection.
Application started successfully?
Check src/main/resources for database connection settings left over from another project. This step expects no JDBC URL or database credentials.
Confirm the application is running from the scm-foundation directory. A different project may already contain valid DataSource configuration.
Help me work out why this project started without the expected DataSource failure.
Checkpoint
- The Spring Boot parent in pom.xml remains pinned to 4.1.1.
- The Maven project includes Spring Data JPA plus runtime MySQL Connector/J dependencies.
- The Product entity maps sku plus name plus quantity to the products table.
- The ProductRepository interface extends JpaRepository<Product, String>.
- The startup output proves that DataSource connection settings are still missing.
You have reached the persistence boundary on purpose. Next up, you will create the local MySQL resources plus supply the connection settings that let the application cross it.
Create and Connect the Local MySQL Database
The intentional DataSource failure proved that Spring Boot cannot infer a database address or credentials. You now know exactly which infrastructure the application is missing.
This step supplies that infrastructure through a local MySQL database. A local Spring Profile keeps the database password outside tracked project files.
In this step, get ready to:
- Create a local database with an application account scoped to that database.
- Configure the local profile without exposing your database password to Git.
- Start the application against MySQL and confirm Hibernate creates the products table.
Create database-scoped resources
A database-scoped account limits the application to scm_db. A reusable SQL script records how to create the database and its account.
- In the IntelliJ IDEA project sidebar, right-click the top-level scm-foundation folder.
- Choose the option to create a new directory.
- Name the directory database.
- Right-click the new database directory.
- Choose the option to create a new file.
- Name the file setup.sql.
- Add the database resource script by pasting the code below:
CREATE DATABASE IF NOT EXISTS scm_db;
CREATE USER IF NOT EXISTS 'scm_app'@'localhost' IDENTIFIED BY 'your-mysql-password-here';
GRANT ALL ON scm_db.* TO 'scm_app'@'localhost';
What does this script create?
- The first statement creates the scm_db database when it does not already exist.
- The second statement creates the scm_app account for connections from localhost.
- The final statement grants that account privileges on scm_db.*.
Working with a password can feel sensitive. You will replace the placeholder only in an unsaved query inside MySQL Workbench.
- Save database/setup.sql with the placeholder unchanged.
- Switch back to the local server connection from earlier in MySQL Workbench.
- Return to the SQL Query Tab from earlier.
- Copy the three statements from database/setup.sql into the query editor.
- Select your-mysql-password-here in the query editor.
- Type a local password that you can use again in the application configuration.
- Execute all three statements with the query editor's lightning bolt control.
- Close the query tab without saving it after execution.
- Refresh the schema list in MySQL Workbench.
You should see scm_db in the schema list. The script has also created the local scm_app@localhost account.
Database or account missing?
Confirm that you executed all three statements through an administrative MySQL connection. An account without database or user administration privileges cannot complete this script.
Check the query output for the statement that failed. Fix that statement before executing the full script again.
help me diagnose why my MySQL setup script did not create scm_db or scm_app
Separate local credentials from tracked configuration
The shared configuration activates the local profile. The profile-specific file supplies the database connection details only on your machine.
Why use a local profile?
The tracked example documents which properties the application needs. The ignored local file stores the real password used by your machine.
This boundary lets another developer create their own local file without receiving your credentials.
- In the IntelliJ IDEA project sidebar, right-click the top-level scm-foundation folder.
- Choose the option to create a new file.
- Name the file .gitignore.
- Protect generated files and local credentials by pasting the code below:
target/
.idea/
*.iml
src/main/resources/application-local.properties
What does this ignore file protect?
The first three patterns keep generated build output and editor files outside Git. The final pattern excludes the only file that contains your real local database password.
- Save .gitignore.
- Confirm the file appears at the top level of the scm-foundation folder.
Can't find the ignore file?
Check that the filename starts with a dot. Remove any extra file extension that IntelliJ IDEA added.
help me check whether my .gitignore filename and local properties pattern are correct
- Expand src/main/resources in the IntelliJ IDEA project sidebar.
- Select the generated application.properties file.
- Replace its contents with the shared profile configuration below:
spring.profiles.active=local
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
What does the shared configuration control?
- The first property activates the local profile whenever the application starts.
- The second property lets Hibernate update the local schema from your entity mappings.
- The final property prints generated SQL so you can see database activity during development.
- Save src/main/resources/application.properties.
- Confirm IntelliJ IDEA displays all three saved property lines.
- Right-click the src/main/resources folder.
- Choose the option to create a new file.
- Name the file application-local.properties.example.
- Document the required local connection properties by pasting the code below:
spring.datasource.url=jdbc:mysql://localhost:3306/scm_db
spring.datasource.username=scm_app
spring.datasource.password=your-mysql-password-here
What is the example file for?
The example records the required JDBC URL and username. Its password line contains a safe placeholder that can remain in version control.
- Save src/main/resources/application-local.properties.example.
- Confirm the example file appears inside src/main/resources.
- Right-click the src/main/resources folder again.
- Choose the option to create a new file.
- Name the file application-local.properties.
- Seed the local connection file by pasting the code below:
spring.datasource.url=jdbc:mysql://localhost:3306/scm_db
spring.datasource.username=scm_app
spring.datasource.password=your-mysql-password-here
What does the local file provide?
This file gives Spring Boot the address and username that the earlier startup attempt lacked. Its final line supplies the local password used by the scm_app account.
- Replace your-mysql-password-here in application-local.properties with the same local password you entered in MySQL Workbench.
- Save src/main/resources/application-local.properties.
- Confirm the local file sits beside application-local.properties.example.
Connection details don't match?
Check that both files use jdbc:mysql://localhost:3306/scm_db and scm_app. Only the password value should differ between the example and local files.
help me compare my Spring Boot local DataSource files without sharing my password
The reference below keeps the password placeholder visible for safety. Your untracked local file uses your real local password on its final line.
✔️ Awesome, I've got everything!
Your database script and profile configuration now match the project boundary.
ⓧ I'd like to double check the full code
CREATE DATABASE IF NOT EXISTS scm_db;
CREATE USER IF NOT EXISTS 'scm_app'@'localhost' IDENTIFIED BY 'your-mysql-password-here';
GRANT ALL ON scm_db.* TO 'scm_app'@'localhost';
target/
.idea/
*.iml
src/main/resources/application-local.properties
spring.profiles.active=local
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.datasource.url=jdbc:mysql://localhost:3306/scm_db
spring.datasource.username=scm_app
spring.datasource.password=your-mysql-password-here
spring.datasource.url=jdbc:mysql://localhost:3306/scm_db
spring.datasource.username=scm_app
spring.datasource.password=your-mysql-password-here
Start the application against MySQL
Hibernate can now read the JPA mapping on Product. During startup, it uses that mapping to create or update the products table in scm_db.
Before you run this, consider which outcome you expect: the earlier DataSource failure or a running server.
- Switch back to the Windows Command Prompt from earlier.
- Start Spring Boot from the scm-foundation directory by running this command:
mvnw.cmd spring-boot:run
What does this startup prove?
The Apache Maven Wrapper launches the application with the active local profile. Spring Boot can now build the DataSource from your URL and credentials.
Hibernate compares the Product mapping with the local schema. The update setting creates the missing table.
You should see the application complete startup and remain running without the earlier DataSource failure. That closes the infrastructure gap you uncovered in the previous step.
- Return to MySQL Workbench while the application remains running.
- Refresh the scm_db schema.
- Expand the table list under scm_db.
You should see the products table. Your application is now connected to MySQL through the local profile.
Application still fails to connect?
Confirm the local MySQL server is running. Check that the database name and username match the values in application-local.properties.
Re-enter the same password used when creating scm_app. Keep the password out of screenshots and help requests.
help me diagnose why Spring Boot cannot connect to my local MySQL database
Your application now starts with a real persistence layer behind it. Next, you will expose stored products through the REST API and commit the foundation without leaking credentials.
Expose Products and Commit the Foundation
Your Spring Boot application now connects to MySQL. Hibernate has also created the table that stores your product inventory.
A running connection alone does not prove the complete request path. In this step, you will expose stored inventory through a REST endpoint before saving the foundation in Git without leaking your local password.
In this step, get ready to:
- Serve product inventory through a database-backed endpoint.
- Seed MySQL with a product that appears in the browser.
- Commit the project while keeping local credentials untracked.
Add the database-backed controller
The repository already knows how to retrieve every product from the database. A controller gives browser requests a route into that repository.
- In IntelliJ IDEA's project sidebar, expand src/main/java/com/nextwork/scm/product.
- Create ProductController.java inside the product package.
- Define the products endpoint by replacing the file contents with this code:
package com.nextwork.scm.product;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductRepository productRepository;
public ProductController(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@GetMapping
public List<Product> findAll() {
return productRepository.findAll();
}
}
What does this controller do?
- The @RequestMapping("/api/products") annotation gives every method in this controller the same base path.
- The constructor receives ProductRepository through dependency injection.
- The findAll() method delegates database retrieval to Spring Data JPA.
- The returned List<Product> becomes the response body for the browser.
✔️ Awesome, I've got everything!
Your ProductController.java file now exposes the repository through /api/products.
ⓧ I'd like to double check the full code
package com.nextwork.scm.product;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductRepository productRepository;
public ProductController(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@GetMapping
public List<Product> findAll() {
return productRepository.findAll();
}
}
- Save ProductController.java.
- Return to the Windows Command Prompt from earlier.
- Start the application through the Maven Wrapper by running:
mvnw.cmd spring-boot:run
What does this command do?
The Maven Wrapper runs the project with its configured Maven environment. The spring-boot:run goal starts the web application with the active local profile.
- Open http://localhost:8080/api/products in your browser.
You should see an empty JSON array. This proves the controller can call the repository even though the table has no rows yet.
Can't reach the products endpoint?
Confirm that ProductController.java is inside src/main/java/com/nextwork/scm/product. Check the Windows Command Prompt for a startup failure before refreshing the browser.
Make sure the address ends with /api/products.
Help me diagnose why my Spring Boot products endpoint is unavailable.
Seed and retrieve one product
A stored row turns the empty endpoint into evidence that the entire persistence path works. The sample product gives you a concrete inventory record to retrieve.
- Use IntelliJ IDEA's project sidebar to create sample-data.sql inside the existing database folder.
- Add the sample inventory row by placing this statement in the file:
INSERT INTO scm_db.products (sku, name, quantity)
VALUES ('SKU-1001', 'Safety Gloves', 50);
What does this statement do?
- The statement inserts one row into the products table in scm_db.
- The row uses SKU-1001 as its primary key.
- The stored quantity records 50 units of Safety Gloves.
- Save database/sample-data.sql.
- Switch back to MySQL Workbench from earlier.
- Load database/sample-data.sql into the SQL Query Tab.
- Execute the current statement.
- Return to the browser tab for http://localhost:8080/api/products.
- Refresh the browser page.
You should see a JSON object containing SKU-1001. The same object should contain Safety Gloves with a quantity of 50.
How does the request reach MySQL?
- Spring MVC routes the browser request to ProductController.
- ProductRepository retrieves the stored row through Spring Data JPA.
- Product maps the table columns to Java fields.
- MySQL supplies the inventory values returned in the response.
Don't see the seeded product?
Confirm that the statement ran against the local server containing scm_db. Refresh the endpoint after the statement completes.
If MySQL reports that the SKU already exists, inspect the endpoint first. A previous execution may have inserted the row successfully.
Help me trace why the seeded MySQL product is missing from my Spring Boot endpoint.
Protect credentials and create the first commit
A clean project snapshot includes the reusable source files. Your ignored local profile keeps the real database password outside that snapshot.
- Return to the Windows Command Prompt where the application is running.
- Stop the application by pressing Ctrl+C.
The cleanup script contains destructive SQL. You are only storing it now, so the database and seeded row stay intact.
- Use IntelliJ IDEA's project sidebar to create cleanup.sql inside the existing database folder.
- Add the project cleanup statements by placing this code in the file:
DROP DATABASE IF EXISTS scm_db;
DROP USER IF EXISTS 'scm_app'@'localhost';
What is this cleanup script for?
This file provides a repeatable cleanup path for the resources created in MySQL. Executing it removes scm_db before removing the scm_app account.
The script is reserved for the cleanup section after the project.
- Save database/cleanup.sql.
- Confirm that the database folder lists cleanup.sql beside setup.sql and sample-data.sql.
Can't find the cleanup script?
Check that cleanup.sql sits directly inside the existing database folder. Confirm that the filename ends with .sql.
Help me place cleanup.sql in the correct IntelliJ IDEA project folder.
- Return to the Windows Command Prompt in the extracted project directory.
- Initialize the local Git repository by running:
git init
What does this command do?
The command creates a hidden .git directory inside the current project. Git uses that directory to store commits and repository metadata.
You should see confirmation that Git initialized the repository in your project directory.
- Check the ignored files before staging anything by running:
git status --ignored
What does this check prove?
The --ignored option includes files excluded by .gitignore in the status report. This reveals whether the local credentials file is protected before you create a commit.
You should see src/main/resources/application-local.properties listed as ignored. Its real password remains outside Git.
Local credentials are not ignored?
Stop before staging files. Confirm that .gitignore contains src/main/resources/application-local.properties on its own line.
Save .gitignore. Run the ignored-file check again before continuing.
Help me fix my .gitignore so the local Spring Boot credentials file stays untracked.
Each commit records an author identity. Choose the path that matches your existing Git configuration.
✔️ My Git identity is configured
Your existing global Git identity is ready for the commit.
ⓧ I need to configure it
Git stores your author name and email in its global configuration. These details identify the author of each commit.
- Replace Your Name with your name before running this command:
git config --global user.name "Your Name"
What does this command store?
This command saves the author name that Git attaches to future commits on this computer.
- Replace you@example.com with your email address before running this command:
git config --global user.email you@example.com
What does this command store?
This command saves the author email that Git attaches to future commits on this computer.
- Stage every new project file by running:
git add -A
What does this command stage?
The -A option stages new files and modified files. Ignored files remain outside the staged snapshot.
- Review the staged snapshot by running:
git status
What should the snapshot contain?
The staged snapshot should include your Java source and tracked configuration. It should also include the three SQL scripts.
The local application-local.properties file should remain absent from the staged files.
- Record the SCM foundation by running:
git commit -m "Build SCM backend foundation"
What does this commit capture?
The commit records the scoped requirements and Spring Boot source. It also records the reusable database scripts without recording your local password.
You should see a commit summary for Build SCM backend foundation.
Commit did not complete?
Use the identity tab above if Git needs an author name or email. Run the commit command again after both values are configured.
If Git reports that there is nothing to commit, run the staging command again before retrying the commit.
Help me diagnose why my first SCM foundation commit did not complete.
Before you run the final check, do you expect Git to report any tracked changes after the commit?
- Verify the committed working tree by running:
git status
What does the final status prove?
Git compares the current tracked files with the commit you just created. A clean result proves that the tracked foundation matches the saved snapshot.
You should see Git report a clean working tree. The ignored local credentials file does not appear as a tracked change.
You made the complete request path work. Your browser now retrieves product inventory from MySQL through the controller and repository.
Secret mission
Add a Low-Stock Filter
Inventory teams need a quick way to find products that may need restocking. Add an endpoint where the caller supplies a quantity threshold and receives only the products below it.
Clean Up Your Resources
Clean Up Your Resources
Every resource for this project runs on your local Windows machine, so keeping them creates no ongoing cost. Choose whether to keep the project active, pause the running process, or delete the local resources.
Resources you used:
- Local scm_db MySQL database, including the products table plus its sample inventory row.
- Local scm_app account with privileges scoped to scm_db.
- scm-foundation project folder. This contains the Maven project, ignored src/main/resources/application-local.properties file, plus the local Git repository.
Keep everything running
No action needed. Choose this if you are still testing the API or plan to continue with another SCM project.
- Keep the Spring Boot application running while you continue testing the product endpoints.
- Keep scm_db plus scm_app in place for later SCM features.
- Keep the scm-foundation folder so the source code, local credentials, plus Git history remain available.
Pause - I'll come back to this later
Shut down the running application to free up memory. Your project files plus MySQL data stay in place for your return.
- Return to the Windows Command Prompt where the Spring Boot application is running.
- Stop the application by pressing Ctrl+C.
- Leave scm_db plus scm_app in place.
- Leave the scm-foundation folder in its current location.
Your API stops responding after Spring Boot exits. The product row remains stored in scm_db.
Delete - I don't want to use this again
Deletion is permanent, so use this option only when you no longer need the local inventory data or Git history. The cleanup script targets scm_db plus scm_app without touching your other local databases.
- Return to the Windows Command Prompt where the Spring Boot application is running.
- Stop the application by pressing Ctrl+C.
- Switch back to the administrative local connection in MySQL Workbench.
- Open the existing database/cleanup.sql file in the SQL Query Tab.
- Execute the entire cleanup script.
- Refresh the database list in MySQL Workbench.
You should no longer see scm_db in the database list. The cleanup script also removes the scm_app account.
- Close IntelliJ IDEA.
- Delete the scm-foundation folder from the location where you extracted it by using your Windows file manager.
- Confirm the scm-foundation folder no longer appears in that location.
Cleanup complete. Your local database account, project files, ignored password file, plus Git history are gone.
Nice Work!
Nice Work!
Excellent work! Your Spring Boot backend now reads product inventory from MySQL. Its low-stock endpoint filters that inventory with a caller-supplied threshold.
You've learned how to:
- Define a focused first-release scope for product inventory. Prove the web application is live with a status endpoint.
- Diagnose an intentional missing-DataSource failure. Connect a JPA entity to MySQL through profile-specific configuration.
- Return stored inventory through a REST API. Keep the local database password outside Git before creating a clean commit.
- Secret Mission: Add a low-stock threshold filter with a Spring Data derived query. Verify the seeded product appears at 60 and disappears at 40.
Ready to quiz yourself?