Documentation Index
Fetch the complete documentation index at: https://dhanurgo.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Authentication & RLS
Authentication Flow
HostMetrics uses Supabase Auth with email/password authentication.
AuthProvider
src/components/auth/AuthProvider.tsx provides a React Context with:
| Property | Type | Description |
|---|
user | User | null | Current authenticated user |
session | Session | null | JWT session |
isLoading | boolean | Auth state loading |
signOut() | () => Promise<void> | Sign out and redirect |
refreshSession() | () => Promise<void> | Force refresh session |
The provider listens to supabase.auth.onAuthStateChange() for real-time session updates across browser tabs.
Protected Routes
(dashboard)/ layout group — Requires authenticated session
(auth)/ layout group — Public (login, signup, reset password)
/fleet/[slug] — Public fleet pages (no auth)
/p/[token] — Token-authenticated investor portal
/r/[token] — Token-authenticated investor report
API Route Authentication
Server-side API routes validate tokens manually:
// Pattern used in /api/turo/sync, /api/tolls/sync, etc.
const authHeader = request.headers.get("authorization");
const token = authHeader?.replace("Bearer ", "");
const { data: { user }, error } = await supabase.auth.getUser(token);
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Row Level Security (RLS)
Every table has RLS enabled with policies ensuring users can only access their own data.
The Pattern
-- SELECT: Users see only their own rows
CREATE POLICY "select_own" ON table_name
FOR SELECT USING (user_id = auth.uid());
-- INSERT: Users can only insert rows with their own user_id
CREATE POLICY "insert_own" ON table_name
FOR INSERT WITH CHECK (user_id = auth.uid());
-- UPDATE: Users can only update their own rows
CREATE POLICY "update_own" ON table_name
FOR UPDATE USING (user_id = auth.uid());
-- DELETE: Users can only delete their own rows
CREATE POLICY "delete_own" ON table_name
FOR DELETE USING (user_id = auth.uid());
Application-Level Enforcement
In addition to RLS, the application code always filters by user_id:
// src/lib/db/_client.ts
export async function getCurrentUserId(): Promise<string> {
const { data: { user } } = await getClient().auth.getUser();
if (!user) throw new Error("Not authenticated");
return user.id;
}
// Used in every DB module:
const userId = await getCurrentUserId();
const { data } = await supabase
.from("trips")
.select("*")
.eq("user_id", userId);
This double enforcement (RLS + application filtering) ensures data isolation even if one layer has a bug.