feat(admin): Settings + Diagnostics field-rename to admin-ui shape#18
Merged
Conversation
Last PR in the contract-gap series. Closes the two remaining cosmetic
mismatches between the admin UI and the backend — both pure JSON-key
renames, no schema or service changes.
Settings (GET /admin/api/v1/settings)
------------------------------------
Rewritten to the admin UI's AdminSettings shape:
{
jwt: { issuer, ttlSeconds, secretMasked },
tenant: { resolver },
identity:{ lockoutThreshold, lockoutDurationSeconds },
audit: { enabled, asyncQueueCapacity },
menu: { cacheTtlSeconds },
raw: { "devslab.kit.foo.bar": "value", ... }
}
- Durations exposed as integer seconds (ttlSeconds /
lockoutDurationSeconds / cacheTtlSeconds) parsed from ISO-8601
strings via Duration.parse — defaults applied on missing or
malformed values (28800s JWT TTL, 900s lockout, 300s menu cache).
- JWT secret rendered as "***" under secretMasked, never the raw
value.
- `raw` dumps every devslab.* key the Environment can enumerate
(sorted for stable diffs) with secrets / passwords / tokens
masked.
- Still reads via org.springframework.core.env.Environment so this
module avoids depending on devslab-kit-autoconfigure (no
circular dep).
Diagnostics — permission-check
------------------------------
- Response field rename: `allowed` -> `hasPermission`,
`userPermissionCodes` -> `matchedVia`.
- matchedVia surfaces the single matched code today; the
"which role / which group granted it" breakdown is queued as a
follow-up once the access SPI exposes that detail.
Diagnostics — menu-visibility
-----------------------------
- Response is now a `{items: [...]}` wrapper instead of a raw
MenuTree (which would have serialized as `{roots: [...]}`).
- Each node carries a `visible` flag (true if the user has the
required permission or the node has none) instead of pre-pruning
hidden nodes. The admin UI uses the flag to render greyed-out
items for parent / sibling context.
- New records: MenuVisibilityResponse, MenuVisibilityItem.
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.
Last PR in the admin-ui ↔ backend contract-gap series (after #14 menus, #15 audit-logs, #16 policies, #17 tenants). Both endpoints reshaped — no schema or service changes, just JSON-key renames + a richer menu-visibility response.
Summary
GET /admin/api/v1/settingsRewritten to the admin UI's
AdminSettingsshape:{ "jwt": { "issuer": "...", "ttlSeconds": 28800, "secretMasked": "***" }, "tenant": { "resolver": "FIXED" }, "identity":{ "lockoutThreshold": 5, "lockoutDurationSeconds": 900 }, "audit": { "enabled": true, "asyncQueueCapacity": 1024 }, "menu": { "cacheTtlSeconds": 300 }, "raw": { "devslab.kit.foo.bar": "value", "...": "..." } }Duration.parse). Defaults applied on missing/malformed values."***"undersecretMasked— never the raw value.rawdumps everydevslab.*key theEnvironmentcan enumerate (sorted for stable diffs in the UI). Keys containingsecret/password/tokenare masked.Environment(notDevslabKitProperties) so this module avoids depending ondevslab-kit-autoconfigure— keeps the dep graph acyclic.POST /admin/api/v1/diagnostics/permission-checkallowed→hasPermission,userPermissionCodes→matchedVia.matchedViasurfaces the single matched code today; the "which role / which group granted it" breakdown is queued as a follow-up once the access SPI exposes that detail.GET /admin/api/v1/diagnostics/menu-visibility{ "items": [...] }wrapper instead of the rawMenuTree(which would have serialised as{ "roots": [...] }).visibleflag (true if the user has the required permission, or the node has no permission gate) instead of pre-pruning hidden nodes. The admin UI uses the flag to render greyed-out items for parent / sibling context.MenuVisibilityResponse,MenuVisibilityItem.Test plan
./gradlew buildgreen (55 tasks, all tests pass — no schema migration in this PR, no service touched)/admin/api/v1/settingsand confirm every devslab.* property appears underrawwithidentity.jwt.secretmasked; exercise Diagnostics permission-check + menu-visibility with a partially-permitted userSeries wrap
This closes the seven open contract gaps between the admin UI's
src/api/*.tsand the backend:The Users / Roles / Permissions / Groups endpoints already matched their
src/api/*.tswrappers and didn't need any change. Once these five PRs merge alongside the admin-ui stack, the UI should light up end-to-end against a running sample-app.Honest follow-ups queued (not in this PR)
PermissionCheckResponse.matchedViareturning the actual grant path (which role, which group) — needs an access-SPI extension.outcome/ip/userAgentto first-classAuditEventfields so publishers don't have to use the metadata map (currently the publisher-side workaround documented in feat(audit-logs): paging + filters + outcome/ip/userAgent + field rename #15).reason/matchedRulesonPolicy.evaluateto a richerPolicyEvaluationdecision object (documented in feat(policies): PolicyDescriptor + nested test body + XACML PERMIT #16).asyncQueueCapacity/cacheTtlSecondsproperties currently expose defaults only — they're not wired to actual behaviour yet. Wire them up when the audit publisher / menu cache need the knob.