diff --git a/CHANGELOG.ko.md b/CHANGELOG.ko.md
index 514557b..5999217 100644
--- a/CHANGELOG.ko.md
+++ b/CHANGELOG.ko.md
@@ -11,6 +11,28 @@ English: [CHANGELOG.md](CHANGELOG.md)
## [Unreleased]
+## [0.4.0] — 2026-06-03
+
+### Added
+- **환경 간 설정 동기화 (ADR 0003).** 정의성 플랫폼 설정 — 권한, 역할(+ 권한 코드), 메뉴 —
+ 을 대상 DB를 직접 손대지 않고, 이식 가능한 코드 기준 번들로 한 환경에서 다른 환경으로 승격.
+ - `GET /admin/api/v1/config/export`, `POST /admin/api/v1/config/import`.
+ - **merge**(기본, 추가형 — 생성·수정만, 삭제 없음) 와 **mirror**(대상을 번들과 일치: 역할
+ 권한 재조정 + 번들에 없는 정의성 엔터티 삭제 — 메뉴 leaf-first; 사용자에게 할당된 역할은
+ skip; 권한은 revoke 후 삭제).
+ - **기본 dry-run** — import 는 섹션별 diff(생성 / 수정 / 삭제 / 건너뜀)를 반환하고
+ `dryRun=false` 가 아니면 아무것도 기록하지 않음.
+ - **옵트인 사용자 동기화**(`includeUsers`, 기본 off): export 는 사용자를 login id 기준으로
+ **비밀번호 없이** 내보내고, import 는 생성 전용이라 기존 사용자를 절대 덮어쓰지 않음.
+ - **기본 off**(`devslab.kit.config-sync.enabled`) + **운영 프로파일**(`prod`/`production`)
+ 에서 **기동 거부**(ADR 0003 §5) — 설정은 배포 시 커밋된 번들로 승격하지, 운영에 즉석
+ push 하지 않음.
+ - [admin 콘솔](https://github.com/devslab-kr/devslab-kit-admin-ui)의 **Config Sync** 페이지가
+ export / import / dry-run diff / 적용을 담당.
+
+### Notes
+- 마이그레이션 불필요: 설정 동기화는 테이블을 추가하지 않으며, 명시적으로 켜기 전까지 비활성.
+
## [0.3.0] — 2026-06-02
### 변경됨 (Changed)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1517f7c..9458522 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,30 @@ The library major aligns with the Spring Boot major: `4.x.y` targets Spring Boot
## [Unreleased]
+## [0.4.0] — 2026-06-03
+
+### Added
+- **Config sync across environments (ADR 0003).** Promote definitional platform config —
+ permissions, roles (+ their permission codes) and menus — from one environment to another as
+ a portable, code-keyed bundle, instead of hand-editing each target database.
+ - `GET /admin/api/v1/config/export` and `POST /admin/api/v1/config/import`.
+ - **merge** (default, additive — creates and updates, never deletes) and **mirror** (makes the
+ target match the bundle: reconciles each role's grants and deletes definitional entities
+ absent from the bundle — menus leaf-first; a role still assigned to a user is skipped;
+ permissions revoked then deleted).
+ - **dry-run by default** — the import returns a per-section diff (created / updated / deleted /
+ skipped) and writes nothing unless `dryRun=false`.
+ - **Opt-in user sync** (`includeUsers`, default off): export carries users by login id with
+ **no password**; import is create-only and never overwrites an existing user.
+ - **Off by default** (`devslab.kit.config-sync.enabled`) and **refused under a production
+ profile** (`prod`/`production`, ADR 0003 §5) — promote config via the committed bundle on
+ deploy, not an ad-hoc push to prod.
+ - A **Config Sync** page in the [admin console](https://github.com/devslab-kr/devslab-kit-admin-ui)
+ drives export / import / dry-run diff / apply.
+
+### Notes
+- No migration required: config sync adds no tables and is inert unless explicitly enabled.
+
## [0.3.0] — 2026-06-02
### Changed
diff --git a/README.ko.md b/README.ko.md
index d852a1b..cff6762 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -41,6 +41,7 @@
| **캐시** | 플러그형 캐시 — `in-memory` · `redis` · `none`. Redis 백엔드가 JSON 직렬화를 직접 책임지므로 `Serializable` 구현이나 직렬화기 배선이 필요 없습니다(ADR 0002). 사용자별 메뉴 캐시도 이 공유 매니저를 사용합니다. |
| **최초 관리자 부트스트랩** | 첫 부팅 시 테넌트, `PLATFORM_ADMIN` 역할, `admin.*` 권한, 관리자 사용자를 멱등하게 생성 — opt-in, 프로퍼티 기반(ADR 0001). |
| **관리자 REST API** | 위 모든 엔티티 + 진단 + 실시간 설정 뷰를 위한 `/admin/api/v1/**`. |
+| **설정 동기화** | 정의성 설정(권한·역할·메뉴) — 그리고 옵트인으로 사용자 — 을 환경 간에 코드 기준 export/import 번들로 승격: `merge` 또는 `mirror`, 먼저 dry-run. 기본 off, 운영 프로파일에선 기동 거부(ADR 0003). |
| **OpenAPI / Swagger UI** | 스타터에 포함 — `/swagger-ui`가 관리자 API 그룹과 함께 자동으로 뜸, 설정 불필요. `openapi.enabled=false`로 끄거나, springdoc 의존성을 `exclude`해 jar 자체를 제거. |
| **Override 친화적** | 모든 기본 빈이 `@ConditionalOnMissingBean` — 직접 선언하면 어느 조각이든 교체 가능. |
| **GraalVM Native** | 리플렉션 중심 설계를 피하고, 샘플 앱이 `nativeCompile`을 검증. |
@@ -62,7 +63,7 @@
**Gradle (Kotlin DSL)**
```kotlin
-implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
+implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0")
```
**Maven**
@@ -71,7 +72,7 @@ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
```
diff --git a/README.md b/README.md
index aad0e7e..296ece0 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,7 @@ specific product's domain.
| **Cache** | A pluggable cache — `in-memory`, `redis`, or `none`. The Redis backend owns JSON serialization, so you never implement `Serializable` or wire a serializer (ADR 0002). The per-user menu cache rides this shared manager. |
| **First-admin bootstrap** | Idempotently provisions a tenant, a `PLATFORM_ADMIN` role, the `admin.*` permissions, and an admin user on first boot — opt-in and property-driven (ADR 0001). |
| **Admin REST API** | `/admin/api/v1/**` for every entity above, plus diagnostics and a live settings view. |
+| **Config sync** | Promote definitional config (permissions, roles, menus) — and, opt-in, users — across environments as a code-keyed export/import bundle: `merge` or `mirror`, dry-run first. Off by default, refused under a production profile (ADR 0003). |
| **OpenAPI / Swagger UI** | Bundled in the starter — `/swagger-ui` comes up with the admin API grouped, no wiring. Toggle off with `openapi.enabled=false`, or `exclude` the springdoc dependency to drop the jar. |
| **Override-friendly** | Every default bean is `@ConditionalOnMissingBean` — replace any piece by declaring your own. |
| **GraalVM Native** | Reflection-heavy patterns are avoided; the sample app verifies `nativeCompile`. |
@@ -64,7 +65,7 @@ specific product's domain.
**Gradle (Kotlin DSL)**
```kotlin
-implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
+implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0")
```
**Maven**
@@ -73,7 +74,7 @@ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
```
diff --git a/docs/getting-started/installation.ko.md b/docs/getting-started/installation.ko.md
index 7d17072..34269c2 100644
--- a/docs/getting-started/installation.ko.md
+++ b/docs/getting-started/installation.ko.md
@@ -17,13 +17,13 @@
=== "Gradle (Kotlin DSL)"
```kotlin
- implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
+ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0")
```
=== "Gradle (Groovy)"
```groovy
- implementation 'kr.devslab:devslab-kit-spring-boot-starter:0.3.0'
+ implementation 'kr.devslab:devslab-kit-spring-boot-starter:0.4.0'
```
=== "Maven"
@@ -32,7 +32,7 @@
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
```
@@ -43,10 +43,10 @@
물러납니다(`@ConditionalOnMissingBean`).
```kotlin
-implementation("kr.devslab:devslab-kit-access-core:0.3.0") // RBAC + 그룹 + ABAC
-implementation("kr.devslab:devslab-kit-cache-core:0.3.0") // 플러그형 캐시
+implementation("kr.devslab:devslab-kit-access-core:0.4.0") // RBAC + 그룹 + ABAC
+implementation("kr.devslab:devslab-kit-cache-core:0.4.0") // 플러그형 캐시
// …또는 계약만:
-implementation("kr.devslab:devslab-kit-access-api:0.3.0")
+implementation("kr.devslab:devslab-kit-access-api:0.4.0")
```
동작하는 앱을 부팅하려면 [빠른 시작](quick-start.md)을 참고하세요.
diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md
index fa423f9..8349a4c 100644
--- a/docs/getting-started/installation.md
+++ b/docs/getting-started/installation.md
@@ -17,13 +17,13 @@ whole platform; depend on individual modules only if you want à la carte.
=== "Gradle (Kotlin DSL)"
```kotlin
- implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0")
+ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0")
```
=== "Gradle (Groovy)"
```groovy
- implementation 'kr.devslab:devslab-kit-spring-boot-starter:0.3.0'
+ implementation 'kr.devslab:devslab-kit-spring-boot-starter:0.4.0'
```
=== "Maven"
@@ -32,7 +32,7 @@ whole platform; depend on individual modules only if you want à la carte.
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
```
@@ -44,10 +44,10 @@ your own — the auto-configuration backs off (`@ConditionalOnMissingBean`) when
do.
```kotlin
-implementation("kr.devslab:devslab-kit-access-core:0.3.0") // RBAC + groups + ABAC
-implementation("kr.devslab:devslab-kit-cache-core:0.3.0") // pluggable cache
+implementation("kr.devslab:devslab-kit-access-core:0.4.0") // RBAC + groups + ABAC
+implementation("kr.devslab:devslab-kit-cache-core:0.4.0") // pluggable cache
// …or just the contract:
-implementation("kr.devslab:devslab-kit-access-api:0.3.0")
+implementation("kr.devslab:devslab-kit-access-api:0.4.0")
```
See [Quick Start](quick-start.md) to boot a working app.
diff --git a/docs/guides/config-sync.ko.md b/docs/guides/config-sync.ko.md
new file mode 100644
index 0000000..a12fdd2
--- /dev/null
+++ b/docs/guides/config-sync.ko.md
@@ -0,0 +1,95 @@
+# 설정 동기화 (Config Sync)
+
+**정의성 플랫폼 설정** — 권한, 역할(과 그 역할이 부여하는 권한 코드), 메뉴 — 을 대상 DB를
+직접 손대지 않고, 이식 가능한 코드 기준 번들로 한 환경에서 다른 환경으로 승격합니다.
+
+admin 콘솔은 RBAC 그래프 전체를 런타임에 관리할 수 있지만, 그 설정은 코드가 아니라
+**데이터베이스**에 있습니다. 팀은 로컬에서 설계한 뒤 dev / staging / 운영 — 각자 자기 DB —
+에 *같은* 구조가 필요해집니다. 설정 동기화가 이를 옮기는 일급 수단입니다. 배경과 설계는
+[ADR 0003](../adr/0003-config-sync.md) 참고.
+
+!!! warning "기본 off, 운영에선 금지"
+ 설정 동기화는 **dev/staging 편의 도구**로, 명시적으로 켜기 전까지 비활성이며 `prod` /
+ `production` 프로파일에서는 **기동을 거부**합니다. 운영 설정은 배포 시 git 에 커밋된 번들을
+ 적용해 승격하지, 라이브 시스템에 즉석으로 push 하지 않습니다.
+
+## 활성화
+
+```yaml
+devslab:
+ kit:
+ config-sync:
+ enabled: true # 기본 false — 끄면 엔드포인트·UI 전체가 비활성
+```
+
+`enabled=true` 인데 `prod`/`production` 프로파일이 활성이면, 기능을 조용히 끄는 대신 명확한
+메시지와 함께 기동 단계에서 즉시 실패합니다.
+
+## 번들에 담기는 것
+
+| 포함(정의성) | 제외 |
+| --- | --- |
+| 권한 (`code`, 설명) | 감사 로그 (이력) |
+| 역할 (`code`, 이름, **권한 코드**) | ABAC 정책 (이건 데이터가 아니라 *코드*) |
+| 메뉴 (`code`, 부모 코드, 라벨, 경로, 아이콘, 필요 권한 코드, 순서) | 비밀번호 / 시크릿 |
+| 사용자 — **옵트인 시에만**, login id 기준, 역할 코드 + **비밀번호 없음** | |
+
+모든 것이 DB UUID 가 아니라 **자연 코드**로 키잉되므로, id 가 다른 다른 환경에도 그대로
+적용됩니다.
+
+## 엔드포인트
+
+| | |
+| --- | --- |
+| `GET /admin/api/v1/config/export?tenantId={t}&includeUsers=false` | 번들을 JSON 으로 반환. |
+| `POST /admin/api/v1/config/import?mode=merge&dryRun=true&includeUsers=false` | 번들 적용; 섹션별 diff 반환. |
+
+## 모드
+
+- **`merge`**(기본) — 추가형. 생성·수정만 하고 **삭제하지 않으며**, 역할의 기존 권한도 회수하지
+ 않음. 멱등: 같은 번들을 다시 적용해도 변화 없음.
+- **`mirror`** — 대상을 *번들과 정확히 일치*시킴. merge 에 더해 역할 권한을 재조정(번들에 없는
+ 권한 회수)하고, 번들에 없는 정의성 엔터티를 **삭제**:
+ - **메뉴**는 leaf-first(자식 먼저, 부모 나중)로 삭제;
+ - **사용자에게 할당된 역할은 skip** — mirror 가 사용자 역할을 함부로 떼지 않음;
+ - **권한**은 테넌트 역할에서 회수 후 삭제.
+
+!!! danger "미러는 삭제합니다"
+ `mirror` 는 항목을 제거합니다. 적용 전 항상 **dry-run** diff 를 확인하고, 단일 테넌트 배포
+ 환경에서만 권장합니다(권한은 전역).
+
+## 먼저 dry-run
+
+`dryRun=true` 가 **기본**입니다. import 는 전체 diff 를 계산하고 아무것도 기록하지 않습니다.
+결과는 섹션별(`permissions` / `roles` / `menus` / `users`)로 다음을 보고합니다:
+
+- **생성(created)**, **수정(updated)**, **삭제(deleted, 미러 전용)**, **건너뜀(skipped — 사용
+ 중인 역할, 또는 이미 존재하는 사용자)**.
+
+미리보기가 의도와 맞으면 `dryRun=false` 로 실제 적용합니다.
+
+## 사용자 동기화 (옵트인)
+
+`includeUsers=true` 시:
+
+- **export** 는 사용자를 login id 기준으로 — 이메일·상태·역할 코드 — 내보내되 **비밀번호는
+ 절대 포함하지 않음**.
+- **import** 는 **생성 전용**: 없는 사용자만 사용 불가 비밀번호 + `mustChangePassword` 로 생성한
+ 뒤 코드로 역할을 할당. **기존 사용자는 절대 덮어쓰지 않음**(`skipped` 로 보고). 비밀번호는
+ 이후 admin 콘솔에서 설정.
+
+사용자는 운영 데이터입니다. 새 환경에 계정을 시드할 의도가 아니면 `includeUsers` 는 꺼 두세요.
+
+## 권장 워크플로
+
+1. 로컬 DB 에서 설정 설계(admin 콘솔 또는 API).
+2. 번들 **export**(정의성만이면 `includeUsers=false`).
+3. 번들 JSON 을 git 에 커밋 — 이제 리뷰·버전 관리되는 설정.
+4. 대상에서 import **dry-run** 후 diff 확인.
+5. 적용(`dryRun=false`). 추가/수정은 `merge`, 대상을 번들과 정확히 일치시킬 때만 `mirror`.
+
+## Admin 콘솔
+
+[admin 콘솔](https://github.com/devslab-kr/devslab-kit-admin-ui)에 전체 흐름을 다루는 **Config
+Sync** 페이지가 있습니다: export(보기 / 다운로드 / 복사), import(붙여넣기·업로드 → dry-run
+diff → 적용), `merge`/`mirror` 전환, 사용자 동기화 토글.
diff --git a/docs/guides/config-sync.md b/docs/guides/config-sync.md
new file mode 100644
index 0000000..ac8991b
--- /dev/null
+++ b/docs/guides/config-sync.md
@@ -0,0 +1,99 @@
+# Config Sync
+
+Promote **definitional platform config** — permissions, roles (and the permission codes
+they grant) and menus — from one environment to another as a portable, code-keyed bundle,
+instead of hand-editing each target database.
+
+The admin console can manage the whole RBAC graph at runtime, but that config lives in the
+**database**, not in code. A team designs it locally, then needs the *same* structure in
+dev / staging / production — each with its own database. Config sync is the first-class way
+to move it. See [ADR 0003](../adr/0003-config-sync.md) for the rationale and design.
+
+!!! warning "Off by default, and never in production"
+ Config sync is a **dev/staging convenience**, disabled unless you opt in, and it
+ **refuses to start** under a `prod` / `production` profile. Production config is promoted
+ by applying the git-committed bundle on deploy — not by an ad-hoc push to a live system.
+
+## Enable it
+
+```yaml
+devslab:
+ kit:
+ config-sync:
+ enabled: true # default false — the whole surface (endpoints + UI) is inert otherwise
+```
+
+If `enabled=true` while a `prod`/`production` profile is active, the application fails fast
+at startup with a clear message rather than silently disabling the feature.
+
+## What's in the bundle
+
+| Included (definitional) | Excluded |
+| --- | --- |
+| Permissions (`code`, description) | Audit logs (history) |
+| Roles (`code`, name, **permission codes**) | ABAC policies (these are *code*, not data) |
+| Menus (`code`, parent code, label, path, icon, required permission code, order) | Passwords / secrets |
+| Users — **opt-in only**, by login id, with role codes and **no password** | |
+
+Everything is keyed by **natural codes**, never database UUIDs, so a bundle exported from one
+environment applies cleanly to another whose ids differ.
+
+## Endpoints
+
+| | |
+| --- | --- |
+| `GET /admin/api/v1/config/export?tenantId={t}&includeUsers=false` | Returns the bundle as JSON. |
+| `POST /admin/api/v1/config/import?mode=merge&dryRun=true&includeUsers=false` | Applies a bundle; returns a per-section diff. |
+
+## Modes
+
+- **`merge`** (default) — additive. Creates and updates; **never deletes**, and never revokes
+ a role's existing grants. Idempotent: re-applying the same bundle changes nothing.
+- **`mirror`** — makes the target *match the bundle exactly*. On top of the merge it reconciles
+ each role's grants (revoking permissions the bundle omits) and **deletes** definitional
+ entities absent from the bundle:
+ - **menus** are deleted leaf-first (a child before its parent);
+ - a **role still assigned to a user is skipped** — mirror never strips a user's role;
+ - **permissions** are revoked from the tenant's roles, then deleted.
+
+!!! danger "Mirror deletes"
+ `mirror` removes things. Always review the **dry-run** diff before applying, and prefer it
+ only for single-tenant-per-deployment setups (permissions are global).
+
+## Dry-run first
+
+`dryRun=true` is the **default**. The import computes the full diff and writes nothing. The
+result reports, per section (`permissions` / `roles` / `menus` / `users`), what would be:
+
+- **created**, **updated**, **deleted** (mirror only), and **skipped** (a role in use, or an
+ existing user).
+
+Apply for real with `dryRun=false` once the preview matches your intent.
+
+## User sync (opt-in)
+
+With `includeUsers=true`:
+
+- **export** carries users by login id — email, status and role codes — but **never a
+ password**.
+- **import** is **create-only**: a missing user is created with no usable password and
+ `mustChangePassword`, then assigned its roles by code. An **existing user is never
+ overwritten** (it is reported as `skipped`). Set the password via the admin console afterwards.
+
+Users are operational data; leave `includeUsers` off unless you specifically want to seed
+accounts into a fresh environment.
+
+## Recommended workflow
+
+1. Design config locally against your local database (admin console or API).
+2. **Export** the bundle (`includeUsers=false` for definitional-only).
+3. Commit the bundle JSON to git — it is now reviewable, versioned config.
+4. On the target, **dry-run** the import and review the diff.
+5. Apply (`dryRun=false`). Use `merge` to add/update; `mirror` only when you intend the target
+ to match the bundle exactly.
+
+## Admin console
+
+The [admin console](https://github.com/devslab-kr/devslab-kit-admin-ui) has a **Config Sync**
+page that drives the whole flow: export (view / download / copy), import (paste or upload →
+dry-run diff → apply), the `merge`/`mirror` switch, and the user-sync toggle.
diff --git a/docs/index.ko.md b/docs/index.ko.md
index 62b885b..d5e5fdb 100644
--- a/docs/index.ko.md
+++ b/docs/index.ko.md
@@ -45,6 +45,11 @@
`in-memory`, `redis`, `none`. Redis 백엔드가 JSON 직렬화를 직접 책임집니다 —
`Serializable`도, 직렬화기 배선도 필요 없습니다.
+- :material-sync: **설정 동기화**
+
+ 권한·역할·메뉴를 환경 간에 코드 기준 export/import 번들로 승격 — `merge` 또는
+ `mirror`, 먼저 dry-run ([가이드](guides/config-sync.ko.md)).
+
## 왜 스타터인가? { #why-a-starter }
diff --git a/docs/index.md b/docs/index.md
index eebc906..0f79d98 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -48,6 +48,11 @@ product's domain.
`in-memory`, `redis`, or `none`. The Redis backend owns JSON serialization — no
`Serializable`, no serializer wiring.
+- :material-sync: **Config sync**
+
+ Promote permissions, roles and menus across environments as a code-keyed
+ export/import bundle — `merge` or `mirror`, dry-run first ([guide](guides/config-sync.md)).
+
## Why a starter? { #why-a-starter }
diff --git a/docs/reference/configuration.ko.md b/docs/reference/configuration.ko.md
index 893d584..83f533e 100644
--- a/docs/reference/configuration.ko.md
+++ b/docs/reference/configuration.ko.md
@@ -121,7 +121,7 @@
=== "Gradle (Kotlin DSL)"
```kotlin
- implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0") {
+ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0") {
exclude(group = "org.springdoc")
}
```
@@ -132,7 +132,7 @@
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
org.springdoc
diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md
index 58a6a80..3abbbae 100644
--- a/docs/reference/configuration.md
+++ b/docs/reference/configuration.md
@@ -128,7 +128,7 @@ Two ways to turn it off:
=== "Gradle (Kotlin DSL)"
```kotlin
- implementation("kr.devslab:devslab-kit-spring-boot-starter:0.3.0") {
+ implementation("kr.devslab:devslab-kit-spring-boot-starter:0.4.0") {
exclude(group = "org.springdoc")
}
```
@@ -139,7 +139,7 @@ Two ways to turn it off:
kr.devslab
devslab-kit-spring-boot-starter
- 0.3.0
+ 0.4.0
org.springdoc
diff --git a/docs/roadmap.ko.md b/docs/roadmap.ko.md
index 71bc602..10ba1cc 100644
--- a/docs/roadmap.ko.md
+++ b/docs/roadmap.ko.md
@@ -21,6 +21,12 @@
("pull, don't push" 원칙 — 두 번째 소비자가 생기면 추출).
- **하드닝** — 통합 커버리지 확대, 보안 리뷰, 성능 개선.
+## 0.1.0 이후 출시됨
+
+- **환경 간 설정 동기화** (`0.4.0`) — 정의성 설정(권한·역할·메뉴; 옵트인 사용자)을 코드 기준
+ 번들로 export/import, `merge`/`mirror`, 기본 dry-run. [가이드](guides/config-sync.ko.md) 와
+ [ADR 0003](adr/0003-config-sync.ko.md) 참고.
+
## 버전 정책
라이브러리 메이저는 Spring Boot 메이저를 따릅니다: **`4.x.y`는 Spring Boot 4.x 대상**.
diff --git a/docs/roadmap.md b/docs/roadmap.md
index c516cba..de03380 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -23,6 +23,13 @@ The current focus: ship the platform that's already feature-complete.
(the "pull, don't push" rule — extract when there's a second consumer).
- **Hardening** — more integration coverage, security review, performance passes.
+## Shipped since 0.1.0
+
+- **Config sync across environments** (`0.4.0`) — export/import definitional config
+ (permissions, roles, menus; opt-in users) as a code-keyed bundle, `merge`/`mirror`,
+ dry-run by default. See the [guide](guides/config-sync.md) and
+ [ADR 0003](adr/0003-config-sync.md).
+
## Versioning
The library major tracks the Spring Boot major: **`4.x.y` targets Spring Boot
diff --git a/mkdocs.yml b/mkdocs.yml
index 96bba51..539142a 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -77,6 +77,7 @@ plugins:
Audit Logging: 감사 로깅
Caching: 캐시
First-admin Bootstrap: 최초 관리자 부트스트랩
+ Config Sync: 설정 동기화
Reference: 레퍼런스
Configuration: 설정
Admin REST API: 관리자 REST API
@@ -140,6 +141,7 @@ nav:
- Audit Logging: guides/audit.md
- Caching: guides/cache.md
- First-admin Bootstrap: guides/bootstrap.md
+ - Config Sync: guides/config-sync.md
- Reference:
- Configuration: reference/configuration.md
- Admin REST API: reference/admin-api.md