Skip to main content

Syncing (Duo)

In cloud mode the plan belongs to a household, and users are linked to it. A second person joins with an invite code.

Sharing modelโ€‹

  • One household = one shared state (jsonb).
  • Members are linked through a membership table.
  • Access is enforced by Row Level Security โ€” only a member can read and change their household's state.
  • The state is end-to-end encrypted; the household's encryption key is shared with the invited partner via key exchange, so neither we nor third parties can read it.

Adding a partner (one tap)โ€‹

While the plan has only one adult, the dashboard shows an "Invite partner" card. One tap opens a sheet with the invite code (and an optional email invite). The second person creates an account and enters the code โ€” from then on you both see the same plan. The card disappears once the partner joins.

Granting access to the encrypted data happens automatically: when the inviter opens or focuses the app, their device seals the household key for the partner (an idempotent step, safe to repeat). No manual settings or admin actions are needed.

Until that happens, the partner sees a calm "Connecting you" screen โ€” the app checks the connection every few seconds and completes it on its own. If it takes a while, just ask the other person to open GrapeVest on their device.

Save with mergeโ€‹

The state is written as a whole, with optimistic concurrency control:

  1. The app remembers the updated_at marker of the state it last fetched.
  2. On save, it sends that marker. If someone wrote in the meantime, the markers diverge โ†’ a conflict is detected.
  3. The app then fetches the fresh state and merges: month-keyed maps (entries, snapshots) are combined, and the remaining fields are taken from the newer side by updated_at. This way "two people filling in different months" doesn't lose data.

Fetching and refreshingโ€‹

The state is fetched when you enter the household, live whenever your partner makes a change (a Realtime subscription on the household row), and when you return to the tab/window as a fallback. When a partner's change arrives, a short "Your partner updated the plan" message is shown.

If you currently have local, not-yet-synced edits, the remote state is merged with them (we don't overwrite them silently) โ€” using the same rule as a write conflict (month-keyed maps merged, the rest by the newer updated_at).

Leaving and deletingโ€‹

  • Leave the household โ€” revokes this account's access; when the last member leaves, the household (and its state) is removed so no orphaned data is left.
  • Delete account โ€” removes any household where you're the only member (GDPR).