chore: repurpose as Spring Boot starter examples repo#1
Merged
Conversation
Strip the GitHub demo-repository template and reframe this repo as a
home for runnable examples of devslab-kr Spring Boot starters and
libraries. Each future demo will live in its own top-level directory
as a standalone Gradle project (independent settings.gradle.kts and
gradlew), so demos can drift in JDK / Spring Boot baseline / starter
versions without affecting each other.
Changes:
- Remove demo-template leftovers: index.html, package.json, and the
proof-html workflow (kept auto-assign.yml — still useful here).
- Rewrite README to document the multi-demo layout, conventions, and
how to add a new demo.
- Add a Gradle-flavoured .gitignore.
- Add .github/workflows/ci.yml with a detect + matrix strategy:
- On PRs, build only demos whose files changed.
- On main pushes, build every demo (catches drift from external
starter version bumps).
- Detection scans for top-level directories containing a
build.gradle.kts, so adding a demo needs no workflow edits.
No demos exist yet; the first one will land in a follow-up PR to
establish the template other demos can copy from.
This was referenced May 23, 2026
jlc488
added a commit
that referenced
this pull request
May 23, 2026
Two bugs in the workflow from #1 conspired to make path-filtered builds silently skip on every PR. Discovered while opening #2, the first demo PR, where the build job was reported as 'skipping' even though easy-paging-demo/ was clearly the changed directory. Bug 1 — GitHub Actions ternary trap on fetch-depth fetch-depth: ${{ github.event_name == 'pull_request' && 0 || 1 }} The intent was "0 (full history) on PRs, 1 (shallow) otherwise". But in Actions expressions, `0` is falsy, so `0 || 1` short-circuits to `1`. The expression evaluated to `1` on both PRs and main pushes, leaving PR checkouts with no history beyond the merge commit. Bug 2 — silent failure on git diff mapfile -t changed_files < <(git diff --name-only "$base" HEAD) With bug 1 in effect, `git diff` exited with "fatal: bad object" because the base SHA wasn't fetched. But process substitution does not propagate the subshell's exit status under `set -e`, so the script kept going with an empty `changed_files` array — and therefore an empty matrix and a "skipped" build job. CI looked green, but it had built nothing. Fix: - fetch-depth: 0 unconditionally. Cost is negligible for this repo and removes the ternary footgun entirely. - Run git diff in a separate statement so `set -e` actually catches a non-zero exit, with an explicit ::error:: pointer to the likely cause (shallow checkout) so the next person debugging this gets a head start. Verification will happen on the next PR (the rebase of #2) — the matrix should populate with easy-paging-demo and the build job should actually execute ./gradlew build instead of skipping.
This was referenced May 23, 2026
jlc488
added a commit
that referenced
this pull request
May 23, 2026
Fourth easy-paging demo, completing the original starter coverage plan. Showcases the reactive companion artifact (kr.devslab:easy-paging-spring-boot-starter-reactive:0.4.0) — WebFlux + Spring Data R2DBC against real PostgreSQL via Testcontainers — so the same JSON pagination envelope as the MVC/MyBatis demos is served as Mono<PageResponse<T>> over a non-blocking stack. Reuses the Docker pattern established in easy-paging-postgres-demo: docker-compose.yml for `bootRun`, Testcontainers + @Serviceconnection for `./gradlew test`. The compose file binds host port 5433 (not 5432) so the reactive and postgres demos can run side by side. Architectural difference worth knowing about (also flagged in the demo's README): the MVC demos use the @AutoPaginate aspect, which is MyBatis/PageHelper-specific. On the reactive path there's no per-thread context to hook into, so the reactive starter instead exposes an explicit helper (R2dbcOffsetPagingSupport.paginate) the service calls directly. Wire-level contract is unchanged. Demo content: - Article entity (id, title, author, publishedAt, viewCount) — newsfeed use case, distinct from the postgres demo's Product so readers can see the entity mapping for a different domain. - 500 rows seeded via generate_series, deterministically across 5 authors (100 each), so the integration test can assert exact totals. - Service is a one-liner around R2dbcOffsetPagingSupport.paginate, with an optional Criteria.where("author") filter to mirror the postgres demo's ?category=. - Spring Data Relational entity mapping: @table on the class, @column only on fields where camelCase ≠ snake_case (publishedAt, viewCount). The integration test (ArticleControllerIT) covers: - envelope metadata on unfiltered listing, - ?author= filter narrowing totalElements from 500 to 100, - sort=id,asc returning Article #1 as content[0], - last page reporting last=true correctly. Uses WebTestClient (WebFlux) instead of MockMvc (servlet) and asserts via JSON paths — same shape as the postgres demo's tests with the reactive client swap. Top-level README updated to list this demo after the postgres one and before the ssrf-guard rows. Local verification note: my Windows + Docker Desktop setup has the named-pipe quirk where Testcontainers ends up talking to the CLI proxy pipe (com.docker.desktop.address=npipe://...docker_cli) and getting a 400 placeholder response, so the local `./gradlew test` couldn't reach a real Docker engine. Compile passes cleanly, and CI on a clean Ubuntu runner (unix socket, no proxies) is the meaningful verification — that will run on this PR.
jlc488
added a commit
that referenced
this pull request
May 23, 2026
…#7) * feat: add easy-paging-reactive-demo Fourth easy-paging demo, completing the original starter coverage plan. Showcases the reactive companion artifact (kr.devslab:easy-paging-spring-boot-starter-reactive:0.4.0) — WebFlux + Spring Data R2DBC against real PostgreSQL via Testcontainers — so the same JSON pagination envelope as the MVC/MyBatis demos is served as Mono<PageResponse<T>> over a non-blocking stack. Reuses the Docker pattern established in easy-paging-postgres-demo: docker-compose.yml for `bootRun`, Testcontainers + @Serviceconnection for `./gradlew test`. The compose file binds host port 5433 (not 5432) so the reactive and postgres demos can run side by side. Architectural difference worth knowing about (also flagged in the demo's README): the MVC demos use the @AutoPaginate aspect, which is MyBatis/PageHelper-specific. On the reactive path there's no per-thread context to hook into, so the reactive starter instead exposes an explicit helper (R2dbcOffsetPagingSupport.paginate) the service calls directly. Wire-level contract is unchanged. Demo content: - Article entity (id, title, author, publishedAt, viewCount) — newsfeed use case, distinct from the postgres demo's Product so readers can see the entity mapping for a different domain. - 500 rows seeded via generate_series, deterministically across 5 authors (100 each), so the integration test can assert exact totals. - Service is a one-liner around R2dbcOffsetPagingSupport.paginate, with an optional Criteria.where("author") filter to mirror the postgres demo's ?category=. - Spring Data Relational entity mapping: @table on the class, @column only on fields where camelCase ≠ snake_case (publishedAt, viewCount). The integration test (ArticleControllerIT) covers: - envelope metadata on unfiltered listing, - ?author= filter narrowing totalElements from 500 to 100, - sort=id,asc returning Article #1 as content[0], - last page reporting last=true correctly. Uses WebTestClient (WebFlux) instead of MockMvc (servlet) and asserts via JSON paths — same shape as the postgres demo's tests with the reactive client swap. Top-level README updated to list this demo after the postgres one and before the ssrf-guard rows. Local verification note: my Windows + Docker Desktop setup has the named-pipe quirk where Testcontainers ends up talking to the CLI proxy pipe (com.docker.desktop.address=npipe://...docker_cli) and getting a 400 placeholder response, so the local `./gradlew test` couldn't reach a real Docker engine. Compile passes cleanly, and CI on a clean Ubuntu runner (unix socket, no proxies) is the meaningful verification — that will run on this PR. * chore(reactive-demo): verbose test logging for CI diagnosis * fix(reactive-demo): register WebFlux argument resolvers for Pageable + Sort First CI run on PR #7 failed all four ArticleControllerIT tests with 500 INTERNAL_SERVER_ERROR, and the verbose-logging commit surfaced the real cause: java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.data.domain.Pageable Spring Boot's SpringDataWebAutoConfiguration only registers PageableHandlerMethodArgumentResolver for Spring MVC; the @EnableSpringDataWebSupport annotation is also servlet-only. WebFlux apps that want `Pageable pageable` method parameters have to wire ReactivePageableHandlerMethodArgumentResolver (and the matching Sort one) themselves via a WebFluxConfigurer bean. PagingWebFluxConfig now does exactly that. The Javadoc on the class documents the failure mode so the next person reading the file sees straight away why this seemingly redundant boilerplate exists. Trap worth documenting (and the kind of thing future reactive demos in this repo will need to repeat — the postgres demo, which uses servlet MVC, doesn't hit this because Spring Boot auto-wires the servlet resolver for it).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Strip the GitHub demo-repository template and reframe this repo as a home for runnable examples of devslab-kr Spring Boot starters and libraries. Sets up the structural scaffolding (README, CI, .gitignore) so the first demo (and every demo after) can be added with zero workflow changes.
What changed
Design choice worth noting
Each demo will be a standalone Gradle project (its own `settings.gradle.kts` and `gradlew`), not a subproject of a shared root build. This means:
Trade-off: slightly more boilerplate per demo (each has its own wrapper). Worth it for the isolation.
What's next
No demos exist yet. The first one (`easy-paging-demo`) lands in a follow-up PR and establishes the template other demos copy from.
Test plan