Skip to content

Commit 09d7c77

Browse files
committed
fix: use two-query approach in getProjectCodevs to bypass RLS filtering
The PostgREST foreign key join to project_members was applying RLS on the codev table, silently dropping users. This caused only 4 mentors to show instead of all 10 in production. Fixed by fetching codevs and project_members separately, then merging client-side (same pattern as getProjectByID and getMembers).
1 parent c768747 commit 09d7c77

1 file changed

Lines changed: 60 additions & 34 deletions

File tree

‎apps/codebility/app/home/projects/actions.ts‎

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
*/
781787
export 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

844870
export const getProjectClients = async (): Promise<Client[]> => {

0 commit comments

Comments
 (0)