Skip to content

refactor(frontend): migrate project backgrounds to v2 client - #3694

Draft
tink-bot wants to merge 18 commits into
refactor-api-client-v2-project-viewsfrom
refactor-api-client-v2-project-backgrounds
Draft

refactor(frontend): migrate project backgrounds to v2 client#3694
tink-bot wants to merge 18 commits into
refactor-api-client-v2-project-viewsfrom
refactor-api-client-v2-project-backgrounds

Conversation

@tink-bot

@tink-bot tink-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Project backgrounds still used legacy services and split cache ownership.

How to verify

  1. Open project background settings and select an Unsplash image or upload an image.
  2. Expected: The background and preview update without losing project permissions or metadata.
  3. Remove the background.
  4. Expected: The background clears immediately and remains cleared after reload.

@tink-bot
tink-bot temporarily deployed to preview-trusted August 31, 2026 22:42 — with GitHub Actions Inactive
@tink-bot tink-bot changed the title refactor api client v2 project backgrounds refactor(frontend): migrate project backgrounds to v2 client Aug 31, 2026
@github-actions github-actions Bot added area/api-v2 Huma-backed /api/v2 API surface area/theming Backgrounds, colors, dark mode, UI customization labels Aug 31, 2026
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown

Preview Deployment

Preview deployments for this PR are available at:

URL Tag Commit
https://pr-3694.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:pr-3694 latest
https://sha-3138f067b9cb21c4e8d1f19be6c5db1609df6e08.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-3138f067b9cb21c4e8d1f19be6c5db1609df6e08 3138f06
https://sha-41e9e2332f92648a416ede96528caf1236fd1372.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-41e9e2332f92648a416ede96528caf1236fd1372 41e9e23
https://sha-03fd55b2195450b74f2a3d56a10b719b8ce5e792.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-03fd55b2195450b74f2a3d56a10b719b8ce5e792 03fd55b
https://sha-98e7c13916a405c671650b24fb5e560e076046a8.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-98e7c13916a405c671650b24fb5e560e076046a8 98e7c13
https://sha-f3d21d4178bbc1c8e6b50372d51f0ee3d88f6ee3.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-f3d21d4178bbc1c8e6b50372d51f0ee3d88f6ee3 f3d21d4
https://sha-d8f5e0d3a90fdb3014500640b68ba0f00a89d2c4.preview.vikunja.dev ghcr.io/go-vikunja/vikunja:sha-d8f5e0d3a90fdb3014500640b68ba0f00a89d2c4 d8f5e0d

The preview environment will start automatically on first visit. Subsequent pushes to this PR will update the pr-3694 image — the preview picks up the new version on restart. The per-commit URLs point to a specific version and will not change.

Run locally with Docker
docker pull ghcr.io/go-vikunja/vikunja:pr-3694
docker run -p 3456:3456 ghcr.io/go-vikunja/vikunja:pr-3694

Last updated for commit 3138f06

@tink-bot
tink-bot force-pushed the refactor-api-client-v2-project-backgrounds branch from 02b64c5 to f3d21d4 Compare September 1, 2026 19:14
@tink-bot tink-bot added the pr-swarm/started PR Swarm run is currently active on this PR label Sep 1, 2026
Address pr-swarm findings: remove the uncalled backgroundLoading export and
the blurHashLoading bookkeeping it required, log blur hash decode failures
instead of surfacing them as global error toasts, and narrow the parameter
back to ProjectResponse.
Address pr-swarm security finding: the auth store clears the query cache
when the signed-in identity changes, but the base store kept the previous
account's background object URLs and current project id alive across an
SPA logout, so the next user on the same tab could briefly see them.
Address pr-swarm findings: background mutations now capture and assert the
client request context like every sibling mutation, resolve to the merged
cached project instead of the sparse wire response, flatten Unsplash search
results to the fields the UI needs, guard the blob responses, and drop the
unused unsplash key.
… settings

Address pr-swarm findings: render each Unsplash result through a small
component that owns its thumbnail query and object URLs instead of hand
rolled pending sets and revoke bookkeeping, pass the merged project from
the mutations straight to the base store, ignore mutation results after
the user moved to another project, encode the attribution handle and skip
the link when unknown, and hide write affordances without write access.
tink-bot pushed a commit that referenced this pull request Sep 1, 2026
Address pr-swarm runtime findings: a failed Unsplash search rendered an
empty grid with no message or retry, the image tiles had no accessible
name, and the attribution link was focusable but invisible without hover.

@tink-bot tink-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 PR Swarm — automated review, round 1. See inline comments.

Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue Outdated
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue Outdated
Comment thread frontend/src/stores/base.ts Outdated
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue Outdated
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue Outdated
Comment thread frontend/src/stores/base.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/composables/useProjectBackground.test.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
@tink-bot

tink-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator Author

🤖 PR Swarm — automated review. Panel: bughunter · security · conventions · design · verifier — round 3 (final) @ 3138f06 (+43/−80 this round, PR +1448/−1266)

Verdict: ✅ APPROVE

Three rounds, 50 findings, 43 fixed, 7 nit-resolved, 0 deferred. Round 3 found no regressions from round 2; verifier re-drove every changed flow on a local build of 41e9e2332 with zero findings. Last three commits (handler tail extraction, log fix, test consolidation) are covered by unit tests but not by a runtime pass — round cap hit. PR net diff vs base: production code smaller than original submission; growth is tests (base.test.ts, ProjectSettingsBackground.test.ts, useBlurHashUrl.test.ts, UnsplashBackgroundThumbnail.test.ts, expanded query tests).

❓ Needs your input (0)

none

✅ Fixed this round (4)

  • ProjectSettingsBackground.vue:185 — post-mutation tail (route recheck, store gate, toast) extracted to applyBackground bda5c7d15
  • stores/base.test.ts:116 — same-identity no-reset case restored; three tests collapsed to one table 3138f067b
  • UnsplashBackgroundThumbnail.test.ts — exercises real unsplashAuthor with real info 3138f067b
  • UnsplashBackgroundThumbnail.vue:58 — log handles non-Error problem bodies 1ff12cfe9

💤 Resolved as nit (3)

  • client/queries/projectBackgrounds.ts:63 [design] — filter id-less Unsplash items in queryFn: decided round 2 (raw pages keep pagination honest; plan narrows at use site).
  • client/queries/projectBackgrounds.ts:100 [bughunter] — explicit eviction mode: disagree, sparse set response would corrupt cache patch either way; v2 set/upload end in ReadOne.
  • client/queries/projectBackgrounds.ts:106 [bughunter] — swallow follow-up fetch failure: disagree, needs both caches empty plus read failure; fake project was the round-1 defect.

🔎 Runtime verification (round 3, local build of 41e9e2332, v2.6.0-60-41e9e2332f)

  • ✅ deep-link-upload-and-remove — fresh load of settings URL: toast on upload, toast + history.back() once on remove, API background_information: null
    deeplink
  • ✅ modal-from-home-unsplash — sidebar dropdown on /: toast, modal usable, no hang
  • ✅ in-app-path-base-store-sync — background paints behind modal within 200 ms; remove returns via router.back()
  • ✅ unsplash-thumbnail-component — id-less item dropped, encoded attribution hrefs inside tiles, aria-labels with author, URLs revoked on term change and dialog close
    thumbnails
  • ✅ project-query-loading-and-error — loader gates all controls; 500 renders ErrorMessage
  • ✅ read-only-user — only the explanatory sentence; zero requests to /backgrounds/unsplash/search
  • ✅ identity-reset-shared-key — logout A / login B same document: no background, hasTasks not leaked (B sees import hint)
  • ✅ project-cards-object-urls — cards paint, URLs revoked on unmount
  • ✅ console-cleanliness — 0 Vue warnings; thumbnail failure logs message
More round-3 screenshots

home unsplash
loading
error
readonly
identity A
identity B
cards

Reviewer summaries (round 3)

Reviewer Assessment
🐛 bughunter No regression from round 2; traced null-heuristic, cancel interplay, useObjectUrl, enabled reactivity, identity watchers. Three LOW judgment calls, two declined with reasons.
🛡 security All controls hold; identityKey collision-free for every reachable transition; canWrite fail-closed with server CanWrite independent; attribution XSS-safe. One logging nit.
📏 conventions Clean.
📐 design Consolidations justified; flagged triplicated handler tail, deleted negative test, test mocking a pure helper — all addressed; one placement disagreement declined.
🔎 verifier All eight re-driven flows pass; no findings.

Out-of-scope notes for follow-ups

  • Backend: backgroundRemove (v2) and RemoveProjectBackground (v1) call DeleteBackgroundFileIfExists with BackgroundFileID always 0 — stored files orphaned on removal (pre-existing, bughunter r1).
  • Backend: Info interface{} on background images generates info?: unknown; typing it would remove the runtime narrowing in unsplashAuthor.
  • Backend: backgroundRemove could return project.ReadOne so the frontend merge dance is unnecessary.
  • Base store still owns current-project background URLs per plan Phase 2 step 6; deriving from useCurrentProject is a later phase.
Previous rounds (2)

round 2 @ 41e9e23⚠️ REQUEST CHANGES (pre-fix): 20 findings, 20 fixed, 0 nit, 0 deferred. Regression from round-1 bail placement fixed; shared identityKey, getCachedProject, useBlurHashUrl/useObjectUrl; Unsplash flatten reverted per plan. Runtime: local build of 98e7c13, deep-link bail observed then fixed; screenshots under round-2. Duration 24m35s.
round 1 @ 98e7c13⚠️ REQUEST CHANGES (pre-fix): 23 findings, 19 fixed, 4 nit-resolved, 0 deferred. Request-context fence, sparse-response fake project, identity leak of blob URLs, thumbnail bookkeeping → component. Runtime: local build of f3d21d4, all "How to verify" flows pass; screenshots under round-1. Duration 28m22s.

Address pr-swarm finding: the identity-change watcher's tuple-and-guard
logic was about to be duplicated in the base store, so derive a single
identity key on the auth store and watch that instead.
Address pr-swarm finding: background mutations need the same detail-or-list
cache lookup that updateProject already does, so share it.
Address pr-swarm findings: derive the cache update and blob eviction from
the response instead of per-call mode arguments, fetch the project when
nothing is cached instead of fabricating a blank one, type the background
fields from the generated schema, and return raw Unsplash results so the
optional fields are narrowed at the use site as the migration plan asks.
Address pr-swarm findings: watch the auth store's identity key instead of
re-implementing its guard, and include the has-tasks flag in the reset so
it cannot leak between accounts on the same tab.
Address pr-swarm findings: replace the hand-rolled object URL lifecycle
in useProjectBackground with useObjectUrl and a shared useBlurHashUrl
composable, which also recreates the URL when a project regains its
background while the blob is still cached.
…r project

Address pr-swarm findings: the stale-route bail swallowed the success toast
and the modal close whenever background settings were opened from the
sidebar or by URL for a project that is not the current one, so only the
base store sync is gated on that now. Also narrow Unsplash results at the
use site, move the attribution into the thumbnail component, show the
project query's loading and error state instead of hiding controls, and
stop running the Unsplash search for users who cannot apply a background.
tink-bot pushed a commit that referenced this pull request Sep 1, 2026
Address pr-swarm runtime findings: read-only users saw an empty background
dialog, and thumbnail load failures logged a bare reactive proxy.

@tink-bot tink-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 PR Swarm — automated review, round 2. See inline comments.

Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue Outdated
Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/composables/useProjectBackground.ts
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue
Comment thread frontend/src/stores/base.ts
Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue
Comment thread frontend/src/components/project/partials/UnsplashBackgroundThumbnail.vue Outdated
Address pr-swarm finding: the route recheck, base store gate and toast
were copied into all three background handlers.
Address pr-swarm finding: the generated client throws the parsed problem
body on HTTP failures, so error.message logged undefined.
Address pr-swarm findings: restore the negative identity-reset case as a
table row and let the thumbnail test exercise the real unsplashAuthor.

@tink-bot tink-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 PR Swarm — automated review, round 3 (final). See inline comments.

Comment thread frontend/src/views/project/settings/ProjectSettingsBackground.vue
Comment thread frontend/src/stores/base.test.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
Comment thread frontend/src/client/queries/projectBackgrounds.ts
@tink-bot tink-bot added pr-swarm/done PR Swarm finished, nothing deferred and removed pr-swarm/started PR Swarm run is currently active on this PR labels Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api-v2 Huma-backed /api/v2 API surface area/theming Backgrounds, colors, dark mode, UI customization pr-swarm/done PR Swarm finished, nothing deferred

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants