Move personalization page from /operator/personalization to /settings/personalization (user-level) #70

Closed
opened 2026-10-07 22:18:15 +02:00 by gotoi-agent · 5 comments
Collaborator

What

Move the personalization page from the operator section to the user section:

  • Old: http://192.168.31.41:5173/operator/personalization (added in #46)
  • New: http://192.168.31.41:5173/settings/personalization

Rationale: theme/accent preferences are a per-user setting, not an instance-operator one —
they belong under /settings, not /operator.

Scope hints

  • Move the route directory under dashboard/src/routes/settings/personalization/; the page
    itself keeps its behaviour (system/dark/light + accent tint picker).
  • Update every pointer: nav/sidebar entries, destinations.ts, page-help.ts, breadcrumbs,
    any operator nav list, and the e2e nav coverage (scripts/e2e/nav_selenium.py if it lists
    the route).
  • Access control: whatever gate currently sits on /operator/* must not be required for the new
    path — a normal signed-in user must reach their own settings page. If some operator-only data
    was being read there, report the conflict instead of guessing.
  • Decide and state what happens to the old URL: keep a redirect from /operator/personalization
    to the new path (preferred if anything links to it) or remove it cleanly — say which and why.
  • UC: this renames/moves a documented route → update or add the UC (frontend), bidirectional
    related:, _check.py green.

Gates

python3 docs/use-cases/_check.py, scripts/check-ai-headers.py, dashboard
bun run test + bun run check. One commit per logical step, Refs #<N>, no closing keywords.

## What Move the personalization page from the operator section to the user section: - **Old:** `http://192.168.31.41:5173/operator/personalization` (added in #46) - **New:** `http://192.168.31.41:5173/settings/personalization` Rationale: theme/accent preferences are a **per-user** setting, not an instance-operator one — they belong under `/settings`, not `/operator`. ## Scope hints - Move the route directory under `dashboard/src/routes/settings/personalization/`; the page itself keeps its behaviour (system/dark/light + accent tint picker). - Update every pointer: nav/sidebar entries, `destinations.ts`, `page-help.ts`, breadcrumbs, any `operator` nav list, and the e2e nav coverage (`scripts/e2e/nav_selenium.py` if it lists the route). - Access control: whatever gate currently sits on `/operator/*` must not be required for the new path — a normal signed-in user must reach their own settings page. If some operator-only data was being read there, report the conflict instead of guessing. - Decide and state what happens to the old URL: keep a redirect from `/operator/personalization` to the new path (preferred if anything links to it) or remove it cleanly — say which and why. - UC: this renames/moves a documented route → update or add the UC (frontend), bidirectional `related:`, `_check.py` green. ## Gates `python3 docs/use-cases/_check.py`, `scripts/check-ai-headers.py`, dashboard `bun run test` + `bun run check`. One commit per logical step, `Refs #<N>`, no closing keywords.
gotoi-agent added reference issue/70-personalization-move 2026-10-08 01:51:56 +02:00
Author
Collaborator

Claimed — branch issue/70-personalization-move. Doing: move the accent-tint page to /settings/personalization (user-level), update nav/destinations/page-help/breadcrumb pointers + e2e walk, keep a 308 shim from the old /operator/personalization, update UC-FE-99/-08/-80.

Claimed — branch `issue/70-personalization-move`. Doing: move the accent-tint page to `/settings/personalization` (user-level), update nav/destinations/page-help/breadcrumb pointers + e2e walk, keep a 308 shim from the old `/operator/personalization`, update UC-FE-99/-08/-80.
Author
Collaborator

Plan — issue #70: move personalization from /operator/personalization to /settings/personalization

Restated goal

The accent-tint picker shipped in #46 (dashboard/src/routes/operator/personalization/+page.svelte, UC-FE-99)
sits behind the instance-operator gate (operator/+layout.server.ts → non-operators 303 to /settings),
but the preference is per-browser/per-user, never an instance-operator concern. Move the page to
/settings/personalization, drop the operator gate (the ordinary session gate in hooks.server.ts
is the only requirement), move every pointer that named the old URL (nav group item, destinations
icon prefix, page-help, app.css comment, selen-check/usecase test lists, e2e walk list), and keep a
thin 308 shim on the old path for bookmarks.

Done for the operator: a normal signed-in user (no instanceOperator) opens
/settings/personalization from the Settings submenu, picks a tint, and it sticks across reloads;
/operator/personalization still lands them on the new page; the old URL is no longer listed in
the Operator module; no operator-only data is read by the page (it is 100% browser-local, zero
middleware calls).

Scope

Will change (9 files + 1 dir move + 1 new file):

  1. dashboard/src/routes/settings/personalization/+page.svelte — moved verbatim from
    dashboard/src/routes/operator/personalization/+page.svelte, header File/Purpose/Last updated.
  2. dashboard/src/routes/operator/personalization/+page.ts — new 308 shim → /settings/personalization
    (same shape as routes/config/kill/+page.ts).
  3. dashboard/src/lib/nav.ts — drop /operator/personalization from the operator group, add
    /settings/personalization to the config group (Settings submenu).
  4. dashboard/src/lib/dashboard/destinations.ts — icon prefix /operator/personalization →
    /settings/personalization.
  5. dashboard/src/lib/page-help.ts — page-help entry key moved; /settings body mentions the new
    submenu item.
  6. dashboard/src/app.css — comment naming the page (line 103) updated.
  7. dashboard/src/lib/usecases-frontend.test.ts — operator href list, full NAV href list,
    accountSettingsNav name list, UC-FE-99 page path + pageHelp key.
  8. scripts/e2e/nav_selenium.py — NAV_HREFS moves the href; REDIRECTS gains the old→new entry.
  9. docs/use-cases/frontend/UC-FE-99-accent-personalization.md — story/preconditions/trigger/
    implementation now trust-level, version bump.
  10. docs/use-cases/frontend/UC-FE-08-nav.md — Settings submenu list gains Personalization, Operator
    list loses it; Implementation path updated.
  11. docs/use-cases/frontend/UC-FE-80-users-organizations.md — trigger line and Implementation cite
    drop personalization; version bump.

Will NOT touch:

  • middleware/**, agent/**, plans/** (no server-side or plan surface involved).
  • dashboard/src/lib/theme.ts, app.html — accent plumbing is unchanged, only the route moves.
  • No new dependencies, no new abstraction, no new config knob.
  • The Settings hub page (routes/settings/+page.svelte) gets no new card: not requested; the
    sidebar Settings submenu is the discoverability pointer (see Open questions).
  • docs/use-cases/README.md — it links the UC file, not the route path.

UC decision

No new UC. UC-FE-99 already owns this capability; the issue renames its route, so I update
UC-FE-99 (Story, Preconditions, Trigger, Implementation, version) plus its two consumers that
enumerate routes (UC-FE-08 nav groups, UC-FE-80 operator menu).

  • UC-FE-99 Implementation cite (real file, unchanged symbol contract):
    • dashboard/src/routes/settings/personalization/+page.svelte
    • dashboard/src/lib/theme.ts setAccentHue
    • dashboard/src/lib/nav.ts NAV_GROUPS
    • dashboard/src/app.html
  • UC-FE-99 Tests cite: dashboard/src/lib/usecases-frontend.test.ts (already mentions UC-FE-99).
  • UC-FE-99 related: [UC-FE-08, UC-FE-80, UC-FE-85] — unchanged, still bidirectional.
  • actor: stays Operator (repo-wide vocabulary for "console user" in every frontend UC, including
    user-level UC-FE-82/-83); the Story text now says signed-in user, not instance operator.

Ordered tasks (each with its verifying command)

# Task Verify
1 git mv the page dir to routes/settings/personalization/, fix its five-field header ls dashboard/src/routes/settings/personalization/
2 Add routes/operator/personalization/+page.ts 308 shim rg -n 'settings/personalization' dashboard/src/routes/operator/personalization/+page.ts
3 nav.ts + destinations.ts + page-help.ts + app.css comment rg -n personalization dashboard/src --glob '!*.test.ts'
4 Update usecases-frontend.test.ts lists/paths cd dashboard && bunx vitest run src/lib/usecases-frontend.test.ts
5 Update scripts/e2e/nav_selenium.py NAV_HREFS + REDIRECTS python3 -c "import ast,pathlib;ast.parse(pathlib.Path('scripts/e2e/nav_selenium.py').read_text())"
6 Update UCs FE-99 / FE-08 / FE-80 python3 docs/use-cases/_check.py
7 Gates + smoke python3 scripts/check-ai-headers.py; cd dashboard && bun run test && bun run check && bun run build; rg -n 'Showing lines' --glob '!node_modules' --glob '!.git'

One commit per task; Refs #70 in each; no closing keyword anywhere.

Open questions (assumption I proceed on)

  1. Old URL: keep a 308 shim (yes). Reason: #46 shipped it, links/bookmarks exist, and the repo
    already uses this exact pattern for /config/* → /settings/*. Cost is one 6-line file. Note: the
    shim sits behind operator/+layout.server.ts, so a non-operator hitting the old URL is 303'd to
    /settings by the layout before the shim runs — they were never able to use the old URL anyway.
  2. Where in the Settings submenu: append after Organization (Settings, <account/Profile>, Kill switch, Secrets, Organization, Personalization), so the existing account-name slot keeps
    index 1 and nothing else shifts.
  3. Settings hub card link: skipped (not requested; sidebar submenu is the pointer). Upgrade path
    if the operator wants it: a card next to the Appearance card, same shape as the Secrets card.
  4. actor: field: left as Operator (matches every frontend UC, incl. user-level ones); Story
    text states signed-in user. Flagged in the report in case the operator wants a distinct actor.
  5. Per-user persistence: unchanged and out of scope — the pick is localStorage
    (gotoi-accent), browser-local, not server-side per-account. The issue asks for the route move,
    not for a middleware-backed user preference.

Risk

  • Nav/UC list drift (highest): four separate literal lists pin the href (operator group test,
    full NAV list test, accountSettingsNav names, selenium NAV_HREFS). Miss one → red vitest or a
    stale e2e walk. Fallback: rg -n 'operator/personalization' must be empty except the shim.
  • UC checker: new Implementation path must exist on disk and related: must stay bidirectional;
    fallback is to run _check.py after each UC edit rather than at the end.
  • svelte-check / build: a moved .svelte file with a stale import path would fail; the page only
    imports $lib/*, so the move is inert. Fallback: re-read the file tail if anything looks truncated.
  • Layout-shadowed shim: accepted limitation, documented above (report + UC note).
# Plan — issue #70: move personalization from `/operator/personalization` to `/settings/personalization` ## Restated goal The accent-tint picker shipped in #46 (`dashboard/src/routes/operator/personalization/+page.svelte`, UC-FE-99) sits behind the instance-operator gate (`operator/+layout.server.ts` → non-operators 303 to `/settings`), but the preference is per-browser/per-user, never an instance-operator concern. Move the page to `/settings/personalization`, drop the operator gate (the ordinary session gate in `hooks.server.ts` is the only requirement), move every pointer that named the old URL (nav group item, destinations icon prefix, page-help, app.css comment, selen-check/usecase test lists, e2e walk list), and keep a thin 308 shim on the old path for bookmarks. **Done for the operator**: a normal signed-in user (no `instanceOperator`) opens `/settings/personalization` from the Settings submenu, picks a tint, and it sticks across reloads; `/operator/personalization` still lands them on the new page; the old URL is no longer listed in the Operator module; no operator-only data is read by the page (it is 100% browser-local, zero middleware calls). ## Scope **Will change (9 files + 1 dir move + 1 new file):** 1. `dashboard/src/routes/settings/personalization/+page.svelte` — moved verbatim from `dashboard/src/routes/operator/personalization/+page.svelte`, header `File`/`Purpose`/`Last` updated. 2. `dashboard/src/routes/operator/personalization/+page.ts` — **new** 308 shim → `/settings/personalization` (same shape as `routes/config/kill/+page.ts`). 3. `dashboard/src/lib/nav.ts` — drop `/operator/personalization` from the `operator` group, add `/settings/personalization` to the `config` group (Settings submenu). 4. `dashboard/src/lib/dashboard/destinations.ts` — icon prefix `/operator/personalization` → `/settings/personalization`. 5. `dashboard/src/lib/page-help.ts` — page-help entry key moved; `/settings` body mentions the new submenu item. 6. `dashboard/src/app.css` — comment naming the page (line 103) updated. 7. `dashboard/src/lib/usecases-frontend.test.ts` — operator href list, full NAV href list, `accountSettingsNav` name list, UC-FE-99 page path + `pageHelp` key. 8. `scripts/e2e/nav_selenium.py` — `NAV_HREFS` moves the href; `REDIRECTS` gains the old→new entry. 9. `docs/use-cases/frontend/UC-FE-99-accent-personalization.md` — story/preconditions/trigger/ implementation now trust-level, version bump. 10. `docs/use-cases/frontend/UC-FE-08-nav.md` — Settings submenu list gains Personalization, Operator list loses it; Implementation path updated. 11. `docs/use-cases/frontend/UC-FE-80-users-organizations.md` — trigger line and Implementation cite drop personalization; version bump. **Will NOT touch:** - `middleware/**`, `agent/**`, `plans/**` (no server-side or plan surface involved). - `dashboard/src/lib/theme.ts`, `app.html` — accent plumbing is unchanged, only the route moves. - No new dependencies, no new abstraction, no new config knob. - The Settings hub page (`routes/settings/+page.svelte`) gets **no** new card: not requested; the sidebar Settings submenu is the discoverability pointer (see Open questions). - `docs/use-cases/README.md` — it links the UC file, not the route path. ## UC decision **No new UC.** UC-FE-99 already owns this capability; the issue renames its route, so I update UC-FE-99 (Story, Preconditions, Trigger, Implementation, version) plus its two consumers that enumerate routes (UC-FE-08 nav groups, UC-FE-80 operator menu). - UC-FE-99 Implementation cite (real file, unchanged symbol contract): - `dashboard/src/routes/settings/personalization/+page.svelte` - `dashboard/src/lib/theme.ts` `setAccentHue` - `dashboard/src/lib/nav.ts` `NAV_GROUPS` - `dashboard/src/app.html` - UC-FE-99 Tests cite: `dashboard/src/lib/usecases-frontend.test.ts` (already mentions UC-FE-99). - UC-FE-99 `related: [UC-FE-08, UC-FE-80, UC-FE-85]` — unchanged, still bidirectional. - `actor:` stays `Operator` (repo-wide vocabulary for "console user" in every frontend UC, including user-level UC-FE-82/-83); the Story text now says *signed-in user*, not instance operator. ## Ordered tasks (each with its verifying command) | # | Task | Verify | |---|---|---| | 1 | `git mv` the page dir to `routes/settings/personalization/`, fix its five-field header | `ls dashboard/src/routes/settings/personalization/` | | 2 | Add `routes/operator/personalization/+page.ts` 308 shim | `rg -n 'settings/personalization' dashboard/src/routes/operator/personalization/+page.ts` | | 3 | `nav.ts` + `destinations.ts` + `page-help.ts` + `app.css` comment | `rg -n personalization dashboard/src --glob '!*.test.ts'` | | 4 | Update `usecases-frontend.test.ts` lists/paths | `cd dashboard && bunx vitest run src/lib/usecases-frontend.test.ts` | | 5 | Update `scripts/e2e/nav_selenium.py` NAV_HREFS + REDIRECTS | `python3 -c "import ast,pathlib;ast.parse(pathlib.Path('scripts/e2e/nav_selenium.py').read_text())"` | | 6 | Update UCs FE-99 / FE-08 / FE-80 | `python3 docs/use-cases/_check.py` | | 7 | Gates + smoke | `python3 scripts/check-ai-headers.py`; `cd dashboard && bun run test && bun run check && bun run build`; `rg -n 'Showing lines' --glob '!node_modules' --glob '!.git'` | One commit per task; `Refs #70` in each; no closing keyword anywhere. ## Open questions (assumption I proceed on) 1. **Old URL**: keep a 308 shim (yes). Reason: #46 shipped it, links/bookmarks exist, and the repo already uses this exact pattern for `/config/*` → `/settings/*`. Cost is one 6-line file. Note: the shim sits behind `operator/+layout.server.ts`, so a *non-operator* hitting the old URL is 303'd to `/settings` by the layout before the shim runs — they were never able to use the old URL anyway. 2. **Where in the Settings submenu**: append after Organization (`Settings, <account/Profile>, Kill switch, Secrets, Organization, Personalization`), so the existing account-name slot keeps index 1 and nothing else shifts. 3. **Settings hub card link**: skipped (not requested; sidebar submenu is the pointer). Upgrade path if the operator wants it: a card next to the Appearance card, same shape as the Secrets card. 4. **`actor:` field**: left as `Operator` (matches every frontend UC, incl. user-level ones); Story text states signed-in user. Flagged in the report in case the operator wants a distinct actor. 5. **Per-user persistence**: unchanged and out of scope — the pick is `localStorage` (`gotoi-accent`), browser-local, not server-side per-account. The issue asks for the route move, not for a middleware-backed user preference. ## Risk - **Nav/UC list drift** (highest): four separate literal lists pin the href (operator group test, full NAV list test, `accountSettingsNav` names, selenium `NAV_HREFS`). Miss one → red vitest or a stale e2e walk. Fallback: `rg -n 'operator/personalization'` must be empty except the shim. - **UC checker**: new Implementation path must exist on disk and `related:` must stay bidirectional; fallback is to run `_check.py` after each UC edit rather than at the end. - **svelte-check / build**: a moved `.svelte` file with a stale import path would fail; the page only imports `$lib/*`, so the move is inert. Fallback: re-read the file tail if anything looks truncated. - **Layout-shadowed shim**: accepted limitation, documented above (report + UC note).
Author
Collaborator

DONE — personalization moved to /settings/personalization (user-level).

Commits (branch issue/70-personalization-move, base origin/develop):

  • 0ed997e move page + /operator 308 shim
  • cd72fb1 nav/destinations/page-help/app.css pointers
  • e4b8c43 tests + selenium walk
  • 0cce80a UC-FE-99 / UC-FE-08 / UC-FE-80

Gates:

  • docs/use-cases/_check.py exit 0 (358 files, all conform)
  • scripts/check-ai-headers.py exit 0 (574 ok)
  • scripts/check-type-mirror.py exit 0
  • dashboard bun run test exit 0 (16 files, 251 tests)
  • dashboard bun run check exit 0 (0 errors, 7 pre-existing warnings)
  • dashboard bun run build exit 0
  • check-test-tampering.py exit 0; Showing lines scan empty

Live smoke (own middleware :3199 + scratch DB + Vite :5411, Chromium):

  • non-operator (instanceOperator:false) GET /settings/personalization → 200, picker renders, tint persists across reload (260→15)
  • GET /operator/personalization → 308 → new page (200)
  • non-operator on /operator/personalization → 303 /settings (layout gate, pre-existing)

Old URL kept as a 308 shim (matches /config/* pattern). No replacement operator gate needed: the page is localStorage-only and reads nothing from middleware. Nothing pushed; report at meta/issue-70.report.md.

DONE — personalization moved to /settings/personalization (user-level). Commits (branch `issue/70-personalization-move`, base origin/develop): - `0ed997e` move page + /operator 308 shim - `cd72fb1` nav/destinations/page-help/app.css pointers - `e4b8c43` tests + selenium walk - `0cce80a` UC-FE-99 / UC-FE-08 / UC-FE-80 Gates: - `docs/use-cases/_check.py` exit 0 (358 files, all conform) - `scripts/check-ai-headers.py` exit 0 (574 ok) - `scripts/check-type-mirror.py` exit 0 - `dashboard bun run test` exit 0 (16 files, 251 tests) - `dashboard bun run check` exit 0 (0 errors, 7 pre-existing warnings) - `dashboard bun run build` exit 0 - `check-test-tampering.py` exit 0; `Showing lines` scan empty Live smoke (own middleware :3199 + scratch DB + Vite :5411, Chromium): - non-operator (`instanceOperator:false`) GET /settings/personalization → 200, picker renders, tint persists across reload (260→15) - GET /operator/personalization → 308 → new page (200) - non-operator on /operator/personalization → 303 /settings (layout gate, pre-existing) Old URL kept as a 308 shim (matches /config/* pattern). No replacement operator gate needed: the page is localStorage-only and reads nothing from middleware. Nothing pushed; report at meta/issue-70.report.md.
Author
Collaborator

REVIEW: FIXED 2 — findings: (1) usecases-frontend.test.ts dropped two passing profile-href assertions in the accountSettingsNav test with no need (test weakening) — restored in 62469c4; (2) UC-FE-08 Main flow step 4 still enumerated the Settings submenu without Personalization after the move — added in a616a19. Verified: route moved, 308 shim matches the /config pattern, all pointers (nav, destinations, page-help, app.css, selenium NAV_HREFS/REDIRECTS, UC-FE-99/-08/-80) updated, _check.py / check-ai-headers.py / check-type-mirror.py / check-test-tampering.py exit 0, touched vitest file 105/105 green; UNFIXED: none

REVIEW: FIXED 2 — findings: (1) usecases-frontend.test.ts dropped two passing profile-href assertions in the accountSettingsNav test with no need (test weakening) — restored in 62469c4; (2) UC-FE-08 Main flow step 4 still enumerated the Settings submenu without Personalization after the move — added in a616a19. Verified: route moved, 308 shim matches the /config pattern, all pointers (nav, destinations, page-help, app.css, selenium NAV_HREFS/REDIRECTS, UC-FE-99/-08/-80) updated, _check.py / check-ai-headers.py / check-type-mirror.py / check-test-tampering.py exit 0, touched vitest file 105/105 green; UNFIXED: none
Author
Collaborator

Done. Branch issue/70-personalization-move (6 commits: 4 implementer + 2 review), PR: #76 (targets agent-develop).

Page moved to /settings/personalization (localStorage-only, no middleware reads), every pointer updated (nav, destinations.ts, page-help.ts, test lists, nav_selenium.py), old URL kept as 308 shim, UCs UC-FE-99/FE-08/FE-80 updated.

review: FIXED 2 — reviewer restored profile-href assertions the move dropped (62469c4) and fixed UC-FE-08 Settings submenu (a616a19).

Gates: _check.py green, ai-headers 574 ok, type-mirror green, dashboard vitest 251/251, svelte-check 0 errors / 7 pre-existing warnings, dashboard build green, hidden-tests exit 0. Live smoke: non-operator 200 on new path, old path 308s.

Done. Branch `issue/70-personalization-move` (6 commits: 4 implementer + 2 review), PR: https://git.eduard3v.com/EduarD3V/gotoi/pulls/76 (targets agent-develop). Page moved to /settings/personalization (localStorage-only, no middleware reads), every pointer updated (nav, destinations.ts, page-help.ts, test lists, nav_selenium.py), old URL kept as 308 shim, UCs UC-FE-99/FE-08/FE-80 updated. review: FIXED 2 — reviewer restored profile-href assertions the move dropped (62469c4) and fixed UC-FE-08 Settings submenu (a616a19). Gates: _check.py green, ai-headers 574 ok, type-mirror green, dashboard vitest 251/251, svelte-check 0 errors / 7 pre-existing warnings, dashboard build green, hidden-tests exit 0. Live smoke: non-operator 200 on new path, old path 308s.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
EduarD3V/gotoi#70
No description provided.