wacrm/supabase/migrations
Arnas Donauskas 0a1cf97d6b
feat(api): account + members management endpoints
PR 3 of the multi-user accounts series. Lands the server-side
endpoints the upcoming Members tab UI will call. Built on the
helpers from #169 (`requireRole`, `getCurrentAccount`,
`toErrorResponse`).

API surface
- GET    /api/account                     — caller's account + role
- PATCH  /api/account                     — rename                  (admin+)
- GET    /api/account/members             — roster; email visible to admin+ only
- PATCH  /api/account/members/[userId]    — change role             (admin+)
- DELETE /api/account/members/[userId]    — remove                  (admin+)
- POST   /api/account/transfer-ownership  — atomic owner handoff    (owner)

Member-role writes can't ride on the regular `profiles_update` RLS
policy (which only allows self-edits — admins can't modify a
teammate's row that way). The three SECURITY DEFINER RPCs in the
new migration are the scoped escape hatches:

- `set_member_role(p_user_id, p_new_role)` — admin+ only. Blocks
  promotion to / demotion from owner (use transfer instead) and
  self-targeting.
- `remove_account_member(p_user_id)` — admin+ only. Creates a
  fresh personal account for the removed user and reassigns
  their profile as its 'owner' — mirror of the signup flow, so
  they keep their login and just "start over". Blocks removing
  the owner or self.
- `transfer_account_ownership(p_new_owner_user_id)` — owner only.
  Atomically demotes current owner → admin, promotes target →
  owner, and points accounts.owner_user_id at the new owner.
  Demote-first ordering means the temporary "zero owners" state
  is never visible.

Error contract
- Each RPC raises with SQLSTATE 42501 (forbidden) or 22023 (bad
  input) and a human-readable RAISE message. The route handlers
  map these onto 403 / 400 respectively; anything else collapses
  to a generic 500.
- The TS guards (e.g. `requireRole('owner')` on the transfer
  route, `isAccountRole(role)` on the PATCH route) are
  belt-and-braces — they fail fast before the Supabase round
  trip but the RPCs would catch the same violations regardless.

Field visibility
- `GET /api/account/members` returns `email` only when the
  caller is admin+. Agents and viewers see name + avatar + role
  + joined date — matches the planning decision so a viewer
  can't harvest the team's email list.

Verification
- `npm run lint`      → 0 errors (same 20 pre-existing warnings)
- `npm run typecheck` → clean
- `npm test`          → 366/366 pass
- `npm run build`     → succeeds; the 4 new routes register as ƒ
                        (dynamic — they all use `next/headers`
                        cookies via the SSR client)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 15:00:27 +03:00
..
001_initial_schema.sql fix: make migration idempotent 2026-04-16 19:46:41 +03:00
002_pipelines_enhancements.sql feat(pipelines): Kanban drag-drop, analytics, deal sheet, contact deals tab 2026-04-16 22:38:45 +03:00
003_broadcast_recipient_wamid.sql fix(broadcasts): per-recipient variables, webhook status sync, rate limit 2026-04-17 11:22:38 +03:00
004_contact_delete_set_null.sql fix(contacts): allow deletion — SET NULL on broadcast_recipients, deals 2026-04-17 16:56:45 +03:00
005_broadcast_counts_incremental.sql fix(broadcasts): senior-review hardening pass 2026-04-17 17:38:52 +03:00
006_automations.sql feat(automations): visual flow builder, engine, and logs viewer 2026-04-17 19:39:02 +03:00
007_automations_increment_counter.sql fix(automations): atomic execution_count via SQL function (migration 007) 2026-04-17 21:45:27 +03:00
008_profile_avatars_storage.sql feat(settings): user profile management 2026-04-20 17:40:39 +03:00
009_message_actions.sql feat(inbox): reactions, reply-to, and copy on chat messages 2026-05-19 16:17:26 +03:00
010_flows.sql feat(flows): foundation for interactive WhatsApp messages (PR 1/4) 2026-05-22 13:12:27 +03:00
011_profile_beta_features.sql feat(beta): per-account beta_features flag on profiles, gating Flows 2026-05-22 12:57:33 +03:00
012_flows_increment_counter.sql fix(flows): atomic execution_count increment via SECURITY DEFINER RPC 2026-05-22 15:39:00 +03:00
013_whatsapp_config_phone_number_id_unique.sql fix(whatsapp): prevent silent inbound-message drop when two users share a phone_number_id 2026-05-26 10:35:59 +02:00
014_message_templates_meta_integration.sql fix(migration-014): drop subquery from buttons CHECK (Postgres disallows it) 2026-05-29 12:21:14 +02:00
015_whatsapp_config_registration.sql fix(whatsapp): register phone numbers on Meta + verify subscription state 2026-05-29 18:12:38 +02:00
016_flow_media.sql feat(flows): add send_media node for image / video / document sends 2026-05-29 19:11:29 +02:00
017_account_sharing.sql fix(db): create profile.account_id before is_account_member helper 2026-05-31 13:06:14 +03:00
018_account_member_rpcs.sql feat(api): account + members management endpoints 2026-05-31 15:00:27 +03:00