Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ Spring Boot 3.3–3.5 사용 중인 앱용. 스타터의 [`3.x` 브랜치](https
| [`api-log-mybatis-demo`](api-log-mybatis-demo/) | **MyBatis 백엔드** — Spring MVC + `RestApiClientUtil` + `MybatisApiLogWriter`. 번들 `ApiLogMapper`는 request_id 조회용, `recent` / `by-event` 쿼리는 데모가 커스텀 `ApiLogQueryMapper` (xml) 추가. 이미 MyBatis 쓰고 JPA 안 원하는 팀용. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/api-log-mybatis)](https://central.sonatype.com/artifact/kr.devslab/api-log-mybatis) |
| [`api-log-r2dbc-demo`](api-log-r2dbc-demo/) | **R2DBC 백엔드 (리액티브)** — WebFlux + `ReactiveApiClientUtil` (`Mono` 기반) + `R2dbcApiLogWriter`. 리더는 `DatabaseClient`로 `Flux<ApiLogView>` 스트리밍. HTTP 경로 전체 논블로킹; api-log 쓰기도 논블로킹. 요청 경로에 JDBC가 전혀 없는 WebFlux 앱용. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/api-log-r2dbc)](https://central.sonatype.com/artifact/kr.devslab/api-log-r2dbc) |

### devslab-kit

Spring Boot 4 플랫폼 스타터 — 인증, RBAC + 그룹 + ABAC, 멀티테넌시, 동적 메뉴, 감사 로깅, 관리자 REST API를 모두 자동 구성으로. 전체 문서: [devslab-kit.devslab.kr](https://devslab-kit.devslab.kr).

| 데모 | 보여주는 것 | Maven Central |
| --- | --- | --- |
| [`devslab-kit-demo`](devslab-kit-demo/) | **플랫폼 코드가 전혀 없는** 소비자 앱 — 스타터만 추가하면 인증, RBAC + ABAC, 멀티테넌시, 동적 메뉴, 감사, 최초 관리자 부트스트랩, 관리자 REST API가 올라옴. PostgreSQL + Redis(분산 캐시); `bootRun`은 Docker Compose, 테스트는 Testcontainers + `@ServiceConnection`. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/devslab-kit-spring-boot-starter)](https://central.sonatype.com/artifact/kr.devslab/devslab-kit-spring-boot-starter) |

## 컨벤션

- 각 데모는 **독립 Gradle 프로젝트** — 자체 `settings.gradle.kts`, `build.gradle.kts`, `gradlew`를 가짐. 루트 빌드를 공유하지 않으므로 의존성 버전이나 JDK 타겟이 독립적으로 변할 수 있음.
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ Async API-call logging into PostgreSQL JSONB via the [api-log](https://github.co
| [`api-log-mybatis-demo`](api-log-mybatis-demo/) | **MyBatis backend** — Spring MVC + `RestApiClientUtil` + `MybatisApiLogWriter`. Uses the bundled `ApiLogMapper` for by-request lookup, plus a custom `ApiLogQueryMapper` (xml) for `recent` / `by-event` queries. For teams already on MyBatis who don't want JPA. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/api-log-mybatis)](https://central.sonatype.com/artifact/kr.devslab/api-log-mybatis) |
| [`api-log-r2dbc-demo`](api-log-r2dbc-demo/) | **R2DBC backend (reactive)** — WebFlux + `ReactiveApiClientUtil` (`Mono`-based) + `R2dbcApiLogWriter`. Reader uses `DatabaseClient` for streaming `Flux<ApiLogView>`. Entire HTTP path is non-blocking; api-log writes also non-blocking. For WebFlux apps that have no JDBC anywhere on the request path. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/api-log-r2dbc)](https://central.sonatype.com/artifact/kr.devslab/api-log-r2dbc) |

### devslab-kit

Spring Boot 4 platform starter — authentication, RBAC + groups + ABAC, multi-tenancy, dynamic menus, audit logging, and an admin REST API, all from auto-configuration. Full docs at [devslab-kit.devslab.kr](https://devslab-kit.devslab.kr).

| Demo | Showcases | Maven Central |
| --- | --- | --- |
| [`devslab-kit-demo`](devslab-kit-demo/) | A plain consumer app with **no platform code of its own** — adding the starter brings up auth, RBAC + ABAC, multi-tenancy, dynamic menus, audit, the first-admin bootstrap, and the admin REST API. PostgreSQL + Redis (distributed cache); Docker Compose for `bootRun`, Testcontainers + `@ServiceConnection` for tests. | [![Maven Central](https://img.shields.io/maven-central/v/kr.devslab/devslab-kit-spring-boot-starter)](https://central.sonatype.com/artifact/kr.devslab/devslab-kit-spring-boot-starter) |

## Conventions

- Each demo is a **standalone Gradle project** — its own `settings.gradle.kts`, `build.gradle.kts`, and `gradlew`. Demos do not share a root build, so their dependency versions and JDK targets can drift independently.
Expand Down
69 changes: 69 additions & 0 deletions devslab-kit-demo/README.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# devslab-kit-demo

> **[devslab-kit](https://github.com/devslab-kr/devslab-kit)**(Spring Boot 4 플랫폼 스타터)를 PostgreSQL + Redis에서 사용하는 최소 앱.

[English](./README.md)

이 앱에는 **플랫폼 코드가 전혀 없습니다.** 스타터를 추가하고 데이터베이스를 가리키기만
하면 인증, RBAC + 그룹 + ABAC, 멀티테넌시, 동적 메뉴, 감사 로깅, 최초 관리자 부트스트랩,
관리자 REST API가 모두 자동 구성으로 제공됩니다.

> **설정 불필요.** 앱 자체 패키지(`kr.devslab.example.*`)에 평범한
> `@SpringBootApplication` 하나면 충분합니다 —
> [`DevslabKitDemoApplication`](src/main/java/kr/devslab/example/devslabkit/DevslabKitDemoApplication.java)
> 참고. `scanBasePackages`·`@EntityScan`·`@EnableJpaRepositories` 모두 불필요:
> 스타터의 자동 구성이 kit의 JPA 엔티티·리포지토리와 관리자 REST API를 직접
> 등록하며, 소비자가 스캔 범위를 넓히는 게 아니라 스타터가 알아서 넓힙니다.

## 요구 사항

- Java 21+
- Docker (Compose / Testcontainers로 PostgreSQL + Redis 기동)

## 실행

```bash
./gradlew bootRun
```

`spring-boot-docker-compose`가 `compose.yaml`(Postgres + Redis)을 자동 기동하고, kit이
Flyway 마이그레이션을 실행하며, 최초 관리자 부트스트랩이 `default` 테넌트에 `admin`/`admin`
사용자를 시드합니다.

로그인해서 JWT 받기:

```bash
curl -s localhost:8080/admin/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"tenantId":"default","loginId":"admin","password":"admin"}'
```

[관리자 콘솔](https://github.com/devslab-kr/devslab-kit-admin-ui)을
`http://localhost:8080`에 연결하면 같은 API 위에서 UI를 쓸 수 있습니다.

## 테스트 실행 (Docker만 필요)

```bash
./gradlew test
```

Testcontainers가 일회용 Postgres + Redis를 띄우고, 테스트가 전체 컨텍스트를 부팅해
플랫폼 빈이 배선됐는지 확인합니다.

## 이 데모가 보여주는 것

- **스타터만 추가하면 됩니다.** `build.gradle.kts`는
`kr.devslab:devslab-kit-spring-boot-starter`와 플랫폼이 사용하는 Spring 스타터(web,
security, JPA, Flyway, data-redis)를 선언합니다 — kit은 런타임 선택을 강요하지 않습니다.
- **코드가 아니라 설정.** 모든 것은 `application.yaml`의 `devslab.kit.*`로 제어합니다 —
테넌트 모드/리졸버, JWT 시크릿, 캐시 백엔드, 부트스트랩 관리자.
[설정 레퍼런스](https://devslab-kit.devslab.kr/ko/reference/configuration/) 참고.
- **property 한 줄로 분산 캐시.** `devslab.kit.cache.type: redis`로 두면 사용자별 메뉴
트리(그리고 직접 추가한 `@Cacheable`)가 Redis에 JSON으로 캐시됩니다 — `Serializable`도,
직렬화기 설정도 필요 없습니다. `in-memory`로 바꾸면 Redis를 뺄 수 있습니다.
- **최초 관리자 부트스트랩.** 빈 데이터베이스가 영구 백도어 없이 첫 부팅에 사용 가능한
관리자 로그인에 도달합니다.

## 문서

전체 문서: **[devslab-kit.devslab.kr](https://devslab-kit.devslab.kr)**.
71 changes: 71 additions & 0 deletions devslab-kit-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# devslab-kit-demo

> A minimal app that consumes **[devslab-kit](https://github.com/devslab-kr/devslab-kit)** — the Spring Boot 4 platform starter — on PostgreSQL + Redis.

[한국어](./README.ko.md)

The app has **no platform code of its own**. Adding the starter and pointing it at
a database gives you authentication, RBAC + groups + ABAC, multi-tenancy, dynamic
menus, audit logging, a first-admin bootstrap, and an admin REST API — all from
auto-configuration.

> **No wiring required.** A plain `@SpringBootApplication` in the app's own package
> (`kr.devslab.example.*`) is all it takes — see
> [`DevslabKitDemoApplication`](src/main/java/kr/devslab/example/devslabkit/DevslabKitDemoApplication.java).
> No `scanBasePackages`, no `@EntityScan`, no `@EnableJpaRepositories`: the starter's
> auto-configuration registers the kit's JPA entities, repositories, and the admin
> REST API itself, broadening scanning rather than making you widen it.

## Prerequisites

- Java 21+
- Docker (for PostgreSQL + Redis via Compose / Testcontainers)

## Run

```bash
./gradlew bootRun
```

`spring-boot-docker-compose` auto-starts `compose.yaml` (Postgres + Redis), the kit
runs its Flyway migrations, and the first-admin bootstrap seeds an `admin`/`admin`
user in the `default` tenant.

Log in to get a JWT:

```bash
curl -s localhost:8080/admin/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"tenantId":"default","loginId":"admin","password":"admin"}'
```

Point the [admin console](https://github.com/devslab-kr/devslab-kit-admin-ui) at
`http://localhost:8080` for a UI over the same API.

## Run the tests (Docker only)

```bash
./gradlew test
```

Testcontainers starts throwaway Postgres + Redis; the test boots the full context
and asserts the platform beans are wired.

## What this demo shows

- **Just add the starter.** `build.gradle.kts` declares
`kr.devslab:devslab-kit-spring-boot-starter` plus the Spring starters the
platform uses (web, security, JPA, Flyway, data-redis) — the kit stays
unopinionated about your runtime.
- **Config, not code.** Everything is driven from `application.yaml` under
`devslab.kit.*` — tenant mode/resolver, the JWT secret, the cache backend, and
the bootstrap admin. See the [configuration reference](https://devslab-kit.devslab.kr/reference/configuration/).
- **Distributed cache via one property.** `devslab.kit.cache.type: redis` makes the
per-user menu tree (and any `@Cacheable` you add) cache as JSON in Redis — no
`Serializable`, no serializer wiring. Flip to `in-memory` to drop Redis.
- **First-admin bootstrap.** A fresh database reaches a usable admin login on first
boot, without a permanent backdoor.

## Docs

Full documentation: **[devslab-kit.devslab.kr](https://devslab-kit.devslab.kr)**.
60 changes: 60 additions & 0 deletions devslab-kit-demo/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
plugins {
java
id("org.springframework.boot") version "4.0.6"
id("io.spring.dependency-management") version "1.1.7"
}

group = "kr.devslab.example"
version = "0.0.1-SNAPSHOT"

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

repositories {
mavenCentral()
// For local testing before 0.1.0 is on Maven Central:
// (1) in the devslab-kit repo run `./gradlew publishToMavenLocal`
// (2) uncomment the line below
// mavenLocal()
}

dependencies {
// The devslab-kit starter pulls in the whole platform's auto-configuration.
implementation("kr.devslab:devslab-kit-spring-boot-starter:0.1.0")

// devslab-kit is deliberately unopinionated about which Spring starters you
// bring — a consumer wires the runtime it actually wants. This is the set the
// platform needs to come fully alive: web + security (admin REST API), JPA +
// Flyway (the kit ships its schema migrations on the classpath), and
// data-redis (only used when devslab.kit.cache.type=redis).
implementation("org.springframework.boot:spring-boot-starter-webmvc")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("org.springframework.boot:spring-boot-starter-flyway")
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.flywaydb:flyway-database-postgresql")

runtimeOnly("org.postgresql:postgresql")

// Auto-starts compose.yaml (Postgres + Redis) on `bootRun`.
developmentOnly("org.springframework.boot:spring-boot-docker-compose")

testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-testcontainers")
// Spring Boot 4 manages Testcontainers 2.x, whose artifacts were renamed to
// the `testcontainers-*` prefix (`testcontainers-junit-jupiter`,
// `testcontainers-postgresql`); the old 1.x IDs (`junit-jupiter`, `postgresql`)
// are absent from the SB4 BOM, so leaving them unversioned fails to resolve.
testImplementation("org.testcontainers:testcontainers-junit-jupiter")
testImplementation("org.testcontainers:testcontainers-postgresql")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.withType<Test> {
useJUnitPlatform()
}
13 changes: 13 additions & 0 deletions devslab-kit-demo/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
postgres:
image: 'postgres:16-alpine'
environment:
- 'POSTGRES_DB=demo'
- 'POSTGRES_USER=demo'
- 'POSTGRES_PASSWORD=demo'
ports:
- '5432:5432'
redis:
image: 'redis:7-alpine'
ports:
- '6379:6379'
32 changes: 32 additions & 0 deletions devslab-kit-demo/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Single-service compose file for the local "run it yourself" path.
#
# The CI / `./gradlew test` path does NOT use this file — Testcontainers spins
# up its own ephemeral PostgreSQL on a random port. This compose file exists
# so a human can do:
#
# docker compose up -d db
# ./gradlew bootRun
#
# ...without installing Postgres on their laptop. The credentials and port
# below match what application.yml reads.

services:
db:
image: postgres:16-alpine
container_name: easy-paging-postgres-demo-db
environment:
POSTGRES_DB: easypaging
POSTGRES_USER: easypaging
POSTGRES_PASSWORD: easypaging
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U easypaging -d easypaging"]
interval: 5s
timeout: 3s
retries: 10
volumes:
- pgdata:/var/lib/postgresql/data

volumes:
pgdata:
3 changes: 3 additions & 0 deletions devslab-kit-demo/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
Binary file not shown.
9 changes: 9 additions & 0 deletions devslab-kit-demo/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading