Add maintenance mode endpoint for Vercel deployments

Create `api/admin/platform/maintenance.ts` to handle maintenance mode logic as a Vercel serverless function, including GET and POST requests for enabling/disabling and admin verification via Supabase.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 9203795e-937a-4306-b81d-b4d5c78c240e
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: eb559abf-e967-427e-a938-a9f28fc6407c
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7c94b7a0-29c7-4f2e-94ef-44b2153872b7/9203795e-937a-4306-b81d-b4d5c78c240e/qPXTzuE
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
sirpiglr 2025-12-07 02:10:17 +00:00
parent ba650c5116
commit 688cfff89a

View file

@ -0,0 +1,106 @@
import type { VercelRequest, VercelResponse } from "@vercel/node";
import { createClient } from "@supabase/supabase-js";
const supabaseUrl = process.env.VITE_SUPABASE_URL || "";
const supabaseServiceRole = process.env.SUPABASE_SERVICE_ROLE || "";
let maintenanceModeCache: boolean | null = null;
const ADMIN_ROLES = ["admin", "super_admin", "staff", "owner"];
async function verifyAdmin(token: string): Promise<boolean> {
if (!supabaseUrl || !supabaseServiceRole) return false;
const supabase = createClient(supabaseUrl, supabaseServiceRole);
try {
const { data: { user }, error } = await supabase.auth.getUser(token);
if (error || !user) return false;
const { data: roles } = await supabase
.from("user_roles")
.select("role")
.eq("user_id", user.id);
if (!roles) return false;
return roles.some(r => ADMIN_ROLES.includes(r.role?.toLowerCase()));
} catch {
return false;
}
}
export default async function handler(req: VercelRequest, res: VercelResponse) {
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
const supabase = supabaseUrl && supabaseServiceRole
? createClient(supabaseUrl, supabaseServiceRole)
: null;
if (req.method === "GET") {
try {
if (supabase) {
const { data, error } = await supabase
.from("platform_settings")
.select("value")
.eq("key", "maintenance_mode")
.single();
if (!error && data) {
const isEnabled = data.value === true || data.value === "true";
maintenanceModeCache = isEnabled;
return res.json({ maintenance_mode: isEnabled });
}
}
const envMaintenance = process.env.MAINTENANCE_MODE === "true";
return res.json({ maintenance_mode: maintenanceModeCache ?? envMaintenance });
} catch (e) {
const envMaintenance = process.env.MAINTENANCE_MODE === "true";
return res.json({ maintenance_mode: maintenanceModeCache ?? envMaintenance });
}
}
if (req.method === "POST") {
const authHeader = req.headers.authorization;
const token = authHeader?.replace("Bearer ", "");
if (!token) {
return res.status(401).json({ error: "Unauthorized" });
}
const isAdmin = await verifyAdmin(token);
if (!isAdmin) {
return res.status(403).json({ error: "Forbidden - Admin access required" });
}
const { maintenance_mode } = req.body;
if (typeof maintenance_mode !== "boolean") {
return res.status(400).json({ error: "maintenance_mode must be a boolean" });
}
try {
if (supabase) {
const { error } = await supabase
.from("platform_settings")
.upsert(
{ key: "maintenance_mode", value: maintenance_mode, updated_at: new Date().toISOString() },
{ onConflict: "key" }
);
if (error) {
console.error("[Maintenance] DB error:", error);
}
}
maintenanceModeCache = maintenance_mode;
return res.json({ maintenance_mode, success: true });
} catch (e) {
maintenanceModeCache = maintenance_mode;
return res.json({ maintenance_mode, success: true });
}
}
return res.status(405).json({ error: "Method not allowed" });
}