15c0c35df6
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
5.4 KiB
5.4 KiB
id, title, status, wave, depends_on, plan, spec
| id | title | status | wave | depends_on | plan | spec |
|---|---|---|---|---|---|---|
| session-hostname-resolution-01 | Portable resolve-session-hostnames setting contract | pending | 1 | docs/plans/session-hostname-resolution/plan.md | docs/specs/session-hostname-resolution/spec.md |
Portable resolve-session-hostnames setting contract
Inputs
The session-hostname-resolution spec
(User setting + Contracts sections) and the existing
app_status_bar_enabled user-settings round trip as the pattern.
TDD sequence
- Add failing backend tests: missing stored value and initial payload
default to
false; explicittruesurvives store read → DTO response → boot mapping → event payload; PATCH omission preserves the current value; PATCH explicitfalseis durable. - Add failing frontend mapper/WS-handler tests: default
false, explicittrue, omission preserving current state, revision-ordered snapshots. - Add the smallest model, DTO, controller, service, store, boot, HTTP type, state, and mapper changes that make those tests pass.
- Refactor only repeated mapping code exposed by the tests. No UI or lookup behavior in this task.
Implementation
- Add
ResolveSessionHostnames booltoapps/backend/internal/user/models/models.go(jsonresolve_session_hostnames). - Add the response field and pointer PATCH field to
apps/backend/internal/user/dto/dto.go(includingFromUserSettings). - Thread the PATCH pointer through
apps/backend/internal/user/controller/controller.goandapps/backend/internal/user/service/service.go(UpdateUserSettingsRequest+applyBasicSettings). - Apply an explicit value only when the pointer is non-nil. Publish
resolve_session_hostnamesin the completeuser.settings.updatedevent (publishUserSettingsEvent). - In
apps/backend/internal/user/store/sqlite.go:- default
falseindefaultUserSettings(zero value; no entry needed); - include
"resolve_session_hostnames"inmarshalUserSettingsPayload; - decode it as
*boolin thescanUserSettingspayload struct and overwrite the default only when present.
- default
- Add
"resolveSessionHostnames": settings.ResolveSessionHostnamestoapps/backend/internal/backendapp/boot_state_routes.go(mapUserSettingsState). - Add
resolve_session_hostnames?: booleanto response and PATCH shapes inapps/web/lib/types/http-user-settings.ts. - Add
resolveSessionHostnames: booleantoapps/web/lib/state/slices/settings/types.ts(UserSettingsState). - Initialize it to
falseincreateDefaultUserSettings()and map it through the shared path inapps/web/lib/ssr/user-settings.ts; the common mapper must preserve the current value when the field is absent. - Controller mapping regression test (required): the controller maps a
long request literal field-by-field; an omitted
ResolveSessionHostnamesentry silently drops{resolve_session_hostnames: true}before the service/store while DTO/service/store tests all pass. Addapps/backend/internal/user/controller/controller_test.gocoverage: a PATCH request with the pointer field set reaches the service request (and the response setting) astrue, an omitted field stays nil (no change), and an explicitfalseis preserved. - The existing
user.settings.updatedWS handler already flows through the shared mapper; do not add a second field-specific handler.
Files likely touched
apps/backend/internal/user/models/models.goapps/backend/internal/user/dto/dto.goapps/backend/internal/user/controller/controller.goapps/backend/internal/user/controller/controller_test.goapps/backend/internal/user/service/service.goapps/backend/internal/user/service/service_test.goapps/backend/internal/user/store/sqlite.goapps/backend/internal/user/store/sqlite_test.goapps/backend/internal/backendapp/boot_state_routes.goapps/backend/internal/backendapp/boot_state_user_settings_test.goapps/web/lib/types/http-user-settings.tsapps/web/lib/state/slices/settings/types.tsapps/web/lib/ssr/user-settings.tsapps/web/lib/ssr/user-settings.test.tsapps/web/lib/ws/handlers/users.test.ts
Acceptance
- A new user, an old settings JSON blob without the field, and an initial
payload that omits it all resolve to
false. - Stored and PATCHed
trueremains true through controller → repository read, DTO response, boot state, frontend mapping, and event mapping. - An omitted PATCH field leaves the existing setting unchanged (pinned at the controller layer too).
- The complete
user.settings.updatedevent payload includesresolve_session_hostnames(pin the key in a service test). - No UI, sessions payload, or lookup behavior changes yet.
Verification
(cd apps/backend && go test ./internal/user/... ./internal/backendapp/...)
(cd apps/web && pnpm exec vitest run lib/ssr/user-settings.test.ts lib/ws/handlers/users.test.ts)
git diff --check
The backend run must include the controller mapping regression test
(internal/user/controller/controller_test.go).
Dependencies
None. This task creates the portable setting consumed by Task 02.
Risks
- A default that remains
truein either mapper enables resolution for old rows with no preference. Pin default-false at store, boot, and frontend mapper boundaries. - The complete event map can silently omit the new field even when HTTP works. Pin the event key in service tests.