This is a multi-module monorepo demonstrating a full HTTPS stack. There is no root-level build system; each module is built independently.
https-springboot-react/
├── movies-api/ # Spring Boot REST API (Java 25, Maven, HTTPS port 8443)
├── movies-shell/ # Spring Boot Shell CLI client (Java 25, Maven)
└── movies-ui/ # React SPA (JavaScript, npm, HTTPS port 3443)
movies-api: H2 in-memory DB, Spring Data JPA, Bean Validation, Springdoc OpenAPI (Swagger UI)movies-shell: Interactive CLI using Spring Shell; callsmovies-apiover HTTPSmovies-ui: Vite + React 19 SPA; callsmovies-apivia axios over HTTPS; MUI component library
# Start dev server
./mvnw clean spring-boot:run
# Build JAR (skip tests)
./mvnw clean package -DskipTests
# Run all tests
./mvnw test
# Run a single test class
./mvnw test -Dtest=MoviesApiApplicationTests
# Run a single test method
./mvnw test -Dtest=MoviesApiApplicationTests#contextLoads# Start the interactive shell
./mvnw clean spring-boot:run
# Build JAR (skip tests)
./mvnw clean package -DskipTests
# Run all tests
./mvnw test
# Run a single test class
./mvnw test -Dtest=MoviesShellApplicationTests# Install dependencies
npm install
# Start dev server (HTTPS, port 3443)
npm start
# Production build
npm run build
# Run all tests (once, CI mode)
npm test
# Run all tests in watch mode
npm run test:watch
# Run a single test file by pattern
npm test -- --reporter=verbose --testPathPattern="App"
# Run tests matching a specific test name
npm test -- --reporter=verbose -t "renders"HTTPS is enabled via
@vitejs/plugin-basic-sslinvite.config.js.
| Module | Language | Framework | Key Version |
|---|---|---|---|
movies-api |
Java 25 | Spring Boot 4.0.3 | Lombok, H2, Spring Data JPA, springdoc-openapi 3.0.2 |
movies-shell |
Java 25 | Spring Boot 4.0.3 | Spring Shell 4.0.1, Spring RestClient |
movies-ui |
JavaScript (ES2020+, no TypeScript) | React 19.2.4 | Vite 8, @vitejs/plugin-react, axios 1.13.x, MUI 7 (@mui/material, @mui/icons-material) |
| Java build | — | Maven 3.9.12 (wrapper) | — |
- Indentation: 4 spaces (no tabs)
- Braces: opening brace on the same line as the declaration (K&R style)
- Annotations: each annotation on its own line, directly above the annotated element
- One blank line between methods; no trailing blank lines inside method bodies
- No wildcard imports — import each class individually
- Import order (blank line between groups):
- Project classes (
com.ivanfranchin.*) jakarta.*lombok.*org.springframework.*java.*
- Project classes (
- Classes/Interfaces:
PascalCase—MoviesController,MovieService - Implementations:
PascalCase+Implsuffix —MovieServiceImpl - DTOs (records):
PascalCase+Request/Responsesuffix —AddMovieRequest,MovieResponse - Exceptions:
PascalCase+Exceptionsuffix —MovieNotFoundException - Config classes:
PascalCase+Configsuffix —CorsConfig,SwaggerConfig - Methods/fields:
camelCase—validateAndGetMovie,movieRepository - Packages: all lowercase, domain-organized —
com.ivanfranchin.moviesapi.movie.dto - Test classes: class name +
Testssuffix —MoviesApiApplicationTests
- Use
@ResponseStatuson custom exceptions to map them to HTTP status codes:@ResponseStatus(HttpStatus.NOT_FOUND) public class MovieNotFoundException extends RuntimeException { ... }
- Use
orElseThrowin service layer to raise typed exceptions:return movieRepository.findById(id).orElseThrow(() -> new MovieNotFoundException(id));
- No
@ControllerAdvice/@ExceptionHandler— rely on Spring Boot's error pipeline - In
movies-shellcommands, wrap API calls intry/catch(Exception e)and return"Error: " + e.getMessage()as a string to the shell
- Prefer Java records for DTOs (
AddMovieRequest,MovieResponse) - Use Lombok (
@RequiredArgsConstructor,@Data,@Getter, etc.) on JPA entities and services - Use Bean Validation annotations (
@NotBlank,@Positive) on DTO fields; validate at controller with@Valid
- Indentation: 2 spaces
- Quotes: single quotes for all string literals and JSX prop values
- Semicolons: omit where possible (no trailing
;on import/export lines in component files) - No Prettier config — no ESLint config present
Order within a file (no blank lines required between groups, but follow this sequence):
- React core —
import React, { ... } from 'react' - Third-party libraries —
import { Button } from '@mui/material' - Local components —
import MovieForm from './MovieForm' - Local utilities/services —
import { moviesApi } from '../misc/MoviesApi'
No barrel/index files — always use explicit relative paths.
- Component files/classes:
PascalCase—MoviePage.jsx,MovieForm.jsx - Service/utility files:
PascalCase—MoviesApi.js - Functions/variables:
camelCase—handleChange,movieList,formInitialState - Event handlers:
handleprefix —handleSaveMovie,handleDeleteMovie - State booleans: descriptive adjective suffix —
isMovieFormOpen,imdbIdError
- End all axios promise chains with
.catch(error => { console.log(error) }) - Do not update UI state or show error messages on API failure (log only)
- Client-side form validation: set
*Errorboolean fields in component state and pass them as theerrorprop to MUITextFieldcomponents
- Use class components (existing code is class-based; do not refactor to hooks unless explicitly asked)
- Store form state as a flat object (
this.state.form = { imdbId: '', title: '', ... }) - Use
setStatecallbacks for dependent state updates
- Framework: JUnit 5 + Spring Boot Test (
@SpringBootTest) - Existing tests are stubbed and annotated
@Disabled— enable and expand them when writing tests - Test class visibility:
public voidtest methods - Test class naming:
{TargetClass}Tests - Package must mirror the main source package
- Framework: Vitest + @testing-library/react + @testing-library/jest-dom
- No existing component tests — write
.test.jsxfiles alongside components - Setup file:
src/vitest.setup.js(already imports@testing-library/jest-dom) - Test config lives in
vite.config.jsunder thetestkey (environment: 'jsdom',globals: true)
- Both Java modules include a self-signed
keystore.p12insrc/main/resources/(password:secret) movies-apiuses the keystore as an SSL server certificatemovies-shelluses the same cert as a truststore to accept the self-signed certmovies-uidev server enables HTTPS via Vite's built-in--httpsflag in the npm start script- Do not commit new keystore files or change the existing ones without updating
application.yml