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