refactor(config-service): move site_settings write API from texera-web to config-service#6116
Conversation
…b to config-service
Fold AdminSettingsResource's GET/PUT/reset endpoints into ConfigResource
as /config/settings/{key}, so the service that seeds site_settings also
owns its read/write API. PUT and reset stay ADMIN-only; the single-key
GET keeps REGULAR+ADMIN because non-admin pages (dashboard logo/tabs,
dataset upload limits) read it. The frontend service now rides the
existing /api/config routing, so no proxy or nginx changes are needed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Automated Reviewer SuggestionsBased on the
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6116 +/- ##
============================================
+ Coverage 59.11% 59.19% +0.08%
- Complexity 3201 3209 +8
============================================
Files 1132 1131 -1
Lines 43681 43704 +23
Branches 4734 4735 +1
============================================
+ Hits 25821 25872 +51
+ Misses 16430 16399 -31
- Partials 1430 1433 +3
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ead of string-based DSL Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 383 | 0.234 | 25,012/33,387/33,387 us | 🔴 +8.6% / 🔴 +120.5% |
| 🟢 | bs=100 sw=10 sl=64 | 783 | 0.478 | 125,933/142,164/142,164 us | 🟢 -11.5% / 🔴 +31.7% |
| ⚪ | bs=1000 sw=10 sl=64 | 915 | 0.558 | 1,092,524/1,138,676/1,138,676 us | ⚪ within ±5% / 🔴 +10.7% |
Baseline details
Latest main 5c4a963 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 383 tuples/sec | 417 tuples/sec | 776.36 tuples/sec | -8.2% | -50.7% |
| bs=10 sw=10 sl=64 | MB/s | 0.234 MB/s | 0.255 MB/s | 0.474 MB/s | -8.2% | -50.6% |
| bs=10 sw=10 sl=64 | p50 | 25,012 us | 23,035 us | 12,636 us | +8.6% | +98.0% |
| bs=10 sw=10 sl=64 | p95 | 33,387 us | 31,466 us | 15,143 us | +6.1% | +120.5% |
| bs=10 sw=10 sl=64 | p99 | 33,387 us | 31,466 us | 18,954 us | +6.1% | +76.1% |
| bs=100 sw=10 sl=64 | throughput | 783 tuples/sec | 818 tuples/sec | 985.33 tuples/sec | -4.3% | -20.5% |
| bs=100 sw=10 sl=64 | MB/s | 0.478 MB/s | 0.499 MB/s | 0.601 MB/s | -4.2% | -20.5% |
| bs=100 sw=10 sl=64 | p50 | 125,933 us | 120,612 us | 101,671 us | +4.4% | +23.9% |
| bs=100 sw=10 sl=64 | p95 | 142,164 us | 160,665 us | 107,939 us | -11.5% | +31.7% |
| bs=100 sw=10 sl=64 | p99 | 142,164 us | 160,665 us | 113,798 us | -11.5% | +24.9% |
| bs=1000 sw=10 sl=64 | throughput | 915 tuples/sec | 910 tuples/sec | 1,016 tuples/sec | +0.5% | -10.0% |
| bs=1000 sw=10 sl=64 | MB/s | 0.558 MB/s | 0.556 MB/s | 0.62 MB/s | +0.4% | -10.1% |
| bs=1000 sw=10 sl=64 | p50 | 1,092,524 us | 1,097,346 us | 989,693 us | -0.4% | +10.4% |
| bs=1000 sw=10 sl=64 | p95 | 1,138,676 us | 1,145,647 us | 1,028,327 us | -0.6% | +10.7% |
| bs=1000 sw=10 sl=64 | p99 | 1,138,676 us | 1,145,647 us | 1,059,969 us | -0.6% | +7.4% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,521.62,200,128000,383,0.234,25012.44,33386.91,33386.91
1,100,10,64,20,2554.45,2000,1280000,783,0.478,125932.64,142163.95,142163.95
2,1000,10,64,20,21860.83,20000,12800000,915,0.558,1092523.68,1138676.11,1138676.11…dded Postgres Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ConfigService main code uses SqlServer and the generated jOOQ tables directly but only got DAO transitively through Auth; declare it like the other services that touch the database do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dmin single-key GET Non-admin pages only need 19 whitelisted keys (branding, sidebar tabs, upload limits); serve those in one payload via GET /config/settings/public (REGULAR+ADMIN) and make the arbitrary single-key GET ADMIN-only. The frontend reads public settings through one cached request instead of a request per key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
xuang7
left a comment
There was a problem hiding this comment.
Generally LGTM! I left one comment.
| getPublicSetting(key: string): Observable<string> { | ||
| if (!this.publicSettings$) { | ||
| this.publicSettings$ = this.http.get<Record<string, string>>(`${this.BASE_URL}/public`).pipe(shareReplay(1)); | ||
| } | ||
| return this.publicSettings$.pipe(map(settings => settings[key] ?? null)); |
There was a problem hiding this comment.
getPublicSetting does not currently handle errors, and shareReplay(1) may cache the error. If the first /settings/public fetch fails, the error could be replayed to every consumer with no retry.
What changes were proposed in this PR?
AdminSettingsResource(GET/PUT/reset over thesite_settingstable) was registered in texera-web, while config-service already owns seeding of the same table at startup and has the JWT auth stack registered. This PR makes config-service the single owner of the table's API by folding the endpoints intoConfigResourceas the write side of the config API:GET /config/settings/public—REGULAR+ADMIN: the 19 whitelisted user-visible keys (dashboard branding, sidebar tab toggles, dataset upload limits) in one payload, replacing the request-per-key pattern (the dashboard alone fired 15).GET /config/settings/{key}—ADMINonly: management read over any key, used by the admin settings page.PUT /config/settings/{key}—ADMINonly (same as before)POST /config/settings/reset/{key}—ADMINonly (same as before)These are complementary to the existing HOCON-backed reads (
/config/pre-login,/config/gui,/config/amber,/config/user-system): those serve deploy-time config resolved from classpath files + env vars, frozen per JVM;/config/settings/*serves the DB-backed values that admins edit at runtime. There is no key overlap between the two families.Behavior change (intended tightening): the old texera-web GET had no role annotation, so anonymous and
RESTRICTED(pending-approval) users could read settings. Now the public read requires aREGULAR/ADMINlogin, matching every other/config/*endpoint (RESTRICTEDusers already get 403 on/config/gui), and arbitrary-key reads requireADMIN. The dashboard degrades gracefully for rejected users — the logo/tabs subscriptions simply keep their defaults.The queries use the generated jOOQ
SITE_SETTINGStable instead of the old string-basedDSL.table/DSL.fieldlookups, andConfigServicenow declares its directDAOdependency explicitly (it previously leaked in transitively throughAuth). A smallConfigSettingPojowire DTO keeps the JSON contract at exactly{key, value}— the generated pojo would also exposeupdated_by/updated_at.AdminSettingsResourceis deleted from texera-web. On the frontend,AdminSettingsServicemoves from/api/admin/settingsto/api/config/settings(riding the existing/api/configrouting in bothproxy.config.jsonand the single-node nginx config — no proxy/nginx/k8s changes needed) and gainsgetPublicSetting(key), which reads from one shared, cached/settings/publicrequest; the non-admin consumers (dashboard, files-uploader, dataset-detail) use it, while the admin settings page keeps the per-key ADMIN read. The admin page reloads the window after saving, so the cache never serves stale values.Any related issues, documentation, discussions?
Closes #6115
How was this PR tested?
sbt ConfigService/test: 27 tests pass.ConfigResourceAuthSpecpin the auth gates (anonymous → 401 with Bearer challenge on public/single-key/PUT; REGULAR single-key GET / PUT / reset → 403; ADMIN reset of a key with no default → 404, proving the role gate admits ADMIN). The spec now also registersAuthValueFactoryProvider.Binder, mirroring productionAuthFeatures.register, so@Auth SessionUserparameters resolve.ConfigSettingsCrudSpeccover the positive paths against an embedded Postgres (MockTexeraDB, via a newDAO % "test->test"dependency): read-miss → null, insert withupdated_byrecorded, upsert-on-conflict updates in place, null-value no-op, public map serves whitelisted keys and hides management-only ones, reset restores thedefault.confvalue, reset of an unknown key → 404.sbt WorkflowExecutionService/compilepasses after removing the resource from texera-web;sbt scalafmtAllclean.tsc --noEmitclean;ng testondashboard.component.spec.ts(11 tests) passes with the mock switched togetPublicSetting.bin/local-dev.sh, all 14 services), through the frontend dev proxy (:4200 → /api/config/** → config-service:9094):GET /settings/public→ 200 with the full whitelisted map; single-key GET → 403; PUT → 403;updated_byrecords the admin's username;/api/admin/settings/{key}now 404s.Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (claude-fable-5)