Roadmap Added

This commit is contained in:
Aiden Smith
2026-02-25 08:34:43 -05:00
parent 466fdd6ef8
commit 09787926f3
4 changed files with 434 additions and 0 deletions

View File

@@ -50,6 +50,12 @@ export default function Home() {
>
Docs
</Link>
<Link
href="/roadmap"
className="text-sm text-muted-foreground transition-colors hover:text-foreground"
>
Roadmap
</Link>
<ThemeToggle />
</div>
</div>

114
app/roadmap/page.tsx Normal file
View File

@@ -0,0 +1,114 @@
import type { Metadata } from "next";
import Link from "next/link";
import { Globe, Map, Info } from "lucide-react";
import { ThemeToggle } from "@/components/theme-toggle";
import { RoadmapFlowchart } from "@/components/roadmap-flowchart";
import { Badge } from "@/components/ui/badge";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card";
export const metadata: Metadata = {
title: "Roadmap",
description: "Visual roadmap and development phases for VectorDNS.",
};
export default function RoadmapPage() {
return (
<div className="flex min-h-screen flex-col">
{/* Header */}
<header className="border-b bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60 sticky top-0 z-50">
<div className="container mx-auto flex h-14 items-center justify-between px-4">
<Link href="/" className="flex items-center gap-2">
<Globe className="size-5 text-primary" />
<span className="text-lg font-semibold tracking-tight">
VectorDNS
</span>
</Link>
<div className="flex items-center gap-4">
<Link
href="/docs"
className="text-sm text-muted-foreground transition-colors hover:text-foreground"
>
Docs
</Link>
<Link
href="/roadmap"
className="text-sm font-medium text-foreground transition-colors"
>
Roadmap
</Link>
<ThemeToggle />
</div>
</div>
</header>
<main className="flex-1">
<div className="container mx-auto px-4 py-12">
{/* Page Header */}
<div className="mb-12 flex flex-col items-center text-center gap-4">
<Badge
variant="outline"
className="px-3 py-1 gap-1.5 border-primary/20 bg-primary/5 text-primary"
>
<Map className="size-3.5" />
Project Roadmap
</Badge>
<h1 className="text-4xl font-extrabold tracking-tight lg:text-5xl">
Building the Future of{" "}
<span className="text-primary">DNS Monitoring</span>
</h1>
<p className="max-w-2xl text-lg text-muted-foreground">
Follow our journey from foundation to a full-featured domain
toolkit. Drag, zoom, and explore the development phases below.
</p>
</div>
{/* Interactive Flowchart */}
<div className="mb-12">
<RoadmapFlowchart />
</div>
{/* Additional Context Cards */}
<div className="grid gap-6 md:grid-cols-2">
<Card className="border-primary/10 bg-primary/5">
<CardHeader>
<div className="flex items-center gap-2 text-primary mb-1">
<Info className="size-5" />
<CardTitle className="text-lg">Project Philosophy</CardTitle>
</div>
<CardDescription>
VectorDNS is built on three core pillars: speed, accuracy, and
transparency. Every phase of our roadmap is designed to ensure
the highest quality data while maintaining a modern,
user-friendly experience.
</CardDescription>
</CardHeader>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-lg">Contributing</CardTitle>
<CardDescription>
We are currently in the early development stages. If
you&apos;re interested in contributing to the Go DNS API or
the Next.js frontend, please check out our GitHub repository
and open an issue or PR.
</CardDescription>
</CardHeader>
</Card>
</div>
</div>
</main>
{/* Footer */}
<footer className="border-t py-6">
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
<p>&copy; {new Date().getFullYear()} VectorDNS</p>
</div>
</footer>
</div>
);
}

View File

@@ -3,6 +3,7 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
SquareKanban,
BookOpen,
Layers,
ArrowRightLeft,
@@ -13,6 +14,10 @@ import {
} from "lucide-react";
const sections = [
{
title: "Roadmap",
items: [{ title: "Project Roadmap", href: "/roadmap", icon: SquareKanban }],
},
{
title: "Getting Started",
items: [{ title: "Overview", href: "/docs", icon: BookOpen }],

View File

@@ -0,0 +1,309 @@
"use client";
import {
ReactFlow,
Background,
type Node,
type Edge,
type NodeProps,
Handle,
Position,
MarkerType,
} from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import {
CheckCircle2,
Circle,
Flag,
Rocket,
Settings,
ShieldCheck,
Database,
Layout,
Activity,
TestTube,
} from "lucide-react";
type PhaseNodeData = {
label: string;
status: "todo" | "doing" | "done";
icon: React.ElementType;
color: string;
items: { text: string; completed: boolean }[];
};
function PhaseNode({ data }: NodeProps<Node<PhaseNodeData>>) {
const Icon = data.icon;
return (
<div
className="rounded-xl border bg-card p-6 shadow-lg transition-all hover:border-primary/50"
style={{ minWidth: 320 }}
>
<Handle type="target" position={Position.Top} className="opacity-0" />
<Handle type="source" position={Position.Bottom} className="opacity-0" />
<div className="flex items-center gap-4 border-b pb-4 mb-4">
<div
className="flex size-12 items-center justify-center rounded-lg"
style={{ backgroundColor: data.color }}
>
<Icon className="size-6 text-white" />
</div>
<div>
<div className="text-lg font-bold text-foreground leading-tight">
{data.label}
</div>
<div
className={`text-xs font-semibold uppercase tracking-wider mt-0.5 ${
data.status === "done"
? "text-green-500"
: data.status === "doing"
? "text-blue-500"
: "text-muted-foreground"
}`}
>
{data.status}
</div>
</div>
</div>
<ul className="space-y-3">
{data.items.map((item, i) => (
<li
key={i}
className="flex items-start gap-3 text-sm leading-relaxed text-muted-foreground"
>
{item.completed ? (
<CheckCircle2 className="mt-0.5 size-4 shrink-0 text-green-500" />
) : (
<Circle className="mt-0.5 size-4 shrink-0 text-muted-foreground/40" />
)}
<span className={item.completed ? "line-through opacity-50" : ""}>
{item.text}
</span>
</li>
))}
</ul>
</div>
);
}
const nodeTypes = { phase: PhaseNode };
const nodes: Node<PhaseNodeData>[] = [
{
id: "p1",
type: "phase",
position: { x: 0, y: 0 },
data: {
label: "Phase 1 — Foundation",
status: "todo",
icon: Database,
color: "#6366f1",
items: [
{ text: "TypeScript types", completed: false },
{ text: "Supabase schema & migrations", completed: false },
{ text: "Supabase client setup (@supabase/ssr)", completed: false },
{ text: "Project config & env setup", completed: false },
],
},
},
{
id: "p2",
type: "phase",
position: { x: 400, y: 0 },
data: {
label: "Phase 2 — Core Services",
status: "todo",
icon: Settings,
color: "#8b5cf6",
items: [
{ text: "DNS service (tangerine)", completed: false },
{ text: "WHOIS service (whoiser)", completed: false },
{ text: "Availability service (IANA RDAP)", completed: false },
{ text: "Public lookup APIs", completed: false },
{ text: "Integration tests", completed: false },
],
},
},
{
id: "p3",
type: "phase",
position: { x: 800, y: 0 },
data: {
label: "Phase 3 — Authentication",
status: "todo",
icon: ShieldCheck,
color: "#ec4899",
items: [
{ text: "Supabase Auth (GitHub, Google, Email)", completed: false },
{ text: "Auth server actions", completed: false },
{ text: "OAuth callback route", completed: false },
{ text: "Middleware protection", completed: false },
{ text: "Login/signup pages", completed: false },
],
},
},
{
id: "p4",
type: "phase",
position: { x: 0, y: 450 },
data: {
label: "Phase 4 — Public UI",
status: "doing",
icon: Layout,
color: "#3b82f6",
items: [
{ text: "App shell layout", completed: false },
{ text: "Homepage Hero & Search", completed: true },
{ text: "DNS results page", completed: false },
{ text: "Save to Dashboard button", completed: false },
],
},
},
{
id: "p5",
type: "phase",
position: { x: 400, y: 450 },
data: {
label: "Phase 5 — Dashboard",
status: "todo",
icon: Rocket,
color: "#06b6d4",
items: [
{ text: "Dashboard layout & stats", completed: false },
{ text: "Saved domains CRUD", completed: false },
{ text: "Domain detail page & history", completed: false },
{ text: "Notes & tags (auto-save)", completed: false },
{ text: "Manual re-check triggers", completed: false },
],
},
},
{
id: "p6",
type: "phase",
position: { x: 800, y: 450 },
data: {
label: "Phase 6 — Monitoring & Alerts",
status: "todo",
icon: Activity,
color: "#10b981",
items: [
{ text: "Change detection logic", completed: false },
{ text: "Vercel Daily Cron job", completed: false },
{ text: "In-app notification system", completed: false },
{ text: "Email alerts via Resend", completed: false },
],
},
},
{
id: "p7",
type: "phase",
position: { x: 200, y: 900 },
data: {
label: "Phase 7 — Settings & Polish",
status: "todo",
icon: Flag,
color: "#f59e0b",
items: [
{ text: "User profile & preferences", completed: false },
{ text: "Error boundaries & 404s", completed: false },
{ text: "Toast notifications (sonner)", completed: false },
{ text: "SEO & OG image generation", completed: false },
],
},
},
{
id: "p8",
type: "phase",
position: { x: 600, y: 900 },
data: {
label: "Phase 8 — Testing & QA",
status: "todo",
icon: TestTube,
color: "#64748b",
items: [
{ text: "End-to-end integration tests", completed: false },
{ text: "Build verification (zero TS errors)", completed: false },
{ text: "Manual QA pass (Light/Dark mode)", completed: false },
],
},
},
];
const edges: Edge[] = [
{
id: "e1-2",
source: "p1",
target: "p2",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8" },
},
{
id: "e2-3",
source: "p2",
target: "p3",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8" },
},
{
id: "e3-4",
source: "p3",
target: "p4",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8", strokeWidth: 2 },
},
{
id: "e4-5",
source: "p4",
target: "p5",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8" },
},
{
id: "e5-6",
source: "p5",
target: "p6",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8" },
},
{
id: "e6-7",
source: "p6",
target: "p7",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8", strokeWidth: 2 },
},
{
id: "e7-8",
source: "p7",
target: "p8",
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
style: { stroke: "#94a3b8" },
},
];
export function RoadmapFlowchart() {
return (
<div className="h-275 w-full rounded-2xl border bg-muted/30 backdrop-blur-sm shadow-inner">
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
fitView
fitViewOptions={{ padding: 0.1 }}
proOptions={{ hideAttribution: true }}
nodesDraggable={false}
nodesConnectable={false}
elementsSelectable={false}
panOnDrag={false}
zoomOnScroll={false}
zoomOnPinch={false}
zoomOnDoubleClick={false}
preventScrolling={false}
>
<Background gap={32} size={1} className="opacity-15" />
</ReactFlow>
</div>
);
}