Byt ägare & överlämning — flow doc
Living doc — how changing an object’s owner works now. For why, see ADR-0078, ADR-0080 and the use-case (UC-103). For history, see the spec. This doc is rewritten in place as the flow changes; it does not restate the ADR/spec.
What it is
Two ways to move ownership between ägare (owners):
- Single object — the existing “Byt ägare” on one object.
- With contents — “ge bort lådan med sakerna i”: a whole branch changes owner as one gated transaction, with a per-object preview and an accept step.
An object has exactly one ägare (ADR-0078), so a transfer always moves objects from one owner to exactly one other owner.
How it works
Single object — “Byt ägare” (iOS, existing)
changeObjectOwner moves one object’s owner. It is membership-checked and dual-writes
Postgres (owner_organization_id) + Neo4j (ownerOrganisationId — British spelling). This
is the building block the with-contents transfer generalises.
With contents — gated transaction (API live; iOS UI in progress)
- Initiate —
initiateOwnershipTransfer(rootObjectId, objectIds, toOrganizationId):- Requires the Ägare (owner) role in the giving owner.
- Freezes the exact set of objects into a frozen list (
object_ids, max 1000 objects; the World root is excluded). Only objects the initiator has ownership rights to can be included. - Objects with a pending sync (temp-id, not yet on the server) cannot be part of a gated transfer — the UI filters them out with an explanation (temp→server-id handoff class).
- Gate / auto-complete — if the initiator also has owner/admin in the receiving owner, the transfer completes immediately (you do not accept from yourself — the Göran Hamberg case). Otherwise it becomes pending: the receiving owner’s owners see an incoming transfer in-app and get an email (“Paul vill ge dig Verktygslådan med 12 saker”).
- Resolve —
acceptOwnershipTransfer(id)/declineOwnershipTransfer(id)by a receiving owner (an admin cannot accept — deliberate);revokeOwnershipTransfer(id)by the initiator while pending. - On accept — the id list is re-validated: objects moved or deleted during the wait are
skipped and reported back as
skippedObjectIds. The remaining objects change owner in batch (same dual-write pattern aschangeObjectOwner,executemany/UNWIND), and the transfer is markedcompleted.
NORMAL / CURRENT preview semantics
The branch shown for selection is the root’s NORMAL subtree (where things belong) plus what is CURRENT there — items physically present but belonging elsewhere are marked “står här men hör hemma annanstans — följer inte med om du inte bockar i”. Location is not ownership: someone else’s things sitting in your box do not transfer unless you tick them.
Local-first
The initiator’s UI never waits — the transfer shows immediately as “väntar på Göran”, and status updates arrive via sync. The receiving accept is cross-user (server-mediated by definition), but the accept button responds optimistically.
Receipt history (archived, not deleted)
Rows in ownership_transfers are archived, never deleted — they are the receipt/kvitto
history. This is deliberate groundwork for future sale (kind is gift now, sale
later) and a future NFT ownership gate, where the on-chain confirmation becomes one more
gate condition in the same transaction lifecycle (an addition, not a rebuild — ADR-0080).
Current UI status
- API: initiate / accept / decline / revoke and
myTransfersare live; the cascade/subtree work is done by this feature (the old “cascade” API backlog item is closed). - iOS: the “med innehåll” preview and the incoming-transfer accept/decline UI are in progress. Single-object “Byt ägare” already exists. Update this section when iOS lands.
Known edges
- Objects moved/deleted during the wait: frozen list + re-validation → reported as
skippedObjectIds. - Receiving owner with no app-using members: the gate needs at least one owner user there; otherwise only the auto-complete case (initiator has rights in the receiver) is possible — exactly today’s “I create the owner for Göran” situation.
Related
- Use-case: UC-103
- Decisions: ADR-0078 (exakt en ägare; delat ägande = gemensam ägare), ADR-0080
(överlämning är en gated transaktion) — see
internal/decisions/INDEX.md - Sibling flow: bjud-in-anvandare.md
- History:
docs/specs/2026-07-15-owner-invitations-and-transfers-design.md