feat(admin): config-sync mirror mode + opt-in user sync (ADR 0003, PR 4)#55
Merged
Conversation
Extends the config-sync import/export beyond additive merge.
mirror mode — 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. There
are no FK cascades between roles/permissions/users, so deletes clean
their own join rows and run in a safe order:
- menus: deleted leaf-first (a child before its parent);
- roles: a role still assigned to any user is SKIPPED (mirror never
strips a user's role), else its grants are revoked then it is deleted;
- permissions: revoked from the tenant's roles, then deleted.
ImportResult.Section gains `deleted` and `skipped` to report this.
user sync (includeUsers, opt-in, default off) — export carries users by
login id with NO password (just email, status, role codes); import is
create-only: a missing user is created with no usable password and
mustChangePassword, then assigned roles by code. An existing user is
never overwritten (reported as skipped). ConfigBundle gains an optional
`users` list (5-arg constructor kept for definitional-only bundles).
Both stay gated by ConfigSyncAutoConfiguration (off unless
devslab.kit.config-sync.enabled=true) and refused under a production
profile. mirror is intended for single-tenant-per-deployment use.
Tests: mirror delete/skip/grant-reconcile and user export/create/
idempotent/never-overwrite, over real Postgres. Full suite green
(54 tests, 0 failures/0 errors).
jlc488
added a commit
that referenced
this pull request
Jun 3, 2026
All implementation PRs have merged: export/import (#53), prod fail-fast gating (#54), mirror mode + opt-in user sync (#55), and the admin-ui "Config Sync" page (devslab-kit-admin-ui #20). Flip the status to Accepted (item 6 of the plan) and record the PRs; the standalone how-to guide is the remaining piece. Both language files.
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
Extends config-sync (ADR 0003) beyond additive merge with mirror mode and opt-in user sync. Both stay gated by
ConfigSyncAutoConfiguration(off unlessdevslab.kit.config-sync.enabled=true) and refused under a production profile.mirrormodeMakes the target match the bundle exactly. On top of the merge it:
There are no FK constraints between roles / permissions / users (only
platform_menu.parent_idcascades), so deletes clean their own join rows and run in a safe order:ImportResult.Sectiongainsdeletedandskippedto report this.user sync (
includeUsers, opt-in, default off)mustChangePassword, then assigned roles by code. An existing user is never overwritten (reported asskipped).ConfigBundlegains an optionaluserslist; the 5-arg constructor is kept for definitional-only bundles.Verification
Full suite green locally — 54 tests, 0 failures / 0 errors (
./gradlew build, real Postgres via Testcontainers). New tests cover mirror delete/skip/grant-reconcile and user export/create/idempotent/never-overwrite.Pairs with admin-ui #20 (the Config Sync page renders the new
deleted/skipped/userssections and theincludeUserstoggle).요약 (한국어)
config-sync(ADR 0003)를 추가형 merge 너머로 확장 — mirror 모드 + 옵트인 user sync. 둘 다
ConfigSyncAutoConfiguration으로 게이팅(기본 off:devslab.kit.config-sync.enabled=true일 때만) 되고 운영 프로파일에서는 기동 거부됩니다.mirror모드대상을 번들과 정확히 일치시킵니다. merge 에 더해:
roles/permissions/users 사이엔 FK 제약이 없어서(오직
platform_menu.parent_id만 cascade), 삭제가 조인 행을 직접 정리하고 안전한 순서로 실행됩니다:ImportResult.Section에deleted·skipped추가.user sync (
includeUsers, 옵트인, 기본 off)mustChangePassword로 생성하고 코드로 역할 할당. 기존 사용자는 절대 덮어쓰지 않음(skipped보고).ConfigBundle에 optionalusers추가; 정의성-only 번들용 5-arg 생성자 유지.검증
로컬 전체 그린 — 54 tests, 0 failures / 0 errors (
./gradlew build, Testcontainers 실제 Postgres). mirror 삭제/skip/권한 재조정 + 사용자 export/생성/멱등/덮어쓰기-금지 테스트 추가.admin-ui #20 과 짝(페이지가 새
deleted/skipped/users섹션 +includeUsers토글 렌더).