max / makenotwork
| 1 | -- A collaborator has to agree before their split is live. |
| 2 | -- |
| 3 | -- Until now an owner could add anyone to a project with a revenue split and the |
| 4 | -- other person found out when money moved, or never. That was tolerable while |
| 5 | -- everyone was paid in dollars. It stopped being tolerable with per-creator |
| 6 | -- settlement currency (migration 190): a split is denominated in the *paying* |
| 7 | -- project's currency, so a collaborator paid in a different one carries a |
| 8 | -- conversion out of their share. Nobody should carry a cost they were never |
| 9 | -- offered the chance to refuse. |
| 10 | -- |
| 11 | -- PENDING SPLITS DO NOT PAY. `accepted_at IS NULL` means the percentage is |
| 12 | -- allocated but inert: sales in the meantime are wholly the owner's, and the |
| 13 | -- collaborator's share begins at acceptance rather than being backdated. The |
| 14 | -- alternative, accruing a share for someone who has not agreed, invents a debt |
| 15 | -- to a person who may yet decline, and unwinding it is worse than not having it. |
| 16 | -- |
| 17 | -- The percentage is still reserved while pending, so `get_total_split_percent` |
| 18 | -- keeps counting it and an owner cannot promise 60% to one person and 60% to |
| 19 | -- another while the first invitation sits unanswered. |
| 20 | -- |
| 21 | -- DECLINING DELETES THE ROW. There is no `declined_at`: a declined invitation |
| 22 | -- is not a state the system needs to remember, and keeping one would only |
| 23 | -- create the question of whether a re-invite is allowed (it is, by adding them |
| 24 | -- again). |
| 25 | |
| 26 | project_members |
| 27 | ADD COLUMN accepted_at TIMESTAMPTZ; |
| 28 | |
| 29 | -- Everyone who is already a member was added under the old rules, where being |
| 30 | -- added *was* the agreement. Backdating their acceptance to when they were |
| 31 | -- added keeps every live split live; leaving them NULL would silently switch |
| 32 | -- off every existing collaborator's revenue share, which is the one outcome |
| 33 | -- this migration must not have. |
| 34 | UPDATE project_members SET accepted_at = added_at WHERE accepted_at IS NULL; |
| 35 | |
| 36 | COMMENT ON COLUMN project_members.accepted_at IS |
| 37 | 'When the collaborator agreed to the split. NULL = invited but not yet ' |
| 38 | 'accepted: the percentage is reserved but earns nothing. Rows predating ' |
| 39 | 'migration 194 were backdated to added_at, since being added was the ' |
| 40 | 'agreement under the old rules.'; |
| 41 | |
| 42 | -- Finding a creator's pending invitations is a per-user lookup on a table |
| 43 | -- indexed only by project and user; this makes the dashboard badge cheap. |
| 44 | NOT EXISTS idx_project_members_pending |
| 45 | ON project_members (user_id) |
| 46 | WHERE accepted_at IS NULL; |
| 47 |