diff --git a/api/gameforge/team.ts b/api/gameforge/team.ts index 8dac79cc..06e9f528 100644 --- a/api/gameforge/team.ts +++ b/api/gameforge/team.ts @@ -13,11 +13,9 @@ export default async function handler(req: any, res: any) { if (method === "GET") { const { user_id, project_id, role, limit = 50, offset = 0 } = query; + // Fix: Use correct join syntax for Supabase/Postgres foreign table let dbQuery = supabase.from("gameforge_team_members").select( - ` - *, - user_profiles(id, full_name, avatar_url, email) - `, + `*,user_profiles:users(id, full_name, avatar_url, email)`, { count: "exact" }, ); @@ -30,7 +28,10 @@ export default async function handler(req: any, res: any) { .order("joined_date", { ascending: false }) .range(Number(offset), Number(offset) + Number(limit) - 1); - if (error) throw error; + if (error) { + console.error("[GameForge Team SQL]", error); + throw error; + } return res.json({ data: user_id ? data : data, total: count, diff --git a/api/staff/directory.ts b/api/staff/directory.ts index aed7e5d4..a8b13b78 100644 --- a/api/staff/directory.ts +++ b/api/staff/directory.ts @@ -16,10 +16,15 @@ export default async (req: Request) => { return new Response("Unauthorized", { status: 401 }); } + // Pagination support + const url = new URL(req.url); + const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50"))); + const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0")); + + const start = Date.now(); const { data: directory, error } = await supabase .from("staff_members") - .select( - ` + .select(` id, user_id, full_name, @@ -32,9 +37,11 @@ export default async (req: Request) => { location, username, created_at - `, - ) - .order("full_name", { ascending: true }); + `) + .order("full_name", { ascending: true }) + .range(offset, offset + limit - 1); + const elapsed = Date.now() - start; + console.log(`[staff/directory] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`); if (error) { console.error("Directory fetch error:", error); diff --git a/api/staff/invoices.ts b/api/staff/invoices.ts index bf35ef9a..fd91339c 100644 --- a/api/staff/invoices.ts +++ b/api/staff/invoices.ts @@ -16,10 +16,15 @@ export default async (req: Request) => { return new Response("Unauthorized", { status: 401 }); } + // Add a limit to prevent timeouts + const url = new URL(req.url); + const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50"))); + const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0")); + + const start = Date.now(); const { data: invoices, error } = await supabase .from("contractor_invoices") - .select( - ` + .select(` id, user_id, invoice_number, @@ -29,10 +34,12 @@ export default async (req: Request) => { due_date, description, created_at - `, - ) + `) .eq("user_id", userData.user.id) - .order("date", { ascending: false }); + .order("date", { ascending: false }) + .range(offset, offset + limit - 1); + const elapsed = Date.now() - start; + console.log(`[staff/invoices] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`); if (error) { console.error("Invoices fetch error:", error); diff --git a/api/staff/me.ts b/api/staff/me.ts index 0a3c8a86..efea4982 100644 --- a/api/staff/me.ts +++ b/api/staff/me.ts @@ -16,10 +16,10 @@ export default async (req: Request) => { return new Response("Unauthorized", { status: 401 }); } + const start = Date.now(); const { data: staffMember, error } = await supabase .from("staff_members") - .select( - ` + .select(` id, user_id, full_name, @@ -31,10 +31,11 @@ export default async (req: Request) => { salary, avatar_url, created_at - `, - ) + `) .eq("user_id", userData.user.id) .single(); + const elapsed = Date.now() - start; + console.log(`[staff/me] Query took ${elapsed}ms`); if (error && error.code !== "PGRST116") { console.error("Staff member fetch error:", error); diff --git a/api/staff/okrs.ts b/api/staff/okrs.ts index deee58b0..c4f6e3ce 100644 --- a/api/staff/okrs.ts +++ b/api/staff/okrs.ts @@ -16,10 +16,15 @@ export default async (req: Request) => { return new Response("Unauthorized", { status: 401 }); } + // Add a limit to prevent timeouts + const url = new URL(req.url); + const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50"))); + const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0")); + + const start = Date.now(); const { data: okrs, error } = await supabase .from("staff_okrs") - .select( - ` + .select(` id, user_id, objective, @@ -34,10 +39,12 @@ export default async (req: Request) => { target_value ), created_at - `, - ) + `) .eq("user_id", userData.user.id) - .order("created_at", { ascending: false }); + .order("created_at", { ascending: false }) + .range(offset, offset + limit - 1); + const elapsed = Date.now() - start; + console.log(`[staff/okrs] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`); if (error) { console.error("OKRs fetch error:", error); diff --git a/supabase-migration.sql b/supabase-migration.sql index e653ebe7..b3d594db 100644 --- a/supabase-migration.sql +++ b/supabase-migration.sql @@ -109,14 +109,14 @@ CREATE TABLE notifications ( created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); --- Insert default achievements -INSERT INTO achievements (name, description, icon, xp_reward, badge_color) VALUES -('Welcome to AeThex', 'Complete your profile setup', '🎉', 100, '#10B981'), -('First Project', 'Create your first project', '🚀', 150, '#3B82F6'), -('Community Contributor', 'Make your first community post', '💬', 75, '#8B5CF6'), -('Level Up', 'Reach level 5', '⭐', 200, '#F59E0B'), -('Experienced Developer', 'Complete 5 projects', '👨‍💻', 300, '#EF4444'), -('Community Leader', 'Get 100 likes on your posts', '👑', 500, '#F97316'); + +-- Insert core achievements with deterministic UUIDs to match activate.ts +INSERT INTO achievements (id, name, description, icon, xp_reward, badge_color) VALUES + ('b6e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Welcome to AeThex', 'Completed onboarding and joined the AeThex network.', '🎉', 250, '#7C3AED'), + ('c1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'AeThex Explorer', 'Engaged with community initiatives and posted first update.', '🧭', 400, '#0EA5E9'), + ('d1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Community Champion', 'Contributed feedback, resolved bugs, and mentored squads.', '🏆', 750, '#22C55E'), + ('e1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Workshop Architect', 'Published a high-impact mod or toolkit adopted by teams.', '🛠️', 1200, '#F97316'), + ('f1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'GOD Mode', 'Legendary status awarded by AeThex studio leadership.', '⚡', 5000, '#FACC15'); -- Enable Row Level Security (RLS) ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY; diff --git a/supabase/.temp/cli-latest b/supabase/.temp/cli-latest index 8c68db77..9b07af9e 100644 --- a/supabase/.temp/cli-latest +++ b/supabase/.temp/cli-latest @@ -1 +1 @@ -v2.67.1 \ No newline at end of file +v2.72.7 \ No newline at end of file diff --git a/supabase/migrations/20241212_add_tier_badges.sql b/supabase/migrations/20241212_add_tier_badges.sql index 499a900d..41098fa7 100644 --- a/supabase/migrations/20241212_add_tier_badges.sql +++ b/supabase/migrations/20241212_add_tier_badges.sql @@ -47,19 +47,14 @@ CREATE INDEX IF NOT EXISTS idx_user_profiles_stripe_customer ON user_profiles(st ALTER TABLE badges ENABLE ROW LEVEL SECURITY; ALTER TABLE user_badges ENABLE ROW LEVEL SECURITY; --- 7. RLS Policies for badges (read-only for authenticated users) -CREATE POLICY IF NOT EXISTS "Badges are viewable by everyone" -ON badges FOR SELECT -USING (true); +DROP POLICY IF EXISTS "Badges are viewable by everyone" ON badges; +CREATE POLICY "Badges are viewable by everyone" ON badges FOR SELECT USING (true); --- 8. RLS Policies for user_badges -CREATE POLICY IF NOT EXISTS "Users can view their own badges" -ON user_badges FOR SELECT -USING (auth.uid() = user_id); +DROP POLICY IF EXISTS "Users can view their own badges" ON user_badges; +CREATE POLICY "Users can view their own badges" ON user_badges FOR SELECT USING (auth.uid() = user_id); -CREATE POLICY IF NOT EXISTS "Users can view others badges" -ON user_badges FOR SELECT -USING (true); +DROP POLICY IF EXISTS "Users can view others badges" ON user_badges; +CREATE POLICY "Users can view others badges" ON user_badges FOR SELECT USING (true); -- 9. Seed initial badges that unlock AI personas INSERT INTO badges (name, slug, description, icon, unlock_criteria, unlocks_persona) VALUES diff --git a/supabase/migrations/20250107_add_discord_integration.sql b/supabase/migrations/20250107_add_discord_integration.sql index 4990792f..6783ec13 100644 --- a/supabase/migrations/20250107_add_discord_integration.sql +++ b/supabase/migrations/20250107_add_discord_integration.sql @@ -36,6 +36,7 @@ CREATE INDEX IF NOT EXISTS idx_discord_linking_sessions_token ON discord_linking CREATE INDEX IF NOT EXISTS idx_discord_linking_sessions_expires ON discord_linking_sessions(expires_at); ALTER TABLE discord_linking_sessions ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS "discord_linking_sessions_service_role" ON discord_linking_sessions; CREATE POLICY "discord_linking_sessions_service_role" ON discord_linking_sessions FOR ALL TO service_role USING (true); @@ -73,35 +74,42 @@ CREATE INDEX IF NOT EXISTS idx_discord_user_roles_server ON discord_user_roles(s -- RLS Policies ALTER TABLE discord_links ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS "discord_links_users_select" ON discord_links; CREATE POLICY "discord_links_users_select" ON discord_links FOR SELECT TO authenticated USING (user_id = auth.uid()); +DROP POLICY IF EXISTS "discord_links_service_role" ON discord_links; CREATE POLICY "discord_links_service_role" ON discord_links FOR ALL TO service_role USING (true); ALTER TABLE discord_verifications ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS "discord_verifications_service_role" ON discord_verifications; CREATE POLICY "discord_verifications_service_role" ON discord_verifications FOR ALL TO service_role USING (true); ALTER TABLE discord_role_mappings ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS "discord_role_mappings_public_read" ON discord_role_mappings; CREATE POLICY "discord_role_mappings_public_read" ON discord_role_mappings FOR SELECT USING (true); +DROP POLICY IF EXISTS "discord_role_mappings_admin_write" ON discord_role_mappings; CREATE POLICY "discord_role_mappings_admin_write" ON discord_role_mappings FOR INSERT TO service_role WITH CHECK (true); +DROP POLICY IF EXISTS "discord_role_mappings_admin_update" ON discord_role_mappings; CREATE POLICY "discord_role_mappings_admin_update" ON discord_role_mappings FOR UPDATE TO service_role USING (true); ALTER TABLE discord_user_roles ENABLE ROW LEVEL SECURITY; +DROP POLICY IF EXISTS "discord_user_roles_service_role" ON discord_user_roles; CREATE POLICY "discord_user_roles_service_role" ON discord_user_roles FOR ALL TO service_role USING (true); diff --git a/supabase/migrations/20250107_add_web3_and_games.sql b/supabase/migrations/20250107_add_web3_and_games.sql index f1e776e2..f978e5cf 100644 --- a/supabase/migrations/20250107_add_web3_and_games.sql +++ b/supabase/migrations/20250107_add_web3_and_games.sql @@ -94,28 +94,32 @@ ALTER TABLE game_sessions ENABLE ROW LEVEL SECURITY; ALTER TABLE roblox_links ENABLE ROW LEVEL SECURITY; ALTER TABLE web3_wallets ENABLE ROW LEVEL SECURITY; --- Public tables for game auth (service role only for inserts) +DROP POLICY IF EXISTS "game_auth_tokens_service_insert" ON game_auth_tokens; CREATE POLICY "game_auth_tokens_service_insert" ON game_auth_tokens FOR INSERT TO anon, authenticated WITH CHECK (false); +DROP POLICY IF EXISTS "game_sessions_service_insert" ON game_sessions; CREATE POLICY "game_sessions_service_insert" ON game_sessions FOR INSERT TO anon, authenticated WITH CHECK (false); --- Allow authenticated users to view their own game data +DROP POLICY IF EXISTS "game_auth_tokens_user_select" ON game_auth_tokens; CREATE POLICY "game_auth_tokens_user_select" ON game_auth_tokens FOR SELECT TO authenticated USING (user_id = auth.uid()); +DROP POLICY IF EXISTS "game_sessions_user_select" ON game_sessions; CREATE POLICY "game_sessions_user_select" ON game_sessions FOR SELECT TO authenticated USING (user_id = auth.uid()); +DROP POLICY IF EXISTS "roblox_links_user_select" ON roblox_links; CREATE POLICY "roblox_links_user_select" ON roblox_links FOR SELECT TO authenticated USING (user_id = auth.uid()); +DROP POLICY IF EXISTS "web3_wallets_user_select" ON web3_wallets; CREATE POLICY "web3_wallets_user_select" ON web3_wallets FOR SELECT TO authenticated USING (user_id = auth.uid()); diff --git a/supabase/migrations/20250115_add_fourthwall_integration.sql b/supabase/migrations/20250115_add_fourthwall_integration.sql index f151fd16..af29cc46 100644 --- a/supabase/migrations/20250115_add_fourthwall_integration.sql +++ b/supabase/migrations/20250115_add_fourthwall_integration.sql @@ -48,22 +48,25 @@ ALTER TABLE fourthwall_products ENABLE ROW LEVEL SECURITY; ALTER TABLE fourthwall_orders ENABLE ROW LEVEL SECURITY; ALTER TABLE fourthwall_webhook_logs ENABLE ROW LEVEL SECURITY; --- Create RLS policies - allow authenticated users to read, admins to manage +DROP POLICY IF EXISTS "Allow authenticated users to read fourthwall products" ON fourthwall_products; CREATE POLICY "Allow authenticated users to read fourthwall products" ON fourthwall_products FOR SELECT USING (true); +DROP POLICY IF EXISTS "Allow service role to manage fourthwall products" ON fourthwall_products; CREATE POLICY "Allow service role to manage fourthwall products" ON fourthwall_products FOR ALL USING (auth.role() = 'service_role'); +DROP POLICY IF EXISTS "Allow service role to manage fourthwall orders" ON fourthwall_orders; CREATE POLICY "Allow service role to manage fourthwall orders" ON fourthwall_orders FOR ALL USING (auth.role() = 'service_role'); +DROP POLICY IF EXISTS "Allow service role to manage webhook logs" ON fourthwall_webhook_logs; CREATE POLICY "Allow service role to manage webhook logs" ON fourthwall_webhook_logs FOR ALL diff --git a/supabase/migrations/20250115_oauth_federation.sql b/supabase/migrations/20250115_oauth_federation.sql index 41596830..ea3bb7ae 100644 --- a/supabase/migrations/20250115_oauth_federation.sql +++ b/supabase/migrations/20250115_oauth_federation.sql @@ -44,27 +44,27 @@ GRANT SELECT, INSERT, UPDATE, DELETE ON public.provider_identities TO service_ro -- Enable RLS ALTER TABLE public.provider_identities ENABLE ROW LEVEL SECURITY; --- Users can only see their own provider identities +DROP POLICY IF EXISTS "Users can view own provider identities" ON public.provider_identities; CREATE POLICY "Users can view own provider identities" ON public.provider_identities FOR SELECT USING (auth.uid() = user_id); --- Users can only insert their own provider identities +DROP POLICY IF EXISTS "Users can insert own provider identities" ON public.provider_identities; CREATE POLICY "Users can insert own provider identities" ON public.provider_identities FOR INSERT WITH CHECK (auth.uid() = user_id); --- Users can only update their own provider identities +DROP POLICY IF EXISTS "Users can update own provider identities" ON public.provider_identities; CREATE POLICY "Users can update own provider identities" ON public.provider_identities FOR UPDATE USING (auth.uid() = user_id); --- Users can only delete their own provider identities +DROP POLICY IF EXISTS "Users can delete own provider identities" ON public.provider_identities; CREATE POLICY "Users can delete own provider identities" ON public.provider_identities FOR DELETE USING (auth.uid() = user_id); --- Service role can do anything for OAuth flows +DROP POLICY IF EXISTS "Service role can manage all provider identities" ON public.provider_identities; CREATE POLICY "Service role can manage all provider identities" ON public.provider_identities FOR ALL diff --git a/supabase/migrations/20250120_add_collaboration_posts.sql b/supabase/migrations/20250120_add_collaboration_posts.sql index 27647d02..fa05659e 100644 --- a/supabase/migrations/20250120_add_collaboration_posts.sql +++ b/supabase/migrations/20250120_add_collaboration_posts.sql @@ -47,17 +47,19 @@ ALTER TABLE public.collaboration_posts_authors ENABLE ROW LEVEL SECURITY; ALTER TABLE public.collaboration_post_likes ENABLE ROW LEVEL SECURITY; ALTER TABLE public.collaboration_comments ENABLE ROW LEVEL SECURITY; --- Policies for collaboration_posts +DROP POLICY IF EXISTS "collaboration_posts_read" ON public.collaboration_posts; CREATE POLICY "collaboration_posts_read" ON public.collaboration_posts FOR SELECT TO authenticated USING (is_published = true); +DROP POLICY IF EXISTS "collaboration_posts_manage_own" ON public.collaboration_posts; CREATE POLICY "collaboration_posts_manage_own" ON public.collaboration_posts FOR ALL TO authenticated USING (created_by = auth.uid()) WITH CHECK (created_by = auth.uid()); --- Policies for collaboration_posts_authors +DROP POLICY IF EXISTS "collaboration_posts_authors_read" ON public.collaboration_posts_authors; CREATE POLICY "collaboration_posts_authors_read" ON public.collaboration_posts_authors FOR SELECT TO authenticated USING (true); +DROP POLICY IF EXISTS "collaboration_posts_authors_manage" ON public.collaboration_posts_authors; CREATE POLICY "collaboration_posts_authors_manage" ON public.collaboration_posts_authors FOR ALL TO authenticated USING ( @@ -73,17 +75,19 @@ CREATE POLICY "collaboration_posts_authors_manage" ON public.collaboration_posts ) ); --- Policies for collaboration_post_likes +DROP POLICY IF EXISTS "collaboration_post_likes_read" ON public.collaboration_post_likes; CREATE POLICY "collaboration_post_likes_read" ON public.collaboration_post_likes FOR SELECT TO authenticated USING (true); +DROP POLICY IF EXISTS "collaboration_post_likes_manage_self" ON public.collaboration_post_likes; CREATE POLICY "collaboration_post_likes_manage_self" ON public.collaboration_post_likes FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid()); --- Policies for collaboration_comments +DROP POLICY IF EXISTS "collaboration_comments_read" ON public.collaboration_comments; CREATE POLICY "collaboration_comments_read" ON public.collaboration_comments FOR SELECT TO authenticated USING (true); +DROP POLICY IF EXISTS "collaboration_comments_manage_self" ON public.collaboration_comments; CREATE POLICY "collaboration_comments_manage_self" ON public.collaboration_comments FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid()); diff --git a/supabase/migrations/20250121_add_feed_arm_affiliation.sql b/supabase/migrations/20250121_add_feed_arm_affiliation.sql index fb962ff1..01402e3c 100644 --- a/supabase/migrations/20250121_add_feed_arm_affiliation.sql +++ b/supabase/migrations/20250121_add_feed_arm_affiliation.sql @@ -23,11 +23,11 @@ CREATE INDEX IF NOT EXISTS idx_user_followed_arms_arm_id ON public.user_followed -- Enable RLS on user_followed_arms ALTER TABLE public.user_followed_arms ENABLE ROW LEVEL SECURITY; --- Policy: Users can read all followed arms data +DROP POLICY IF EXISTS "user_followed_arms_read" ON public.user_followed_arms; CREATE POLICY "user_followed_arms_read" ON public.user_followed_arms FOR SELECT TO authenticated USING (true); --- Policy: Users can manage their own followed arms +DROP POLICY IF EXISTS "user_followed_arms_manage_self" ON public.user_followed_arms; CREATE POLICY "user_followed_arms_manage_self" ON public.user_followed_arms FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid()); diff --git a/supabase/migrations/20250121_add_staff_management.sql b/supabase/migrations/20250121_add_staff_management.sql index d1d633ad..d6a5eaff 100644 --- a/supabase/migrations/20250121_add_staff_management.sql +++ b/supabase/migrations/20250121_add_staff_management.sql @@ -54,18 +54,18 @@ ALTER TABLE staff_contractors ENABLE ROW LEVEL SECURITY; -- Staff members policies --- Allow authenticated users to read all staff members (directory) +DROP POLICY IF EXISTS "staff_members_select_authenticated" ON staff_members; CREATE POLICY "staff_members_select_authenticated" ON staff_members FOR SELECT USING (auth.role() = 'authenticated'); --- Allow staff members to update their own record +DROP POLICY IF EXISTS "staff_members_update_own" ON staff_members; CREATE POLICY "staff_members_update_own" ON staff_members FOR UPDATE USING (auth.uid() = user_id OR auth.role() = 'service_role') WITH CHECK (auth.uid() = user_id OR auth.role() = 'service_role'); --- Allow admins to do anything +DROP POLICY IF EXISTS "staff_members_admin_all" ON staff_members; CREATE POLICY "staff_members_admin_all" ON staff_members FOR ALL USING ( @@ -79,18 +79,18 @@ CREATE POLICY "staff_members_admin_all" ON staff_members -- Staff contractors policies --- Allow authenticated users to read all contractors (directory) +DROP POLICY IF EXISTS "staff_contractors_select_authenticated" ON staff_contractors; CREATE POLICY "staff_contractors_select_authenticated" ON staff_contractors FOR SELECT USING (auth.role() = 'authenticated'); --- Allow contractors to update their own record +DROP POLICY IF EXISTS "staff_contractors_update_own" ON staff_contractors; CREATE POLICY "staff_contractors_update_own" ON staff_contractors FOR UPDATE USING (auth.uid() = user_id OR auth.role() = 'service_role') WITH CHECK (auth.uid() = user_id OR auth.role() = 'service_role'); --- Allow admins to do anything +DROP POLICY IF EXISTS "staff_contractors_admin_all" ON staff_contractors; CREATE POLICY "staff_contractors_admin_all" ON staff_contractors FOR ALL USING ( diff --git a/supabase/migrations/20250206_add_email_linking.sql b/supabase/migrations/20250206_add_email_linking.sql index ee8c7b82..44679e58 100644 --- a/supabase/migrations/20250206_add_email_linking.sql +++ b/supabase/migrations/20250206_add_email_linking.sql @@ -18,7 +18,7 @@ CREATE INDEX idx_user_email_links_primary ON user_email_links(user_id, is_primar -- Enable RLS ALTER TABLE user_email_links ENABLE ROW LEVEL SECURITY; --- RLS: Users can view their own linked emails +DROP POLICY IF EXISTS "Users can view own email links" ON user_email_links; CREATE POLICY "Users can view own email links" ON user_email_links FOR SELECT @@ -29,7 +29,7 @@ CREATE POLICY "Users can view own email links" ) ); --- RLS: Service role can do anything (for backend operations) +DROP POLICY IF EXISTS "Service role full access" ON user_email_links; CREATE POLICY "Service role full access" ON user_email_links FOR ALL diff --git a/supabase/migrations/20250206_add_ethos_guild.sql b/supabase/migrations/20250206_add_ethos_guild.sql index a425541c..729f4a5d 100644 --- a/supabase/migrations/20250206_add_ethos_guild.sql +++ b/supabase/migrations/20250206_add_ethos_guild.sql @@ -86,33 +86,45 @@ alter table public.ethos_artist_profiles enable row level security; alter table public.ethos_guild_members enable row level security; alter table public.ethos_licensing_agreements enable row level security; --- RLS Policies: ethos_tracks +drop policy if exists "Ethos tracks are readable by all authenticated users" on public.ethos_tracks; create policy "Ethos tracks are readable by all authenticated users" on public.ethos_tracks for select using (auth.role() = 'authenticated'); +create policy "Users can insert their own tracks" on public.ethos_tracks +drop policy if exists "Users can insert their own tracks" on public.ethos_tracks; create policy "Users can insert their own tracks" on public.ethos_tracks for insert with check (auth.uid() = user_id); +create policy "Users can update their own tracks" on public.ethos_tracks +drop policy if exists "Users can update their own tracks" on public.ethos_tracks; create policy "Users can update their own tracks" on public.ethos_tracks for update using (auth.uid() = user_id); +create policy "Users can delete their own tracks" on public.ethos_tracks +drop policy if exists "Users can delete their own tracks" on public.ethos_tracks; create policy "Users can delete their own tracks" on public.ethos_tracks for delete using (auth.uid() = user_id); --- RLS Policies: ethos_artist_profiles +drop policy if exists "Ethos artist profiles are readable by all authenticated users" on public.ethos_artist_profiles; create policy "Ethos artist profiles are readable by all authenticated users" on public.ethos_artist_profiles for select using (auth.role() = 'authenticated'); +create policy "Users can insert their own artist profile" on public.ethos_artist_profiles +drop policy if exists "Users can insert their own artist profile" on public.ethos_artist_profiles; create policy "Users can insert their own artist profile" on public.ethos_artist_profiles for insert with check (auth.uid() = user_id); +create policy "Users can update their own artist profile" on public.ethos_artist_profiles +drop policy if exists "Users can update their own artist profile" on public.ethos_artist_profiles; create policy "Users can update their own artist profile" on public.ethos_artist_profiles for update using (auth.uid() = user_id); --- RLS Policies: ethos_guild_members +drop policy if exists "Guild membership is readable by all authenticated users" on public.ethos_guild_members; create policy "Guild membership is readable by all authenticated users" on public.ethos_guild_members for select using (auth.role() = 'authenticated'); +create policy "Admins can manage guild members" on public.ethos_guild_members +drop policy if exists "Admins can manage guild members" on public.ethos_guild_members; create policy "Admins can manage guild members" on public.ethos_guild_members for all using ( exists( @@ -121,10 +133,12 @@ create policy "Admins can manage guild members" on public.ethos_guild_members ) ); +create policy "Users can see their own membership" on public.ethos_guild_members +drop policy if exists "Users can see their own membership" on public.ethos_guild_members; create policy "Users can see their own membership" on public.ethos_guild_members for select using (auth.uid() = user_id or auth.role() = 'authenticated'); --- RLS Policies: ethos_licensing_agreements +drop policy if exists "Licensing agreements readable by involved parties" on public.ethos_licensing_agreements; create policy "Licensing agreements readable by involved parties" on public.ethos_licensing_agreements for select using ( auth.uid() in ( diff --git a/supabase/migrations/20250210_add_ethos_artist_verification.sql b/supabase/migrations/20250210_add_ethos_artist_verification.sql index 078c326b..dc57408c 100644 --- a/supabase/migrations/20250210_add_ethos_artist_verification.sql +++ b/supabase/migrations/20250210_add_ethos_artist_verification.sql @@ -43,9 +43,13 @@ alter table public.ethos_verification_requests enable row level security; alter table public.ethos_verification_audit_log enable row level security; -- RLS Policies: ethos_verification_requests +create policy "Artists can view their own verification request" on public.ethos_verification_requests +drop policy if exists "Artists can view their own verification request" on public.ethos_verification_requests; create policy "Artists can view their own verification request" on public.ethos_verification_requests for select using (auth.uid() = user_id); +create policy "Admins can view all verification requests" on public.ethos_verification_requests +drop policy if exists "Admins can view all verification requests" on public.ethos_verification_requests; create policy "Admins can view all verification requests" on public.ethos_verification_requests for select using ( exists( @@ -54,9 +58,13 @@ create policy "Admins can view all verification requests" on public.ethos_verifi ) ); +create policy "Artists can submit verification request" on public.ethos_verification_requests +drop policy if exists "Artists can submit verification request" on public.ethos_verification_requests; create policy "Artists can submit verification request" on public.ethos_verification_requests for insert with check (auth.uid() = user_id); +create policy "Admins can update verification status" on public.ethos_verification_requests +drop policy if exists "Admins can update verification status" on public.ethos_verification_requests; create policy "Admins can update verification status" on public.ethos_verification_requests for update using ( exists( @@ -66,6 +74,8 @@ create policy "Admins can update verification status" on public.ethos_verificati ); -- RLS Policies: ethos_verification_audit_log +create policy "Admins can view audit log" on public.ethos_verification_audit_log +drop policy if exists "Admins can view audit log" on public.ethos_verification_audit_log; create policy "Admins can view audit log" on public.ethos_verification_audit_log for select using ( exists( @@ -74,6 +84,8 @@ create policy "Admins can view audit log" on public.ethos_verification_audit_log ) ); +create policy "System can write audit logs" on public.ethos_verification_audit_log +drop policy if exists "System can write audit logs" on public.ethos_verification_audit_log; create policy "System can write audit logs" on public.ethos_verification_audit_log for insert with check (true); diff --git a/supabase/migrations/20250211_add_ethos_artist_services.sql b/supabase/migrations/20250211_add_ethos_artist_services.sql index d49a0361..e7290eda 100644 --- a/supabase/migrations/20250211_add_ethos_artist_services.sql +++ b/supabase/migrations/20250211_add_ethos_artist_services.sql @@ -44,9 +44,13 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_ethos_ecosystem_licenses_unique ON public. ALTER TABLE public.ethos_ecosystem_licenses ENABLE ROW LEVEL SECURITY; -- RLS Policies: ethos_ecosystem_licenses +CREATE POLICY "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses +DROP POLICY IF EXISTS "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses; CREATE POLICY "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses FOR SELECT USING (auth.uid() = artist_id); +CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses +DROP POLICY IF EXISTS "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses; CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses FOR SELECT USING ( EXISTS( @@ -55,6 +59,8 @@ CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem ) ); +CREATE POLICY "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses +DROP POLICY IF EXISTS "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses; CREATE POLICY "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses FOR INSERT WITH CHECK (auth.uid() = artist_id); diff --git a/supabase/migrations/20250214_add_foundation_system.sql b/supabase/migrations/20250214_add_foundation_system.sql index 6ed5cd07..68dea168 100644 --- a/supabase/migrations/20250214_add_foundation_system.sql +++ b/supabase/migrations/20250214_add_foundation_system.sql @@ -211,13 +211,19 @@ alter table public.foundation_mentorship_sessions enable row level security; alter table public.foundation_contributions enable row level security; -- Courses: Published courses readable by all, all ops by instructor/admin +create policy "Published courses readable by all" on public.foundation_courses +drop policy if exists "Published courses readable by all" on public.foundation_courses; create policy "Published courses readable by all" on public.foundation_courses for select using (is_published = true or auth.uid() = instructor_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')); +create policy "Instructors manage own courses" on public.foundation_courses +drop policy if exists "Instructors manage own courses" on public.foundation_courses; create policy "Instructors manage own courses" on public.foundation_courses for all using (auth.uid() = instructor_id) with check (auth.uid() = instructor_id); -- Course modules: same as courses (published visible, instructor/admin manage) +create policy "Published modules readable by all" on public.foundation_course_modules +drop policy if exists "Published modules readable by all" on public.foundation_course_modules; create policy "Published modules readable by all" on public.foundation_course_modules for select using ( is_published = true or @@ -225,10 +231,14 @@ create policy "Published modules readable by all" on public.foundation_course_mo exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin') ); +create policy "Instructors manage course modules" on public.foundation_course_modules +drop policy if exists "Instructors manage course modules" on public.foundation_course_modules; create policy "Instructors manage course modules" on public.foundation_course_modules for all using (exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid())); -- Lessons: same pattern +create policy "Published lessons readable by all" on public.foundation_course_lessons +drop policy if exists "Published lessons readable by all" on public.foundation_course_lessons; create policy "Published lessons readable by all" on public.foundation_course_lessons for select using ( is_published = true or @@ -236,69 +246,107 @@ create policy "Published lessons readable by all" on public.foundation_course_le exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin') ); +create policy "Instructors manage course lessons" on public.foundation_course_lessons +drop policy if exists "Instructors manage course lessons" on public.foundation_course_lessons; create policy "Instructors manage course lessons" on public.foundation_course_lessons for all using (exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid())); -- Enrollments: users see own, instructors see their course enrollments +create policy "Users see own enrollments" on public.foundation_enrollments +drop policy if exists "Users see own enrollments" on public.foundation_enrollments; create policy "Users see own enrollments" on public.foundation_enrollments for select using (auth.uid() = user_id or exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid())); +create policy "Users manage own enrollments" on public.foundation_enrollments +drop policy if exists "Users manage own enrollments" on public.foundation_enrollments; create policy "Users manage own enrollments" on public.foundation_enrollments for insert with check (auth.uid() = user_id); +create policy "Users update own enrollments" on public.foundation_enrollments +drop policy if exists "Users update own enrollments" on public.foundation_enrollments; create policy "Users update own enrollments" on public.foundation_enrollments for update using (auth.uid() = user_id); -- Lesson progress: users see own +create policy "Users see own lesson progress" on public.foundation_lesson_progress +drop policy if exists "Users see own lesson progress" on public.foundation_lesson_progress; create policy "Users see own lesson progress" on public.foundation_lesson_progress for select using (auth.uid() = user_id); +create policy "Users update own lesson progress" on public.foundation_lesson_progress +drop policy if exists "Users update own lesson progress" on public.foundation_lesson_progress; create policy "Users update own lesson progress" on public.foundation_lesson_progress for insert with check (auth.uid() = user_id); +create policy "Users update own lesson completion" on public.foundation_lesson_progress +drop policy if exists "Users update own lesson completion" on public.foundation_lesson_progress; create policy "Users update own lesson completion" on public.foundation_lesson_progress for update using (auth.uid() = user_id); -- Achievements: all readable, admin/system manages +create policy "Achievements readable by all" on public.foundation_achievements +drop policy if exists "Achievements readable by all" on public.foundation_achievements; create policy "Achievements readable by all" on public.foundation_achievements for select using (true); -- User achievements: users see own, admin manages +create policy "Users see own achievements" on public.foundation_user_achievements +drop policy if exists "Users see own achievements" on public.foundation_user_achievements; create policy "Users see own achievements" on public.foundation_user_achievements for select using (auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')); -- Mentors: approved mentors visible, mentors manage own +create policy "Approved mentors visible to all" on public.foundation_mentors +drop policy if exists "Approved mentors visible to all" on public.foundation_mentors; create policy "Approved mentors visible to all" on public.foundation_mentors for select using (approval_status = 'approved' or auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')); +create policy "Users manage own mentor profile" on public.foundation_mentors +drop policy if exists "Users manage own mentor profile" on public.foundation_mentors; create policy "Users manage own mentor profile" on public.foundation_mentors for all using (auth.uid() = user_id) with check (auth.uid() = user_id); -- Mentorship requests: involved parties can see +create policy "Mentorship requests visible to involved" on public.foundation_mentorship_requests +drop policy if exists "Mentorship requests visible to involved" on public.foundation_mentorship_requests; create policy "Mentorship requests visible to involved" on public.foundation_mentorship_requests for select using (auth.uid() = mentor_id or auth.uid() = mentee_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')); +create policy "Mentees request mentorship" on public.foundation_mentorship_requests +drop policy if exists "Mentees request mentorship" on public.foundation_mentorship_requests; create policy "Mentees request mentorship" on public.foundation_mentorship_requests for insert with check (auth.uid() = mentee_id); +create policy "Mentors respond to requests" on public.foundation_mentorship_requests +drop policy if exists "Mentors respond to requests" on public.foundation_mentorship_requests; create policy "Mentors respond to requests" on public.foundation_mentorship_requests for update using (auth.uid() = mentor_id); -- Mentorship sessions: involved parties can see/manage +create policy "Sessions visible to involved" on public.foundation_mentorship_sessions +drop policy if exists "Sessions visible to involved" on public.foundation_mentorship_sessions; create policy "Sessions visible to involved" on public.foundation_mentorship_sessions for select using (auth.uid() = mentor_id or auth.uid() = mentee_id); +create policy "Mentorship sessions insert" on public.foundation_mentorship_sessions +drop policy if exists "Mentorship sessions insert" on public.foundation_mentorship_sessions; create policy "Mentorship sessions insert" on public.foundation_mentorship_sessions for insert with check (auth.uid() = mentor_id or auth.uid() = mentee_id); +create policy "Mentorship sessions update" on public.foundation_mentorship_sessions +drop policy if exists "Mentorship sessions update" on public.foundation_mentorship_sessions; create policy "Mentorship sessions update" on public.foundation_mentorship_sessions for update using (auth.uid() = mentor_id or auth.uid() = mentee_id); -- Contributions: users see own, admin sees all +create policy "Contributions visible to user and admin" on public.foundation_contributions +drop policy if exists "Contributions visible to user and admin" on public.foundation_contributions; create policy "Contributions visible to user and admin" on public.foundation_contributions for select using (auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')); +create policy "System logs contributions" on public.foundation_contributions +drop policy if exists "System logs contributions" on public.foundation_contributions; create policy "System logs contributions" on public.foundation_contributions for insert with check (true); diff --git a/supabase/migrations/20251018_storage_post_media_policies.sql b/supabase/migrations/20251018_storage_post_media_policies.sql index b5f7625b..63578813 100644 --- a/supabase/migrations/20251018_storage_post_media_policies.sql +++ b/supabase/migrations/20251018_storage_post_media_policies.sql @@ -6,14 +6,14 @@ alter table if exists storage.objects enable row level security; -- Allow public read for objects in post_media bucket (because bucket is public) DO $$ BEGIN - CREATE POLICY IF NOT EXISTS post_media_public_read ON storage.objects + CREATE POLICY post_media_public_read ON storage.objects FOR SELECT TO public USING (bucket_id = 'post_media'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; -- Allow authenticated users to upload to post_media bucket DO $$ BEGIN - CREATE POLICY IF NOT EXISTS post_media_auth_insert ON storage.objects + CREATE POLICY post_media_auth_insert ON storage.objects FOR INSERT TO authenticated WITH CHECK (bucket_id = 'post_media'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; diff --git a/supabase/migrations/20260107_developer_api_keys.sql b/supabase/migrations/20260107_developer_api_keys.sql index 54430441..6fcf11f8 100644 --- a/supabase/migrations/20260107_developer_api_keys.sql +++ b/supabase/migrations/20260107_developer_api_keys.sql @@ -158,15 +158,15 @@ ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY; ALTER TABLE api_usage_logs ENABLE ROW LEVEL SECURITY; ALTER TABLE developer_profiles ENABLE ROW LEVEL SECURITY; --- Users can only see their own API keys +DROP POLICY IF EXISTS api_keys_user_policy ON api_keys; CREATE POLICY api_keys_user_policy ON api_keys FOR ALL USING (auth.uid() = user_id); --- Users can only see their own usage logs +DROP POLICY IF EXISTS api_usage_logs_user_policy ON api_usage_logs; CREATE POLICY api_usage_logs_user_policy ON api_usage_logs FOR ALL USING (auth.uid() = user_id); --- Users can only see their own developer profile +DROP POLICY IF EXISTS developer_profiles_user_policy ON developer_profiles; CREATE POLICY developer_profiles_user_policy ON developer_profiles FOR ALL USING (auth.uid() = user_id);