mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 06:03:36 +02:00
feat(chat): integrate chat project into monorepo with full app structure
- Restructure chat as apps/mobile, apps/web, apps/landing, backend - Add NestJS backend for secure Azure OpenAI API calls - Remove exposed API key from mobile app (security fix) - Add shared chat-types package - Create SvelteKit web app scaffold - Create Astro landing page scaffold - Update pnpm workspace configuration - Add project-level CLAUDE.md documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
fcf3a344b1
commit
c638a7ffee
155 changed files with 22622 additions and 348 deletions
176
chat/apps/mobile/scripts/spaces/create_spaces_rls.sql
Normal file
176
chat/apps/mobile/scripts/spaces/create_spaces_rls.sql
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
-- Enable Row Level Security for spaces tables
|
||||
ALTER TABLE public.spaces ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.space_members ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS policies for spaces
|
||||
|
||||
-- Space owners can do everything with their spaces
|
||||
CREATE POLICY spaces_owner_policy
|
||||
ON public.spaces
|
||||
TO authenticated
|
||||
USING (owner_id = auth.uid());
|
||||
|
||||
-- Members can view spaces they belong to
|
||||
CREATE POLICY spaces_member_select_policy
|
||||
ON public.spaces
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
id IN (
|
||||
SELECT space_id
|
||||
FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
);
|
||||
|
||||
-- RLS policies for space_members
|
||||
|
||||
-- Space owners can manage all members
|
||||
CREATE POLICY space_members_owner_policy
|
||||
ON public.space_members
|
||||
TO authenticated
|
||||
USING (
|
||||
space_id IN (
|
||||
SELECT id FROM public.spaces WHERE owner_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Space admins can manage members (except owners)
|
||||
CREATE POLICY space_members_admin_policy
|
||||
ON public.space_members
|
||||
TO authenticated
|
||||
USING (
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND role = 'admin' AND invitation_status = 'accepted'
|
||||
)
|
||||
AND role != 'owner'
|
||||
);
|
||||
|
||||
-- Users can see which spaces they are members of
|
||||
CREATE POLICY space_members_self_select_policy
|
||||
ON public.space_members
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid());
|
||||
|
||||
-- Users can accept/decline their own invitations
|
||||
CREATE POLICY space_members_invitation_update_policy
|
||||
ON public.space_members
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id = auth.uid())
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND (OLD.invitation_status = 'pending')
|
||||
AND (NEW.invitation_status IN ('accepted', 'declined'))
|
||||
AND (OLD.role = NEW.role)
|
||||
AND (OLD.space_id = NEW.space_id)
|
||||
AND (OLD.user_id = NEW.user_id)
|
||||
);
|
||||
|
||||
-- Update RLS policies for conversations
|
||||
|
||||
-- Modify existing policies to include space-based access
|
||||
DROP POLICY IF EXISTS conversations_select_policy ON conversations;
|
||||
CREATE POLICY conversations_select_policy
|
||||
ON conversations
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow space members to create conversations in spaces they belong to
|
||||
CREATE POLICY conversations_space_insert_policy
|
||||
ON conversations
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
user_id = auth.uid()
|
||||
AND
|
||||
(
|
||||
space_id IS NULL
|
||||
OR
|
||||
space_id IN (
|
||||
SELECT space_id FROM public.space_members
|
||||
WHERE user_id = auth.uid() AND invitation_status = 'accepted'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow updates to conversations in spaces based on role
|
||||
DROP POLICY IF EXISTS conversations_update_policy ON conversations;
|
||||
CREATE POLICY conversations_update_policy
|
||||
ON conversations
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT sm.space_id FROM public.space_members sm
|
||||
WHERE sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND sm.role IN ('owner', 'admin')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Allow deletion of conversations in spaces based on role
|
||||
DROP POLICY IF EXISTS conversations_delete_policy ON conversations;
|
||||
CREATE POLICY conversations_delete_policy
|
||||
ON conversations
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id = auth.uid()
|
||||
OR
|
||||
(
|
||||
space_id IN (
|
||||
SELECT sm.space_id FROM public.space_members sm
|
||||
WHERE sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND sm.role IN ('owner', 'admin')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Helper function to check if a user has access to a space
|
||||
CREATE OR REPLACE FUNCTION public.user_has_space_access(space_uuid UUID, role_level TEXT DEFAULT 'viewer')
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
has_access BOOLEAN;
|
||||
role_hierarchy TEXT[];
|
||||
BEGIN
|
||||
-- Define role hierarchy from highest to lowest
|
||||
role_hierarchy := ARRAY['owner', 'admin', 'member', 'viewer'];
|
||||
|
||||
-- Find position of requested role in hierarchy
|
||||
WITH role_positions AS (
|
||||
SELECT
|
||||
unnest(role_hierarchy) AS role,
|
||||
row_number() OVER () AS position
|
||||
)
|
||||
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM public.space_members sm
|
||||
JOIN role_positions rp1 ON sm.role = rp1.role
|
||||
JOIN role_positions rp2 ON rp2.role = role_level
|
||||
WHERE sm.space_id = space_uuid
|
||||
AND sm.user_id = auth.uid()
|
||||
AND sm.invitation_status = 'accepted'
|
||||
AND rp1.position <= rp2.position -- Check if user's role is at least the required level
|
||||
) INTO has_access;
|
||||
|
||||
RETURN has_access;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
Loading…
Add table
Add a link
Reference in a new issue