@@ -778,9 +778,16 @@ export const updateProjectMembers = async (
778778 }
779779} ;
780780
781+ /**
782+ * ─── PATCH: Fix RLS filtering issue ──────────────────────────────────────────
783+ * Use two-query approach to avoid PostgREST join RLS filtering that silently
784+ * drops users. Same pattern as getProjectByID() and getMembers().
785+ * ─────────────────────────────────────────────────────────────────────────────
786+ */
781787export const getProjectCodevs = async ( filters = { } ) : Promise < Codev [ ] > => {
782788 const supabase = await createClientServerComponent ( ) ;
783789
790+ // Step 1: Fetch codev records WITHOUT project_members join to avoid RLS filtering
784791 let query = supabase . from ( "codev" ) . select ( `
785792 id,
786793 first_name,
@@ -790,15 +797,7 @@ export const getProjectCodevs = async (filters = {}): Promise<Codev[]> => {
790797 positions,
791798 tech_stacks,
792799 display_position,
793- internal_status,
794- project_members!codev_id (
795- project:project_id (
796- id,
797- name
798- ),
799- role,
800- joined_at
801- )
800+ internal_status
802801 ` ) ;
803802
804803 Object . entries ( filters ) . forEach ( ( [ key , value ] ) => {
@@ -807,38 +806,65 @@ export const getProjectCodevs = async (filters = {}): Promise<Codev[]> => {
807806 }
808807 } ) ;
809808
810- const { data, error } = await query ;
809+ const { data : codevs , error } = await query ;
811810
812811 if ( error ) {
813812 console . error ( "Error fetching Codevs:" , error ) ;
814813 throw new Error ( "Failed to fetch Codevs" ) ;
815814 }
816815
817- return (
818- data ?. map ( ( codev : any ) => {
819- const projects = ( codev . project_members || [ ] ) . map (
820- ( pm : DbProjectMember ) => {
821- const project : Project & { role : string ; joined_at : string } = {
822- id : pm . project . id ,
823- name : pm . project . name ,
824- role : pm . role ,
825- joined_at : pm . joined_at ,
826- status : pm . project . status ,
827- kanban_display : pm . project . kanban_display ,
828- public_display : pm . project . public_display ,
829- } ;
830- return project ;
831- } ,
832- ) ;
816+ if ( ! codevs || codevs . length === 0 ) {
817+ return [ ] ;
818+ }
833819
834- return {
835- ...codev ,
836- positions : codev . positions || [ ] ,
837- tech_stacks : codev . tech_stacks || [ ] ,
838- projects,
839- } as Codev ;
840- } ) || [ ]
841- ) ;
820+ // Step 2: Fetch project_members separately for all codevs
821+ const codevIds = codevs . map ( c => c . id ) ;
822+
823+ const { data : projectMembers , error : pmError } = await supabase
824+ . from ( "project_members" )
825+ . select ( `
826+ codev_id,
827+ project_id,
828+ role,
829+ joined_at,
830+ project:project_id (
831+ id,
832+ name,
833+ status,
834+ kanban_display,
835+ public_display
836+ )
837+ ` )
838+ . in ( "codev_id" , codevIds ) ;
839+
840+ if ( pmError ) {
841+ console . error ( "Error fetching project members:" , pmError ) ;
842+ }
843+
844+ // Step 3: Merge project_members data back into codevs
845+ return codevs . map ( ( codev : any ) => {
846+ const codevProjectMembers = projectMembers ?. filter ( pm => pm . codev_id === codev . id ) || [ ] ;
847+
848+ const projects = codevProjectMembers . map ( ( pm : any ) => {
849+ const project : Project & { role : string ; joined_at : string } = {
850+ id : pm . project . id ,
851+ name : pm . project . name ,
852+ role : pm . role ,
853+ joined_at : pm . joined_at ,
854+ status : pm . project . status ,
855+ kanban_display : pm . project . kanban_display ,
856+ public_display : pm . project . public_display ,
857+ } ;
858+ return project ;
859+ } ) ;
860+
861+ return {
862+ ...codev ,
863+ positions : codev . positions || [ ] ,
864+ tech_stacks : codev . tech_stacks || [ ] ,
865+ projects,
866+ } as Codev ;
867+ } ) ;
842868} ;
843869
844870export const getProjectClients = async ( ) : Promise < Client [ ] > => {
0 commit comments