mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
* feat(security): replace instant member-add with invitation acceptance flow Users invited to a workspace must now explicitly accept the invitation before becoming a member. This fixes the security vulnerability where knowing someone's email was enough to auto-register their runtime to your workspace. Changes: - Add workspace_invitation table with pending/accepted/declined/expired states - Replace CreateMember with CreateInvitation (same endpoint, new behavior) - Add accept/decline/revoke/list invitation API endpoints - Add invitation WS events for real-time notification - Frontend: invitation accept/decline UI in workspace switcher - Frontend: pending invitations section in members settings tab * fix(invitation): address PR review nits - Fix invitation:revoked listener to send event to invitee user (was no-op) - Remove duplicate queryClient2 in app-sidebar.tsx, reuse existing queryClient - Add expires_at > now() filter to ListPendingInvitationsByWorkspace query
21 lines
1.1 KiB
SQL
21 lines
1.1 KiB
SQL
CREATE TABLE workspace_invitation (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspace(id) ON DELETE CASCADE,
|
|
inviter_id UUID NOT NULL REFERENCES "user"(id),
|
|
invitee_email TEXT NOT NULL,
|
|
invitee_user_id UUID REFERENCES "user"(id),
|
|
role TEXT NOT NULL CHECK (role IN ('admin', 'member')),
|
|
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'accepted', 'declined', 'expired')),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
expires_at TIMESTAMPTZ NOT NULL DEFAULT now() + INTERVAL '7 days'
|
|
);
|
|
|
|
-- Only one pending invitation per workspace + email at a time.
|
|
CREATE UNIQUE INDEX idx_invitation_unique_pending
|
|
ON workspace_invitation(workspace_id, invitee_email) WHERE status = 'pending';
|
|
|
|
-- Fast lookup of pending invitations for a user (by email or user_id).
|
|
CREATE INDEX idx_invitation_invitee_email ON workspace_invitation(invitee_email) WHERE status = 'pending';
|
|
CREATE INDEX idx_invitation_invitee_user ON workspace_invitation(invitee_user_id) WHERE status = 'pending';
|