Scaffold Next.js MVP foundation with pnpm

This commit is contained in:
Matthias
2026-06-03 21:46:52 +02:00
parent 762571cb43
commit 20615e12a1
13 changed files with 8055 additions and 11741 deletions

27
app/audit/[slug]/page.tsx Normal file
View File

@@ -0,0 +1,27 @@
import { FileText } from "lucide-react";
export default async function PublicAuditPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return (
<main className="flex min-h-dvh items-center justify-center bg-background px-6 py-12">
<section className="w-full max-w-2xl rounded-lg border bg-card p-6 text-card-foreground">
<FileText className="mb-5 size-6 text-muted-foreground" />
<p className="text-sm font-medium text-muted-foreground">
Audit: {slug}
</p>
<h1 className="mt-3 text-3xl font-semibold tracking-normal">
Dieser Audit ist noch nicht freigegeben
</h1>
<p className="mt-4 text-sm leading-6 text-muted-foreground">
Sobald der Bericht manuell geprueft und veroeffentlicht wurde,
erscheinen hier die freigegebenen Beobachtungen und Empfehlungen.
</p>
</section>
</main>
);
}

64
app/dashboard/page.tsx Normal file
View File

@@ -0,0 +1,64 @@
import { FileSearch, MailCheck, MapPinned, ShieldCheck } from "lucide-react";
const pipelineSteps = [
{
title: "Kampagnen",
description: "Kategorie, PLZ, Radius und Lauf-Limits vorbereiten.",
icon: MapPinned,
},
{
title: "Lead-Audit",
description: "Website-Potenzial, Screenshots und Quellen buendeln.",
icon: FileSearch,
},
{
title: "Freigabe",
description: "Audit-Seite, E-Mail und Telefon-Skript manuell pruefen.",
icon: ShieldCheck,
},
{
title: "Outreach",
description: "Freigegebene Kontakte senden und Antworten nachhalten.",
icon: MailCheck,
},
];
export default function DashboardPage() {
return (
<main className="min-h-dvh bg-background px-6 py-8">
<div className="mx-auto flex w-full max-w-6xl flex-col gap-8">
<header className="flex flex-col gap-2 border-b pb-6">
<p className="text-sm font-medium text-muted-foreground">
Interner Arbeitsbereich
</p>
<h1 className="text-3xl font-semibold tracking-normal">
Dashboard-Platzhalter
</h1>
<p className="max-w-2xl text-sm leading-6 text-muted-foreground">
Hier entsteht der scanbare Funnel fuer Recherche, Audit, Review,
Versand und Follow-up.
</p>
</header>
<section className="grid gap-3 md:grid-cols-4">
{pipelineSteps.map((step) => {
const Icon = step.icon;
return (
<article
className="rounded-lg border bg-card p-4 text-card-foreground"
key={step.title}
>
<Icon className="mb-4 size-5 text-muted-foreground" />
<h2 className="text-sm font-medium">{step.title}</h2>
<p className="mt-2 text-sm leading-6 text-muted-foreground">
{step.description}
</p>
</article>
);
})}
</section>
</div>
</main>
);
}

View File

@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "WebDev Pipeline",
description: "Interner Akquise-Agent fuer lokale Webdesign-Leads",
};
export default function RootLayout({
@@ -24,7 +24,7 @@ export default function RootLayout({
}>) {
return (
<html
lang="en"
lang="de"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>

19
app/login/page.tsx Normal file
View File

@@ -0,0 +1,19 @@
import { LockKeyhole } from "lucide-react";
export default function LoginPage() {
return (
<main className="flex min-h-dvh items-center justify-center bg-background px-6 py-12">
<section className="w-full max-w-md rounded-lg border bg-card p-6 text-card-foreground">
<LockKeyhole className="mb-5 size-6 text-muted-foreground" />
<h1 className="text-2xl font-semibold tracking-normal">
Login-Platzhalter
</h1>
<p className="mt-3 text-sm leading-6 text-muted-foreground">
Better Auth wird in einem spaeteren Task angebunden. Bis dahin bleibt
diese Route als definierter Einstiegspunkt fuer den Admin-Login
bestehen.
</p>
</section>
</main>
);
}

View File

@@ -1,65 +1,81 @@
import Image from "next/image";
import Link from "next/link";
import { ArrowRight, FileText, LayoutDashboard, LockKeyhole } from "lucide-react";
import { Button } from "@/components/ui/button";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
<main className="flex flex-1 bg-background">
<section className="mx-auto flex min-h-dvh w-full max-w-5xl flex-col justify-center gap-10 px-6 py-12">
<div className="max-w-3xl space-y-5">
<p className="text-sm font-medium text-muted-foreground">
WebDev Pipeline MVP
</p>
<h1 className="text-4xl font-semibold tracking-normal text-foreground sm:text-5xl">
Lokale Webdesign-Leads recherchieren, auditieren und respektvoll
kontaktieren.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
<p className="max-w-2xl text-base leading-7 text-muted-foreground sm:text-lg">
Diese Foundation setzt die ersten App-Routen fuer Dashboard,
Anmeldung und oeffentliche Audit-Seiten auf. Die Integrationen
folgen in den naechsten Backlog-Tasks.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
<div className="grid gap-3 sm:grid-cols-3">
<Button asChild size="lg" className="justify-between">
<Link href="/dashboard">
<span className="inline-flex items-center gap-2">
<LayoutDashboard />
Dashboard
</span>
<ArrowRight />
</Link>
</Button>
<Button asChild size="lg" variant="outline" className="justify-between">
<Link href="/login">
<span className="inline-flex items-center gap-2">
<LockKeyhole />
Login
</span>
<ArrowRight />
</Link>
</Button>
<Button asChild size="lg" variant="outline" className="justify-between">
<Link href="/audit/example">
<span className="inline-flex items-center gap-2">
<FileText />
Audit
</span>
<ArrowRight />
</Link>
</Button>
</div>
</main>
</div>
<dl className="grid gap-4 border-t pt-8 sm:grid-cols-3">
<div>
<dt className="text-sm font-medium text-foreground">Recherche</dt>
<dd className="mt-2 text-sm leading-6 text-muted-foreground">
Kampagnen, Places-Quellen und Lead-Qualitaet werden spaeter im
Dashboard gebuendelt.
</dd>
</div>
<div>
<dt className="text-sm font-medium text-foreground">Audit</dt>
<dd className="mt-2 text-sm leading-6 text-muted-foreground">
Oeffentliche Audit-Seiten starten als sichere Platzhalter ohne
freigegebene Inhalte.
</dd>
</div>
<div>
<dt className="text-sm font-medium text-foreground">Outreach</dt>
<dd className="mt-2 text-sm leading-6 text-muted-foreground">
Versand bleibt im MVP an manuelle Pruefung und Freigabe
gekoppelt.
</dd>
</div>
</dl>
</section>
</main>
);
}