Create /api/gameforge/sprint endpoint

cgen-a9bf50fc08a54a73971f02028a847099
This commit is contained in:
Builder.io 2025-11-15 16:26:27 +00:00
parent 5aa9356e12
commit e9441535ae
13 changed files with 721 additions and 0 deletions

View file

@ -0,0 +1,50 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: opportunities, error } = await supabase
.from("devlink_opportunities")
.select(`
id,
title,
description,
budget,
type,
status,
skills_required,
created_at
`)
.eq("status", "open")
.eq("type", "roblox")
.order("created_at", { ascending: false });
if (error) {
console.error("Opportunities fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(opportunities || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

76
api/devlink/profile.ts Normal file
View file

@ -0,0 +1,76 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: profile, error } = await supabase
.from("devlink_profiles")
.select(`
id,
user_id,
username,
profile_views,
creations,
experiences,
certifications,
created_at,
updated_at
`)
.eq("user_id", userData.user.id)
.single();
if (error && error.code !== "PGRST116") {
console.error("Profile fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
if (!profile) {
// Create default profile if it doesn't exist
const { data: newProfile, error: createError } = await supabase
.from("devlink_profiles")
.insert([
{
user_id: userData.user.id,
username: userData.user.user_metadata?.username || userData.user.email?.split("@")[0],
profile_views: 0,
},
])
.select()
.single();
if (createError) {
console.error("Profile creation error:", createError);
return new Response(JSON.stringify({ error: createError.message }), {
status: 500,
});
}
return new Response(JSON.stringify(newProfile), {
headers: { "Content-Type": "application/json" },
});
}
return new Response(JSON.stringify(profile), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

53
api/devlink/teams.ts Normal file
View file

@ -0,0 +1,53 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: teams, error } = await supabase
.from("devlink_teams")
.select(`
id,
name,
description,
members_count,
created_at,
members:devlink_team_members(
id,
user_id,
role,
full_name,
avatar_url
)
`)
.contains("members", [{ user_id: userData.user.id }])
.order("created_at", { ascending: false });
if (error) {
console.error("Teams fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(teams || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

53
api/gameforge/sprint.ts Normal file
View file

@ -0,0 +1,53 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: sprint, error } = await supabase
.from("gameforge_sprints")
.select(`
id,
project_id,
title,
phase,
status,
start_date,
end_date,
deadline,
gdd,
scope
`)
.eq("user_id", userData.user.id)
.order("created_at", { ascending: false })
.limit(1)
.single();
if (error && error.code !== "PGRST116") {
console.error("Sprint fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(sprint || null), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

63
api/gameforge/tasks.ts Normal file
View file

@ -0,0 +1,63 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const url = new URL(req.url);
const sprintId = url.searchParams.get("sprint_id");
let query = supabase
.from("gameforge_tasks")
.select(`
id,
title,
description,
status,
assigned_to:assigned_to_id(
id,
full_name,
avatar_url
),
priority,
due_date,
created_at
`)
.eq("created_by_id", userData.user.id);
if (sprintId) {
query = query.eq("sprint_id", sprintId);
}
const { data: tasks, error } = await query.order("created_at", {
ascending: false,
});
if (error) {
console.error("Tasks fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(tasks || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

49
api/labs/bounties.ts Normal file
View file

@ -0,0 +1,49 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: bounties, error } = await supabase
.from("labs_bounties")
.select(`
id,
title,
description,
reward,
difficulty,
status,
research_track_id,
created_at
`)
.eq("status", "available")
.order("reward", { ascending: false });
if (error) {
console.error("Bounties fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(bounties || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

66
api/labs/ip-portfolio.ts Normal file
View file

@ -0,0 +1,66 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
// Check if user is admin in labs
const { data: labsAdmin, error: adminError } = await supabase
.from("labs_admin")
.select("id")
.eq("user_id", userData.user.id)
.single();
if (adminError && adminError.code !== "PGRST116") {
console.error("Admin check error:", adminError);
}
const isAdmin = !!labsAdmin;
// Fetch IP portfolio (all projects' IP counts)
const { data: portfolio, error } = await supabase
.from("labs_ip_portfolio")
.select(`
id,
patents_count,
trademarks_count,
trade_secrets_count,
copyrights_count,
created_at,
updated_at
`)
.single();
if (error && error.code !== "PGRST116") {
console.error("IP portfolio fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
const result = {
...portfolio,
is_admin: isAdmin,
};
return new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

48
api/labs/publications.ts Normal file
View file

@ -0,0 +1,48 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: publications, error } = await supabase
.from("labs_publications")
.select(`
id,
title,
description,
status,
url,
published_date,
research_track_id,
created_at
`)
.order("published_date", { ascending: false });
if (error) {
console.error("Publications fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(publications || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

View file

@ -0,0 +1,54 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: tracks, error } = await supabase
.from("labs_research_tracks")
.select(`
id,
title,
description,
status,
progress,
lead_id,
lead:lead_id(
id,
full_name,
avatar_url
),
publications,
whitepaper_url,
created_at
`)
.order("created_at", { ascending: false });
if (error) {
console.error("Research tracks fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(tracks || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

52
api/staff/directory.ts Normal file
View file

@ -0,0 +1,52 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: directory, error } = await supabase
.from("staff_members")
.select(`
id,
user_id,
full_name,
email,
role,
department,
employment_type,
avatar_url,
phone,
location,
username,
created_at
`)
.order("full_name", { ascending: true });
if (error) {
console.error("Directory fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(directory || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

50
api/staff/invoices.ts Normal file
View file

@ -0,0 +1,50 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: invoices, error } = await supabase
.from("contractor_invoices")
.select(`
id,
user_id,
invoice_number,
amount,
status,
date,
due_date,
description,
created_at
`)
.eq("user_id", userData.user.id)
.order("date", { ascending: false });
if (error) {
console.error("Invoices fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(invoices || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

52
api/staff/me.ts Normal file
View file

@ -0,0 +1,52 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: staffMember, error } = await supabase
.from("staff_members")
.select(`
id,
user_id,
full_name,
email,
employment_type,
department,
role,
start_date,
salary,
avatar_url,
created_at
`)
.eq("user_id", userData.user.id)
.single();
if (error && error.code !== "PGRST116") {
console.error("Staff member fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(staffMember || null), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};

55
api/staff/okrs.ts Normal file
View file

@ -0,0 +1,55 @@
import { supabase } from "../_supabase";
export default async (req: Request) => {
if (req.method !== "GET") {
return new Response("Method not allowed", { status: 405 });
}
try {
const token = req.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return new Response("Unauthorized", { status: 401 });
}
const { data: userData } = await supabase.auth.getUser(token);
if (!userData.user) {
return new Response("Unauthorized", { status: 401 });
}
const { data: okrs, error } = await supabase
.from("staff_okrs")
.select(`
id,
user_id,
objective,
description,
status,
quarter,
year,
key_results(
id,
title,
progress,
target_value
),
created_at
`)
.eq("user_id", userData.user.id)
.order("created_at", { ascending: false });
if (error) {
console.error("OKRs fetch error:", error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
});
}
return new Response(JSON.stringify(okrs || []), {
headers: { "Content-Type": "application/json" },
});
} catch (err: any) {
return new Response(JSON.stringify({ error: err.message }), {
status: 500,
});
}
};