Skip to content

fix: changing the family code signs other devices out; recipes and meal plans merge into the shopping list - #417

Merged
svenger87 merged 1 commit into
mainfrom
fix/join-code-revoke-and-shopping-merge
Oct 25, 2026
Merged

svenger87 merged 1 commit into
mainfrom
fix/join-code-revoke-and-shopping-merge

Conversation

@svenger87

Copy link
Copy Markdown
Owner

Summary

Two bugs that came up while comparing Kinboard with Yuvomi.

1. Changing the family code didn't sign anyone out (security).

  • The confirmation said "all connected devices will need to rejoin", but rotation was only a browser-side UPDATE of families.join_code.
  • Sessions last a year, and revokeFamilySessions in lib/session.ts was written "for a join-code rotation" but had no callers. After a lost phone, a new code only stopped new devices from joining.
  • New POST /api/family/join-code:
    • Rotates the code using crypto.randomInt. The browser version used Math.random.
    • Requires a session and the settings PIN.
    • Revokes every other session of the family and keeps the caller's.
  • A failed revoke now throws, so the route never reports success when nobody was signed out.
  • The confirm text now says exactly what happens (en/de/fr), and failures show a toast.

2. Sending a recipe or the meal plan to the shopping list created duplicates.

  • useAddRecipeToShoppingList and useGenerateShoppingFromMealPlan did a plain .insert. Milk already on the list was added a second time, and the same recipe added twice doubled every item.
  • lib/shopping-merge.ts already had the right rules, but only the assistant API used them.
  • addOrMergeShoppingItems moves from the server-only lib/shopping-enrich.ts into a new browser-safe lib/shopping-add.ts. Its shoppingStore works with either Supabase client. shopping-enrich.ts re-exports it, so the server callers are unchanged.
  • Both hooks now merge, and they invalidate the shopping page's real query key (queryKeys.shoppingItems) instead of ["shopping_items", …], which nothing reads.

Type of change

  • Bug fix
  • New feature
  • Refactor (no user-facing change)
  • Documentation
  • Translation
  • Plugin / integration

Test plan

  • e2e/join-code-rotation.spec.ts: revokes others but keeps the caller, needs a session and PIN, uses the session's family only, crypto code, the hook goes through the route, strings exist in all locales
  • e2e/shopping-merge-ui.spec.ts: merges into an existing item and inserts a new one through a fake Supabase client; both hooks use the merge; shopping-add.ts imports nothing server-only
  • Full stack-free spec suite as CI runs it: 10,419 passed
  • npm run lint, npx tsc --noEmit, node scripts/check-changelog-sections.mjs
  • Not exercised on a running stack: rotate the code on one device and check that a second device lands on the join screen while the first stays in

Screenshots

Text-only change to the existing confirmation dialog.

Checklist

  • npm run lint passes
  • New strings added to both messages/en.json and messages/de.json (and fr)
  • Schema changes ship as a new webapp/docker/migration*.sql file (none needed)
  • No secrets, real API keys, or personal hostnames in the diff
  • I agree to the licensing of contributions
  • CHANGELOG.md updated under [Unreleased] (Fixed and Security)
  • Commit follows Conventional Commits

Generated by Claude Code

…al plans merge into the shopping list

Changing the join code was a browser-side UPDATE of families.join_code.
The confirmation promised that every connected device would need to
rejoin, but sessions last a year and revokeFamilySessions had no caller,
so a lost phone stayed signed in. POST /api/family/join-code now rotates
the code (crypto.randomInt, settings PIN required) and revokes every
other session of the family, keeping the caller's.

"Add to shopping list" on a recipe and "generate shopping list" on the
meal plan did a plain insert, so items already on the list were added a
second time. addOrMergeShoppingItems moves out of the server-only
lib/shopping-enrich.ts into lib/shopping-add.ts, which works with either
Supabase client. Both hooks now go through it, and they invalidate the
shopping page's real query key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STyQ3UYK3VBFvcZ3Je5jCr
@svenger87
svenger87 marked this pull request as ready for review October 25, 2026 13:42
@svenger87
svenger87 merged commit 3e239d5 into main Oct 25, 2026
14 checks passed
@svenger87
svenger87 deleted the fix/join-code-revoke-and-shopping-merge branch October 25, 2026 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants