import type { Metadata } from "next"; import { Database } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; export const metadata: Metadata = { title: "Database Schema", }; type Column = { name: string; type: string; notes?: string; }; type Table = { name: string; description: string; columns: Column[]; }; const currentTables: Table[] = [ { name: "profiles", description: "Extends Supabase auth.users with app-specific user preferences and settings.", columns: [ { name: "id", type: "uuid", notes: "FK → auth.users" }, { name: "email", type: "text" }, { name: "display_name", type: "text", notes: "nullable" }, { name: "avatar_url", type: "text", notes: "nullable" }, { name: "created_at", type: "timestamptz" }, { name: "updated_at", type: "timestamptz" }, ], }, { name: "saved_domains", description: "Domains the user has added to their watchlist for monitoring.", columns: [ { name: "id", type: "uuid" }, { name: "user_id", type: "uuid", notes: "FK → profiles" }, { name: "domain", type: "text" }, { name: "tags", type: "text[]", notes: "nullable" }, { name: "last_checked_at", type: "timestamptz", notes: "nullable" }, { name: "created_at", type: "timestamptz" }, ], }, { name: "dns_history", description: "Snapshots of DNS records captured at each monitoring check. Used for change detection and history browsing.", columns: [ { name: "id", type: "uuid" }, { name: "saved_domain_id", type: "uuid", notes: "FK → saved_domains" }, { name: "user_id", type: "uuid", notes: "FK → profiles" }, { name: "records", type: "jsonb", notes: "Full DNS snapshot" }, { name: "resolver", type: "text", notes: "e.g. 8.8.8.8" }, { name: "checked_at", type: "timestamptz" }, ], }, { name: "availability_history", description: "Tracks domain availability (registered / available) over time.", columns: [ { name: "id", type: "uuid" }, { name: "saved_domain_id", type: "uuid", notes: "FK → saved_domains" }, { name: "user_id", type: "uuid", notes: "FK → profiles" }, { name: "available", type: "boolean" }, { name: "checked_at", type: "timestamptz" }, ], }, { name: "notifications", description: "In-app notification feed. Written by the Go monitoring service when changes are detected.", columns: [ { name: "id", type: "uuid" }, { name: "user_id", type: "uuid", notes: "FK → profiles" }, { name: "saved_domain_id", type: "uuid", notes: "FK → saved_domains" }, { name: "type", type: "text", notes: "e.g. dns_change, availability" }, { name: "message", type: "text" }, { name: "read", type: "boolean" }, { name: "created_at", type: "timestamptz" }, ], }, ]; type PlannedTable = { name: string; for: string; description: string; keyColumns: string[]; }; const plannedTables: PlannedTable[] = [ { name: "teams", for: "Team / org accounts", description: "Supports shared watchlists and role-based access for organizations.", keyColumns: ["id", "name", "owner_id", "created_at"], }, { name: "team_members", for: "Team membership & roles", description: "Maps users to teams with a role (admin / viewer). Enables team-aware RLS policies.", keyColumns: ["team_id", "user_id", "role", "joined_at"], }, { name: "domain_folders", for: "Folder organization", description: "Lets users organize monitored domains into named folders. saved_domains will gain an optional folder_id FK.", keyColumns: ["id", "user_id", "name", "created_at"], }, { name: "shared_snapshots", for: "Public shareable links", description: "Stores DNS snapshots accessible via a unique token — no auth required to view.", keyColumns: [ "id", "saved_domain_id", "share_token", "dns_snapshot", "expires_at", ], }, { name: "notification_channels", for: "Webhook / Slack / Discord", description: "User-configured alert destinations beyond in-app and email. Config stored as JSONB.", keyColumns: ["id", "user_id", "type", "config", "enabled"], }, { name: "subscriptions", for: "Billing tier tracking", description: "Tracks the active plan (free / pro / team) per user for feature gating.", keyColumns: ["id", "user_id", "plan", "valid_until", "created_at"], }, ]; function TableCard({ table }: { table: Table }) { return (
{table.name} current
{table.description}
{table.columns.map((col) => ( ))}
Column Type Notes
{col.name} {col.type} {col.notes ?? "—"}
); } export default function DatabaseSchemaPage() { return (
{/* Page header */}

Database Schema

VectorDNS uses Supabase (managed Postgres) with Row Level Security. There are currently 5 tables in production, with 6 more planned as features are built out.

{/* Current tables */}

Current Tables

{currentTables.length} tables
{currentTables.map((table) => ( ))}
{/* Planned tables */}

Planned Tables

{plannedTables.length} planned

These tables will be added as the corresponding features are implemented. Schema details may evolve.

{plannedTables.map((table) => (
{table.name} planned
{table.for} {table.description}
{table.keyColumns.map((col) => ( {col} ))}
))}
{/* RLS note */}

Row Level Security

All tables have RLS enabled. Policies enforce that users can only read and write their own rows ( user_id = auth.uid() ). Future team-aware policies will extend this to allow team members access to shared resources based on their role.

); }