Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fe75932
docs: add docs/TESTING.md, absorb TEST-ANALYSIS.md, repoint @Disabled…
devondragon Aug 15, 2026
ebf9afe
docs: add extending guide for framework extension points
devondragon Aug 15, 2026
40949c9
build: multi-stage Dockerfile on Java 21
devondragon Aug 15, 2026
26edbf4
build: keep developmentOnly dependencies out of the packaged jar
devondragon Aug 15, 2026
1821513
fix: make the documented run paths work from a fresh clone
devondragon Aug 15, 2026
c08df71
chore: remove TempTest startup debug logger
devondragon Aug 15, 2026
1177ec7
merge sdd/task-4: docs/TESTING.md
devondragon Aug 15, 2026
7269f02
docs: correct event api auth, form action, and mfa claims in extendin…
devondragon Aug 15, 2026
360b379
merge sdd/task-5: docs/EXTENDING.md
devondragon Aug 15, 2026
019b422
fix: session-scope DemoSessionProfile
devondragon Aug 15, 2026
1911144
feat: admin lock/unlock account endpoints
devondragon Aug 15, 2026
02bc99d
docs: add configuration and development guides
devondragon Aug 15, 2026
e556a59
merge sdd/task-9: session-scope DemoSessionProfile, admin lock/unlock…
devondragon Aug 15, 2026
e7fdac9
docs: fix reviewer findings in configuration and development guides
devondragon Aug 15, 2026
d3d83f3
docs: fix mfa row's challenge-page unprotect claim
devondragon Aug 15, 2026
d5a457c
fix: make the keycloak oidc stack work from a host browser
devondragon Aug 15, 2026
d85b4d1
docs: describe the keycloak stack in keycloak/README.md
devondragon Aug 15, 2026
1bcde9c
merge sdd/task-3: docs/CONFIGURATION.md and docs/DEVELOPMENT.md
devondragon Aug 15, 2026
abff287
fix: tighten the keycloak stack redirect uri, health gate and readme
devondragon Aug 15, 2026
a35847f
docs: reconcile keycloak profile docs with the tracked yml and realm …
devondragon Aug 15, 2026
0f74113
merge sdd/task-3b: reconcile config/dev docs with keycloak changes
devondragon Aug 15, 2026
329da6f
docs: add docs/AUTHENTICATION.md
devondragon Aug 15, 2026
77ff854
docs: refresh application.yml line citations in extending guide
devondragon Aug 15, 2026
ae6e339
merge sdd/task-5b: refresh extending guide line citations
devondragon Aug 15, 2026
b001ebd
docs: correct the mfa walkthrough, keycloak start and oauth callback …
devondragon Aug 15, 2026
0ab4efe
merge sdd/task-6: docs/AUTHENTICATION.md
devondragon Aug 15, 2026
f18abeb
docs: rewrite README as a demo overview that links to docs/
devondragon Aug 15, 2026
cd9ff90
docs: delete superseded CONFIG.md and docs/HELP.md, correct CLAUDE.md…
devondragon Aug 15, 2026
24006e5
docs: add 2026-08-15 changelog entry
devondragon Aug 15, 2026
dee5ae8
fix: comment out the broken keycloak block in application-local.yml-e…
devondragon Aug 15, 2026
0b65c4d
fix: restore dropped unprotectedURIs and skip verification email in t…
devondragon Aug 15, 2026
9ba5ef0
docs: correct testing commands, profile facts, and stale citations
devondragon Aug 15, 2026
7444227
docs: log the local quick start, unprotectedURIs, and keycloak mail f…
devondragon Aug 15, 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
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Keep the build context small and keep local files out of the image.
.git/
.github/
.gradle/
build/
build.bak/
.superpowers/
.vscode/
.idea/
docs/
playwright/
node_modules/
**/node_modules/
logs/
*.log

# Gitignored local config holding real credentials: must never reach an image.
.env
src/main/resources/application-local.yml
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ application-local.yml
/project_concatenated.txt
.env
/repomix-output.txt
src/main/resources/application-docker-keycloak.yml
# src/main/resources/application-docker-keycloak.yml is tracked on purpose: it holds only ${ENV_VAR}
# placeholders, and the Keycloak stack builds the app image from src/, so it must be in the repo.

# VS Code: personal settings stay local, shared tasks.json is tracked
.vscode/*
Expand Down
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,66 @@ the library.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## 2026-08-15

### Added
- Admin lock/unlock API (`POST /admin/lockAccount`, `POST /admin/unlockAccount`), guarded by
`ADMIN_PRIVILEGE` and backing the admin actions page, whose JavaScript already called those paths
- `keycloak/README.md`: contents, ports, credentials, and realm re-export for the Keycloak stack
- `.dockerignore`, so the image build context excludes `build/`, `.git/`, and local config

### Changed
- Rewrote `README.md` and split its content into `docs/CONFIGURATION.md`, `docs/DEVELOPMENT.md`,
`docs/TESTING.md`, `docs/EXTENDING.md`, `docs/AUTHENTICATION.md`, and `keycloak/README.md`
- `Dockerfile` is now multi-stage on Java 21: a JDK stage runs `bootJar` inside the image, a JRE
stage runs it, so `docker compose up --build` works from a fresh clone with no local Gradle build
- The Docker demo stack sets `USER_REGISTRATION_SENDVERIFICATIONEMAIL=false` in `compose.yaml`, so
registered accounts are enabled immediately instead of waiting on mail the relay cannot deliver
- Moved `spring.docker.compose.file: compose.dev.yaml` from `application-local.yml-example` into base
`application.yml`, so `./gradlew bootRun` starts its database without a copied config file
- `build.gradle` no longer extends `runtimeOnly` from `developmentOnly`, keeping
`spring-boot-docker-compose` out of the packaged jar (it made containerized runs fail at startup)
- `application-local.yml-example` now points at the `compose.dev.yaml` database and seeds
`data-local.sql`, so the `local` profile has sample events
- Added `/actuator/health` to `user.security.unprotectedURIs` for container healthchecks; the rest of
`/actuator` still requires a login
- `src/main/resources/application-docker-keycloak.yml` is now tracked; it holds only environment
variable placeholders, so there is nothing to copy before running the Keycloak stack
- `mise.toml` pins Java 21
- `@Disabled` test annotations now point at `docs/TESTING.md`

### Fixed
- Keycloak OIDC stack, which could not complete a login: the realm export is now named `demo` rather
than `master` (Keycloak skips a `master` import), the client secret matches `keycloak.env`,
authorization services that blocked the import were removed, a `demo` user with an email address
was added, the browser-facing and container-facing Keycloak URLs are split, the client's redirect
URI is narrowed to the exact callback, and the healthcheck probes the realm's discovery document
- `DemoSessionProfile` is now `@SessionScopedProfile`; as a plain `@Component` it was a singleton
shared by every HTTP session
- `DomainRegistrationGuard`'s Javadoc link to the framework's registration guard documentation
- The `local` quick start, which died at startup once `application-local.yml-example` was copied into
place: the example's masked Keycloak `client-secret` was not valid YAML, and its Keycloak
`issuer-uri` pointed at a host that does not resolve but that Spring Boot fetches at startup. The
Keycloak client registration and provider blocks are now commented out, with a pointer to the
Keycloak stack for OIDC
- `application-playwright-test.yml` replaced `user.security.unprotectedURIs` wholesale and lost
`/user/registration/passwordless`, `/webauthn/authenticate/**`, `/login/webauthn`, and
`/actuator/health`; the override now matches the base list
- `docker-compose-keycloak.yml` sets `USER_REGISTRATION_SENDVERIFICATIONEMAIL: "false"` like
`compose.yaml`, so form registration in that stack no longer creates an account waiting on mail the
bundled relay cannot deliver

### Removed
- Root `CONFIG.md` (a stale copy of the framework's property reference), `docs/HELP.md` (Spring
Initializr boilerplate), `docs/TEST-ANALYSIS.md` (absorbed into `docs/TESTING.md`), and the
`TempTest` startup debug logger

### Dependencies
- **Spring User Framework 5.3.0**, Spring Boot 4.1.0 (2026-08-14)
- Backfill of the bumps between the entries: framework 4.3.1 (2026-03-22, missing from that entry),
4.4.0, 5.0.0, and 5.0.1 (2026-06-15), 5.1.0 (2026-07-10), 5.1.1 (2026-07-24), 5.2.0 (2026-08-12);
Gradle wrapper 9.4.1 to 9.7.0 (2026-08-13). Spring Boot stayed on 4.0.4 until the 4.1.0 bump above

## 2026-03-22

### Changed
Expand Down
23 changes: 15 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
# Standard run
./gradlew bootRun

# Run with specific profile (local, dev, test, docker-keycloak)
# Run with specific profile (see "Configuration Profiles" below for the full list)
./gradlew bootRun --args='--spring.profiles.active=local'

# Build and run with debugging
Expand Down Expand Up @@ -60,25 +60,32 @@ This is a Spring Boot demo application showcasing the [Spring User Framework](ht

### Important Conventions

1. **No Custom User Entity**: This demo uses the framework's User entity directly. Custom user data goes in separate entities (like UserProfile).
1. **No Custom User Entity**: This demo uses the framework's User entity directly. Custom user data goes in separate entities (like `DemoUserProfile`).

2. **Configuration Profiles**:
- `local`: Development with local database
- `test`: Integration testing with H2
- `dev`: Debug-heavy dev server; also what the `compose.yaml` Docker stack runs
- `prd`: Production settings (env-driven datasource and URLs, strict cookies)
- `test`: Integration testing with H2, applied automatically by `./gradlew test`
- `playwright-test`: Enables the test-only API for E2E runs; combine with a base profile
- `docker-keycloak`: OIDC integration with Keycloak
- `registration-guard`: Enables domain-restricted registration (form/passwordless only)
- `mfa`: Enables multi-factor authentication (PASSWORD + WEBAUTHN); combine with another profile, e.g. `local,mfa`

3. **Template Organization**: All Thymeleaf templates are in `src/main/resources/templates/` with subdirectories for user management (`email/`, `password/`, etc.)
3. **Template Organization**: All Thymeleaf templates are in `src/main/resources/templates/`, with subdirectories `user/` (including `user/mfa/`), `mail/`, `event/`, `admin/`, and `fragments/`

4. **Test Data Builders**: Use the builder classes in `src/test/java/com/devondragon/springdemo/test/data/` for consistent test data creation.
4. **Test Data Builders**: Use the builder classes in `src/test/java/com/digitalsanctuary/spring/user/test/builders/` for consistent test data creation.

### Framework Integration Points

The application demonstrates framework usage through:
- Custom controllers that extend framework functionality (EventController)
- Service extensions (CustomUserService extends UserService)
- Custom controllers that build on framework functionality (`event/EventAPIController`, `event/EventPageController`)
- Service extensions (`service/CustomUserEmailService` extends the framework's `UserEmailService` and is `@Primary`)
- Configuration of framework components via application.yml
- Event listeners for user lifecycle events

When modifying user-related functionality, check if the Spring User Framework already provides it before implementing custom solutions.
When modifying user-related functionality, check if the Spring User Framework already provides it before implementing custom solutions.

## Documentation

Demo documentation lives in `docs/`: `CONFIGURATION.md` (profiles and properties), `DEVELOPMENT.md` (running and building), `TESTING.md` (JUnit and Playwright), `EXTENDING.md` (framework extension points), `AUTHENTICATION.md` (every auth path). The Keycloak stack has its own `keycloak/README.md`. Update these rather than growing `README.md`.
77 changes: 0 additions & 77 deletions CONFIG.md

This file was deleted.

24 changes: 20 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
FROM eclipse-temurin:17-jre-jammy
# Stage 1: build the boot jar inside the image, so no local Gradle build is required.
# JDK 21 matches the toolchain declared in build.gradle.
FROM eclipse-temurin:21-jdk-jammy AS build

# Install wget for healthcheck
WORKDIR /workspace

# Resolve dependencies in their own layer so editing sources does not re-download them.
COPY gradlew gradlew
COPY gradle gradle
COPY build.gradle settings.gradle ./
RUN ./gradlew --no-daemon dependencies --configuration runtimeClasspath > /dev/null

COPY src src
RUN ./gradlew --no-daemon bootJar -x test

# Stage 2: runtime image, JRE only.
FROM eclipse-temurin:21-jre-jammy

# Install wget for the healthcheck (the JRE image has no curl)
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*

# Add a non-root user to run the application
Expand All @@ -9,8 +25,8 @@ RUN groupadd -r spring && useradd -r -g spring spring
# Set working directory
WORKDIR /opt/app

# Copy the JAR file
COPY build/libs/*SNAPSHOT.jar app.jar
# Copy the JAR file built in stage 1
COPY --from=build /workspace/build/libs/*-SNAPSHOT.jar app.jar

# Set ownership of the files
RUN chown -R spring:spring /opt/app
Expand Down
Loading
Loading