Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
403886e
build(pom): share test dependencies and expose the common test-jar
EdgarEldy Sep 19, 2026
b61861d
build(core): declare the auth, catalog, customer and order modules
EdgarEldy Sep 19, 2026
a01445c
build(common): add the JDBC, Flyway and test-jar dependencies
EdgarEldy Sep 19, 2026
c9178aa
build(ws): add Spring MVC, Jackson, validation and logging dependencies
EdgarEldy Sep 19, 2026
91c8265
feat(common): add ResourceNotFoundException and BusinessRuleException
EdgarEldy Sep 19, 2026
b7f207a
feat(common): add the Flyway V1 schema for both domains
EdgarEldy Sep 19, 2026
5fb25ac
feat(common): add AbstractDao with shared JdbcTemplate helpers
EdgarEldy Sep 19, 2026
bdcf0e4
feat(common): declare DataSource, Flyway, JdbcTemplate and transactions
EdgarEldy Sep 19, 2026
fbb1d84
feat(common): add a health check through the five-layer split
EdgarEldy Sep 19, 2026
8fb2304
feat(ws): add ApiResponse, PageResponse and HealthResponse payloads
EdgarEldy Sep 19, 2026
bb048a7
feat(ws): map every exception to an ApiResponse in GlobalExceptionHan…
EdgarEldy Sep 19, 2026
8739721
feat(ws): add the public health route
EdgarEldy Sep 19, 2026
9aace48
feat(ws): configure Spring MVC explicitly with WebMvcConfig
EdgarEldy Sep 19, 2026
a7c5f6b
feat(ws): replace web.xml with a WebApplicationInitializer
EdgarEldy Sep 19, 2026
b7526cc
test(common): verify the Flyway schema against a real PostgreSQL
EdgarEldy Sep 19, 2026
a360c64
test(common): check that DataSourceConfig fails without its settings
EdgarEldy Sep 19, 2026
fee8885
test(common): cover AbstractDao and HealthDao against PostgreSQL
EdgarEldy Sep 19, 2026
ce291f6
test(common): unit test HealthServiceImpl with a mocked DAO
EdgarEldy Sep 19, 2026
6a85553
test(ws): cover ApiResponse and PageResponse
EdgarEldy Sep 19, 2026
177723b
test(ws): verify HTTP error mapping and the health controller with Mo…
EdgarEldy Sep 19, 2026
c3bf50a
test(ws): boot the real WebMvcConfig against PostgreSQL
EdgarEldy Sep 19, 2026
b8a2051
build(docker): add a multi-stage Dockerfile for the WAR on Tomcat 10.1
EdgarEldy Sep 19, 2026
78173a6
build(docker): add docker-compose for the WAR and PostgreSQL 16
EdgarEldy Sep 19, 2026
351b854
ci(actions): run mvn verify on the whole reactor
EdgarEldy Sep 19, 2026
60dd8f7
ci(actions): lint commit messages against Conventional Commits
EdgarEldy Sep 19, 2026
63b93ca
docs(github): add the pull request template
EdgarEldy Sep 19, 2026
8619f3d
docs(readme): tick core-architecture tasks and note two deviations
EdgarEldy Sep 19, 2026
8122095
fix(ws): stop the catch-all from leaking ErrorResponse detail text
EdgarEldy Sep 19, 2026
31f4f3c
fix(ws): register the validator as a bean and keep default converters
EdgarEldy Sep 19, 2026
9473c7c
fix(common): log the cause when the health check fails
EdgarEldy Sep 19, 2026
4ecd869
Merge pull request #1 from EdgarEldy/feature/core-architecture
EdgarEldy Sep 19, 2026
a5f971e
build(auth): add spring-security-crypto for password hashing
EdgarEldy Sep 19, 2026
67daef9
feat(common): declare a Clock bean shared by every service
EdgarEldy Sep 19, 2026
e2667be
feat(auth): add the User and token entities
EdgarEldy Sep 19, 2026
df45c51
feat(auth): add the auth dto classes returned and accepted by services
EdgarEldy Sep 19, 2026
3a798ec
feat(auth): add the RowMappers turning ResultSet rows into entities
EdgarEldy Sep 19, 2026
29736cd
feat(auth): add UserMapper between the User entity and UserDto
EdgarEldy Sep 19, 2026
a465d43
feat(auth): add UserDao and its JdbcTemplate implementation
EdgarEldy Sep 19, 2026
d3879d4
feat(auth): add the token DAOs
EdgarEldy Sep 19, 2026
f66c12c
feat(auth): add the authentication exceptions
EdgarEldy Sep 19, 2026
77fad26
feat(auth): implement registration, activation, login, logout and reset
EdgarEldy Sep 19, 2026
caf3984
feat(auth): wire the DAOs, the AuthService and the cleanup job
EdgarEldy Sep 19, 2026
ca7f22d
build(ws): add Spring Security, jjwt and the test key locations
EdgarEldy Sep 19, 2026
8c4dce5
chore(keys): add the development RS256 key pair
EdgarEldy Sep 19, 2026
a4bd52a
feat(ws): issue and verify RS256 JWTs with JwtService
EdgarEldy Sep 19, 2026
2c36767
feat(ws): authenticate requests with JwtAuthFilter and reject revoked…
EdgarEldy Sep 19, 2026
646dcaf
feat(ws): answer 401 and 403 in the ApiResponse format
EdgarEldy Sep 19, 2026
9b76987
feat(ws): declare the stateless SecurityFilterChain explicitly
EdgarEldy Sep 19, 2026
8dd582f
feat(ws): add the auth payloads and UserConverter
EdgarEldy Sep 19, 2026
7855550
feat(ws): expose the auth endpoints in AuthController
EdgarEldy Sep 19, 2026
c92b262
feat(ws): map authentication and access denied exceptions to 401 and 403
EdgarEldy Sep 19, 2026
59a35cd
feat(ws): import the auth module and security into the shared context
EdgarEldy Sep 19, 2026
ec6cfc5
build(auth): add Testcontainers test dependencies to the auth module
EdgarEldy Sep 19, 2026
2f9cb0d
test(auth): cover the user and token DAOs against PostgreSQL
EdgarEldy Sep 19, 2026
56c753c
test(auth): test the RowMappers with a mocked ResultSet and UserMapper
EdgarEldy Sep 19, 2026
19953ba
test(auth): unit test AuthServiceImpl and the cleanup job with mocked…
EdgarEldy Sep 19, 2026
a5a2336
test(ws): add shared fixtures and assertions for HTTP tests
EdgarEldy Sep 19, 2026
2d20d42
test(ws): test JwtService and JwtKeyLoader
EdgarEldy Sep 19, 2026
7caed75
test(ws): test the auth endpoints and the security chain with MockMvc
EdgarEldy Sep 19, 2026
28d3721
test(ws): prove the full auth flow against the real stack
EdgarEldy Sep 19, 2026
c255318
build(docker): pass the JWT key locations and mount the production keys
EdgarEldy Sep 19, 2026
a2c2d0c
fix(auth): treat a blank email as unknown in forgotPassword
EdgarEldy Sep 19, 2026
dfd45f0
docs(readme): tick the feature/auth tasks
EdgarEldy Sep 19, 2026
4cbe777
Merge pull request #2 from EdgarEldy/feature/auth
EdgarEldy Sep 19, 2026
766944a
feat(common): seed the baseline permissions and the ADMIN role in Fly…
EdgarEldy Sep 19, 2026
9d7c467
feat(common): add PageDto for paginated service results
EdgarEldy Sep 19, 2026
37aa991
feat(auth): add the Role, Permission and AuditLog entities
EdgarEldy Sep 19, 2026
2a2889e
feat(auth): add RoleDto, PermissionDto and AuditLogDto
EdgarEldy Sep 19, 2026
4b7a9c0
feat(auth): add the RowMappers of roles, permissions and audit logs
EdgarEldy Sep 19, 2026
bb9b5aa
feat(auth): add the entity mappers of roles, permissions and audit logs
EdgarEldy Sep 19, 2026
be284fd
feat(auth): add the role, permission and audit log DAOs
EdgarEldy Sep 19, 2026
6840f29
feat(auth): add user paging, role assignment and last-admin queries
EdgarEldy Sep 19, 2026
95bde19
feat(auth): add AuditLogger with joined and independent transactions
EdgarEldy Sep 19, 2026
450a87f
feat(auth): implement roles, permissions and assignments in RbacService
EdgarEldy Sep 19, 2026
b731605
feat(auth): wire the RBAC beans and the optional admin bootstrap
EdgarEldy Sep 19, 2026
b9a1169
feat(ws): resolve permissions in CustomPermissionEvaluator
EdgarEldy Sep 19, 2026
b18a707
feat(ws): enable method security backed by the permission evaluator
EdgarEldy Sep 19, 2026
f25f7a9
feat(ws): add the RBAC payloads and converters
EdgarEldy Sep 19, 2026
fea7e3b
feat(ws): expose the RBAC endpoints with declarative permissions
EdgarEldy Sep 19, 2026
3d0fcd0
fix(ws): refine 401 versus 403 and name the invalid request parameters
EdgarEldy Sep 19, 2026
0945886
test(common): assert the V2 seed exactly
EdgarEldy Sep 19, 2026
c8b8cf1
test(auth): cover the RBAC DAOs against PostgreSQL
EdgarEldy Sep 19, 2026
165033f
test(auth): test the RBAC RowMappers and entity mappers
EdgarEldy Sep 19, 2026
aa72181
test(auth): unit test every RbacService operation with mocked DAOs
EdgarEldy Sep 19, 2026
f5cf45d
test(auth): test AuditLoggerImpl and AdminBootstrap
EdgarEldy Sep 19, 2026
98aa7ca
test(ws): add RBAC fixtures for token-based and database-backed tests
EdgarEldy Sep 19, 2026
c2ab81c
test(ws): test CustomPermissionEvaluator and the actor provider
EdgarEldy Sep 19, 2026
af363b3
test(ws): test the RBAC controllers with MockMvc
EdgarEldy Sep 19, 2026
8107daa
test(ws): check the permission matrix of the 14 RBAC endpoints
EdgarEldy Sep 19, 2026
65b1ddf
test(ws): run the RBAC flows on the real stack
EdgarEldy Sep 19, 2026
e2fcf7f
test(ws): prove the last-admin rule, including under concurrency
EdgarEldy Sep 19, 2026
a2e1da5
test(ws): test the admin bootstrap on the real context
EdgarEldy Sep 19, 2026
0aa9a43
fix(ws): never print a null parameter name in validation messages
EdgarEldy Sep 19, 2026
848397c
docs(readme): tick the feature/rbac tasks and document the dev admin …
EdgarEldy Sep 19, 2026
a213811
Merge pull request #3 from EdgarEldy/feature/rbac
EdgarEldy Sep 19, 2026
26ca072
feat(catalog): add the Category and Product entities and dto classes
EdgarEldy Sep 19, 2026
eef96e8
feat(catalog): add the RowMappers and entity mappers of the catalog
EdgarEldy Sep 19, 2026
e7ff607
feat(catalog): add the category and product DAOs
EdgarEldy Sep 19, 2026
3760e00
feat(catalog): implement the category and product services
EdgarEldy Sep 19, 2026
fecd079
feat(catalog): wire the catalog DAOs and services explicitly
EdgarEldy Sep 19, 2026
53f4b96
feat(ws): add the catalog payloads and converters
EdgarEldy Sep 19, 2026
bab6a02
feat(ws): expose the category and product endpoints
EdgarEldy Sep 19, 2026
f79baf8
feat(ws): import the catalog module into the shared context
EdgarEldy Sep 19, 2026
d966788
build(catalog): add Testcontainers test dependencies to the catalog m…
EdgarEldy Sep 19, 2026
1b535c1
test(catalog): cover the category and product DAOs against PostgreSQL
EdgarEldy Sep 19, 2026
c247a96
test(catalog): test the catalog RowMappers and entity mappers
EdgarEldy Sep 19, 2026
aeee5c5
test(catalog): unit test the category and product services
EdgarEldy Sep 19, 2026
2bfaa85
test(ws): test the catalog controllers with MockMvc
EdgarEldy Sep 19, 2026
84fb7dd
test(ws): check the permission matrix of the 10 catalog endpoints
EdgarEldy Sep 19, 2026
1e85f54
test(ws): run the catalog flows on the real stack
EdgarEldy Sep 19, 2026
df70d22
docs(readme): tick the feature/catalog tasks
EdgarEldy Sep 19, 2026
de86bd6
fix(catalog): bound the price before scaling and handle a vanished ca…
EdgarEldy Sep 19, 2026
1b01988
Merge pull request #4 from EdgarEldy/feature/catalog
EdgarEldy Sep 19, 2026
575b813
feat(customer): add the Customer entity and CustomerDto
EdgarEldy Sep 19, 2026
0431c53
feat(customer): add the customer RowMapper and entity mapper
EdgarEldy Sep 19, 2026
378cef4
feat(customer): add the customer DAO
EdgarEldy Sep 19, 2026
3c3095e
feat(customer): implement the customer service
EdgarEldy Sep 19, 2026
27485bc
feat(customer): wire the customer DAO and service explicitly
EdgarEldy Sep 19, 2026
f26eeab
feat(ws): add the customer payloads and converter
EdgarEldy Sep 19, 2026
53a00aa
feat(ws): expose the customer endpoints
EdgarEldy Sep 19, 2026
b5f559d
feat(ws): import the customer module into the shared context
EdgarEldy Sep 19, 2026
6c7c8e8
build(customer): add Testcontainers test dependencies to the customer…
EdgarEldy Sep 19, 2026
bebafab
test(customer): cover the customer DAO against PostgreSQL
EdgarEldy Sep 19, 2026
47acf9c
test(customer): test the customer RowMapper and entity mapper
EdgarEldy Sep 19, 2026
993ac0e
test(customer): unit test the customer service
EdgarEldy Sep 19, 2026
2a6ede5
test(ws): test the customer controller with MockMvc
EdgarEldy Sep 19, 2026
6168879
test(ws): check the permission matrix of the customer endpoints
EdgarEldy Sep 19, 2026
34f99c4
test(ws): run the customer flows on the real stack
EdgarEldy Sep 19, 2026
4792b5e
docs(readme): tick the feature/customer tasks
EdgarEldy Sep 19, 2026
2886b43
Merge pull request #5 from EdgarEldy/feature/customer
EdgarEldy Sep 19, 2026
fc9a236
feat(order): add the Order entity and OrderDto
EdgarEldy Sep 19, 2026
1b26545
feat(order): add the order RowMapper and entity mapper
EdgarEldy Sep 19, 2026
8a626fc
feat(order): add the order DAO with optional filters
EdgarEldy Sep 19, 2026
c1e3e2a
feat(order): implement the order service on top of the catalog and cu…
EdgarEldy Sep 19, 2026
927bac4
feat(order): wire the order DAO and service explicitly
EdgarEldy Sep 19, 2026
f7e97bd
feat(ws): add the order payloads and converter
EdgarEldy Sep 19, 2026
9a1a4d8
feat(ws): expose the order endpoints
EdgarEldy Sep 19, 2026
bd27d9a
feat(ws): import the order module into the shared context
EdgarEldy Sep 19, 2026
c5fb3cf
build(order): add Testcontainers test dependencies to the order module
EdgarEldy Sep 19, 2026
1b33ba1
test(order): cover the order DAO against PostgreSQL
EdgarEldy Sep 19, 2026
97ade20
test(order): test the order RowMapper and entity mapper
EdgarEldy Sep 19, 2026
fe066f3
test(order): unit test the order service with mocked customer and pro…
EdgarEldy Sep 19, 2026
205e770
test(ws): test the order controller with MockMvc
EdgarEldy Sep 19, 2026
6df2919
test(ws): check the permission matrix of the order endpoints
EdgarEldy Sep 19, 2026
eaf6676
test(ws): run the order flows on the real stack
EdgarEldy Sep 19, 2026
79f133c
fix(ws): refuse a decimal where an integer is expected
EdgarEldy Sep 19, 2026
f8cd73f
docs(readme): tick the feature/order tasks and correct the order depe…
EdgarEldy Sep 19, 2026
87694e4
refactor(order): drop an unreachable second total check
EdgarEldy Sep 19, 2026
fb2bbb5
Merge pull request #6 from EdgarEldy/feature/order
EdgarEldy Sep 19, 2026
e482c50
docs(readme): correct the run instructions to match the packaged setup
EdgarEldy Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Keep the build context small and free of local files (keys, env files, git data)
*
!pom.xml
!core/
!ws/
!mvnw
!.mvn/
**/target/
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copy to .env (ignored by git) and adjust. Read by docker-compose.yml only.
DB_NAME=spring_jdbc_tutorial
DB_USER=spring
DB_PASSWORD=change-me
APP_PORT=8080
32 changes: 32 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Branch

<!-- e.g. feature/core-architecture -->

## Task checklist

<!-- Copy the relevant section's checklist from README.md and check off each item. -->

- [ ]

## Commit summary

<!-- One line per group of commits, summarizing what changed and why. -->

## Test plan

- [ ] Tests exist at every layer the branch's checklist calls for (DAO, RowMapper, EntityMapper, service, controller)
- [ ] Each DAO test class loads its own dedicated SQL fixture file
- [ ] `./mvnw clean verify` is green on the whole reactor

## Code review checklist

- [ ] No business logic in controllers; controllers only see services and `payload/` types
- [ ] DAOs only use `entity/` types, services only `dto/` types at their boundary
- [ ] Every response, success or error, is an `ApiResponse<T>` (errors through `GlobalExceptionHandler`, 401/403 through the security handlers)
- [ ] Permission checks are declarative (`@PreAuthorize("hasPermission(...)")`), no manual permission `if`
- [ ] No `@Repository`, `@Service` or `@Component` on a DAO or service; every bean is an explicit `@Bean` in `DaoConfig`/`ServiceConfig`
- [ ] No Lombok, no `record`, no ORM (`JdbcTemplate` only)
- [ ] Every RBAC mutation calls `AuditLogger`
- [ ] The database schema only changes through a Flyway migration
- [ ] Test methods are named `_NN_Should<Outcome>_When<Condition>`
- [ ] Commits are atomic, follow Conventional Commits with a scope, no em dash, no tool attribution
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
cache: maven

# No "services: postgres" block on purpose. The DAO tests start their own PostgreSQL
# container through Testcontainers and the Docker daemon already available on
# ubuntu-latest, exactly as they do locally, so nothing is provisioned by the workflow.
- name: Build and test the whole reactor
run: ./mvnw -B verify
43 changes: 43 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: PR checks

on:
pull_request:
branches: [master, develop]

jobs:
commit-lint:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Validate commit messages (Conventional Commits)
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail

pattern='^(feat|fix|refactor|test|docs|chore|build|ci|style|perf)\([a-z0-9.,/_-]+\): .{1,100}$'
failed=0

while IFS= read -r subject; do
[ -z "$subject" ] && continue
if [[ "$subject" =~ $pattern ]]; then
echo "OK: $subject"
else
echo "INVALID: $subject"
failed=1
fi
done < <(git log "$BASE_SHA..$HEAD_SHA" --no-merges --pretty=format:'%s')

if [ "$failed" -ne 0 ]; then
echo ""
echo "One or more commit messages do not follow Conventional Commits."
echo "Expected format: <type>(<scope>): <short summary>"
echo "Allowed types: feat, fix, refactor, test, docs, chore, build, ci, style, perf"
exit 1
fi
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Multi-stage image for the packaged WAR.
# Stage 1 compiles and packages with Maven, stage 2 is a Tomcat 10.1 runtime holding only the WAR.

FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build

# Copy the poms first so Docker caches the dependency download until a pom changes.
COPY pom.xml ./
COPY core/pom.xml core/pom.xml
COPY core/common/pom.xml core/common/pom.xml
COPY core/auth/pom.xml core/auth/pom.xml
COPY core/catalog/pom.xml core/catalog/pom.xml
COPY core/customer/pom.xml core/customer/pom.xml
COPY core/order/pom.xml core/order/pom.xml
COPY ws/pom.xml ws/pom.xml
RUN mvn -B -q dependency:go-offline -DskipTests || true

COPY core ./core
COPY ws ./ws
# Tests are skipped here: the DAO tests need Testcontainers, i.e. a Docker daemon that a build
# stage does not have. They run in CI with mvn verify instead.
RUN mvn -B -q package -DskipTests

FROM tomcat:10.1-jre17-temurin
# The README documents the API under /spring-jdbc-tutorial/api/v1: the WAR name is the context path.
RUN rm -rf /usr/local/tomcat/webapps/*
COPY --from=build /build/ws/target/ws.war /usr/local/tomcat/webapps/spring-jdbc-tutorial.war

# Run as a non-root user so a compromised process has no rights on the container.
RUN useradd --system --no-create-home spring \
&& chown -R spring /usr/local/tomcat/webapps /usr/local/tomcat/logs /usr/local/tomcat/temp /usr/local/tomcat/work /usr/local/tomcat/conf
USER spring

EXPOSE 8080
CMD ["catalina.sh", "run"]
Loading
Loading