diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx
new file mode 100644
index 0000000..0370726
--- /dev/null
+++ b/app/admin/layout.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+
+// Force dynamic rendering for all admin routes to avoid build-time errors
+// when calling getServerSession() or other header-dependent functions.
+export const dynamic = 'force-dynamic'
+
+export default function AdminRootLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ return (
+
{/* Background Grid Pattern - Very Roblox Studio */}
{/* Top Warning Bar */}
@@ -44,22 +48,38 @@ export default function MaintenancePage() {
- Technical Stats
+ System Logs
-
- - Status: Repairing
- - Eta: 60-120 MIN
- - Build: v2.4.0
+
+ -
+ Status:
+ Maintenance Mode
+
+ -
+ Eta:
+ {config.estimatedDuration || 'TBD'}
+
+ -
+ Transmission from Admin:
+
+ {config.message}
+
+
{/* Action Box */}
)
-}
\ No newline at end of file
+}
diff --git a/lib/maintenance.ts b/lib/maintenance.ts
index f7e8af0..5f94118 100644
--- a/lib/maintenance.ts
+++ b/lib/maintenance.ts
@@ -1,16 +1,118 @@
+import { supabase } from '@/lib/supabase'
+import { promises as fs } from 'fs'
+import path from 'path'
+import os from 'os'
+
/**
* Utility functions for managing maintenance mode
*/
-export function isMaintenanceMode(): boolean {
- return process.env.MAINTENANCE_MODE === 'true'
+export interface MaintenanceConfig {
+ enabled: boolean
+ message: string
+ estimatedDuration: string
+ contactEmail: string
+}
+
+interface CachedConfig extends MaintenanceConfig {
+ lastUpdated: number
}
-export function getMaintenanceConfig() {
- return {
- enabled: isMaintenanceMode(),
- message: process.env.MAINTENANCE_MESSAGE || 'We are currently performing scheduled maintenance.',
- estimatedDuration: process.env.MAINTENANCE_DURATION || '1-2 hours',
- contactEmail: process.env.FROM_EMAIL || 'support@gitmesh.dev'
+const CACHE_FILE = path.join(os.tmpdir(), 'gitmesh_maintenance_cache.json')
+const CACHE_TTL = 5 * 60 * 1000 // 5 minutes
+
+/**
+ * Checks if the site should redirect to maintenance page.
+ * Uses a file-based cache to avoid hitting the DB on every request.
+ */
+export async function checkMaintenanceRedirection(): Promise
{
+ try {
+ // 1. Try to read from cache
+ const cacheData = await fs.readFile(CACHE_FILE, 'utf-8').catch(() => null)
+
+ if (cacheData) {
+ const cached: CachedConfig = JSON.parse(cacheData)
+ const now = Date.now()
+
+ // If cache is fresh (< 5 mins), use it
+ if (now - cached.lastUpdated < CACHE_TTL) {
+ return cached.enabled
+ }
+ }
+
+ // 2. Cache is missing or stale, fetch fresh data
+ const config = await getMaintenanceConfig()
+
+ // 3. Update cache
+ await updateMaintenanceCache(config)
+
+ return config.enabled
+
+ } catch (error) {
+ console.error('Error in checkMaintenanceRedirection:', error)
+ // Fail safe: If caching fails, check DB directly to be safe.
+ return isMaintenanceMode()
}
-}
\ No newline at end of file
+}
+
+/**
+ * Manually update the cache.
+ * Useful when admin updates settings to propagate changes immediately (to this instance).
+ */
+export async function updateMaintenanceCache(config: MaintenanceConfig): Promise {
+ try {
+ const newCache: CachedConfig = {
+ ...config,
+ lastUpdated: Date.now()
+ }
+ await fs.writeFile(CACHE_FILE, JSON.stringify(newCache))
+ } catch (error) {
+ console.error('Failed to update maintenance cache:', error)
+ }
+}
+
+/**
+ * Direct check for real-time status (Admin usage)
+ */
+export async function isMaintenanceMode(): Promise {
+ const config = await getMaintenanceConfig()
+ return config.enabled
+}
+
+/**
+ * Fetch configuration directly from Supabase (Real-time)
+ */
+export async function getMaintenanceConfig(): Promise {
+ const defaults: MaintenanceConfig = {
+ enabled: false,
+ message: 'We are currently performing scheduled maintenance.',
+ estimatedDuration: '1-2 hours',
+ contactEmail: 'support@gitmesh.dev'
+ }
+
+ try {
+ const { data, error } = await supabase
+ .from('maintenance_config')
+ .select('*')
+ .eq('id', 1)
+ .single()
+
+ if (error) {
+ console.error('Error fetching maintenance config:', error)
+ return defaults
+ }
+
+ if (data) {
+ return {
+ enabled: data.enabled,
+ message: data.message,
+ estimatedDuration: data.estimated_duration,
+ contactEmail: data.contact_email
+ }
+ }
+ } catch (error) {
+ console.error('Unexpected error checking maintenance mode:', error)
+ }
+
+ return defaults
+}
diff --git a/middleware.ts b/middleware.ts
index 0468b7e..1ffb680 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -3,13 +3,15 @@ import { NextResponse } from 'next/server'
export default withAuth(
function middleware(req) {
- // For now, disable maintenance mode check to avoid Edge Runtime issues
- // You can implement this via environment variables or API routes instead
- const isMaintenancePage = req.nextUrl.pathname === '/maintenance'
- const isApiRoute = req.nextUrl.pathname.startsWith('/api')
- const isAdminRoute = req.nextUrl.pathname.startsWith('/admin')
-
- // Add any additional middleware logic here
+ // Add current path to headers for Server Components to use
+ const requestHeaders = new Headers(req.headers)
+ requestHeaders.set('x-current-path', req.nextUrl.pathname)
+
+ return NextResponse.next({
+ request: {
+ headers: requestHeaders,
+ },
+ })
},
{
callbacks: {
diff --git a/supabase_schema.sql b/supabase_schema.sql
index 3bf9b1f..51ce6c1 100644
--- a/supabase_schema.sql
+++ b/supabase_schema.sql
@@ -55,3 +55,37 @@ CREATE TRIGGER update_content_updated_at
BEFORE UPDATE ON public.content
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
+
+-- 6. Maintenance Configuration
+-- Singleton table to store global maintenance mode settings
+CREATE TABLE IF NOT EXISTS public.maintenance_config (
+ id INT PRIMARY KEY DEFAULT 1 CHECK (id = 1), -- Enforce singleton pattern
+ enabled BOOLEAN DEFAULT FALSE,
+ message TEXT DEFAULT 'We are currently performing scheduled maintenance.',
+ estimated_duration TEXT DEFAULT '1-2 hours',
+ contact_email TEXT DEFAULT 'support@gitmesh.dev',
+ updated_at TIMESTAMPTZ DEFAULT NOW()
+);
+
+-- Seed the initial configuration if it doesn't exist
+INSERT INTO public.maintenance_config (id, enabled)
+VALUES (1, false)
+ON CONFLICT (id) DO NOTHING;
+
+-- Security Policies
+ALTER TABLE public.maintenance_config ENABLE ROW LEVEL SECURITY;
+
+-- Allow everyone (including unauthenticated users) to read maintenance status
+CREATE POLICY "anon_read_maintenance" ON public.maintenance_config FOR SELECT TO anon USING (true);
+
+-- Allow authenticated users (admins) to manage it
+CREATE POLICY "auth_manage_maintenance" ON public.maintenance_config FOR ALL TO authenticated USING (true) WITH CHECK (true);
+
+-- Allow service role full access
+CREATE POLICY "service_manage_maintenance" ON public.maintenance_config FOR ALL TO service_role USING (true) WITH CHECK (true);
+
+-- Trigger to update 'updated_at' automatically
+CREATE TRIGGER update_maintenance_updated_at
+BEFORE UPDATE ON public.maintenance_config
+FOR EACH ROW
+EXECUTE FUNCTION update_updated_at_column();
\ No newline at end of file