feat(auth): Einrichtung, Anmeldeseite und Registrierung
- /setup fuehrt beim ersten Aufruf durch das Anlegen des Administratorkontos und die Wahl der Betriebsart. Der Endpunkt funktioniert nur, solange es keinen Benutzer gibt; danach kann sich niemand mehr nachtraeglich ein Adminkonto erschleichen. Vorhandene Projekte ohne Besitzer werden dabei uebernommen und im Formular vorher angekuendigt. - /login mit Passwort oder Passkey. Der Passkey-Knopf entfaellt, wenn APP_URL keinen sicheren Kontext ergibt - mit Hinweis, woran es liegt. Das Ziel nach der Anmeldung wird auf relative Pfade begrenzt, sonst waere der weiter-Parameter ein offener Redirect. - /register nur im Mehrbenutzerbetrieb und nur, wenn ein Administrator die Selbstregistrierung freigegeben hat. - Kopfzeile mit Benutzermenue: eigenes Konto, Admin-Einstellungen, Abmelden. Ohne Anmeldung bleibt sie auf das Logo reduziert. - Layout liest Titel und Namen ueber generateMetadata, damit APP_NAME zur Laufzeit greift statt beim Build eingefroren zu werden. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+25
-15
@@ -1,16 +1,26 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { TopNav } from "@/components/TopNav";
|
||||
import { getSessionUser } from "@/lib/auth/session";
|
||||
import { APP_NAME, APP_TAGLINE } from "@/lib/config";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: "Nebula – Vibe Coding Dashboard",
|
||||
template: "%s · Nebula",
|
||||
},
|
||||
description:
|
||||
"Uebersicht ueber alle Vibe-Coding Projekte: Status, Notizen und Live-Daten aus GitHub, GitLab und Gitea.",
|
||||
applicationName: "Nebula",
|
||||
};
|
||||
/**
|
||||
* generateMetadata statt eines konstanten metadata-Objekts: nur so wird
|
||||
* APP_NAME zur Laufzeit gelesen. Ein konstanter Export waere beim Build
|
||||
* eingefroren und liesse sich im fertigen Docker-Image nicht mehr aendern.
|
||||
*/
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: {
|
||||
default: `${APP_NAME} – Vibe Coding Dashboard`,
|
||||
template: `%s · ${APP_NAME}`,
|
||||
},
|
||||
description:
|
||||
"Uebersicht ueber alle Vibe-Coding Projekte: Status, Notizen und Live-Daten aus GitHub, GitLab und Gitea.",
|
||||
applicationName: APP_NAME,
|
||||
robots: { index: false, follow: false },
|
||||
};
|
||||
}
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#05060f",
|
||||
@@ -18,9 +28,11 @@ export const viewport: Viewport = {
|
||||
initialScale: 1,
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) {
|
||||
const user = await getSessionUser();
|
||||
|
||||
return (
|
||||
<html lang="de" suppressHydrationWarning>
|
||||
<body className="min-h-screen antialiased">
|
||||
@@ -31,7 +43,7 @@ export default function RootLayout({
|
||||
</div>
|
||||
<div className="aurora-grid" aria-hidden="true" />
|
||||
|
||||
<TopNav />
|
||||
<TopNav user={user} appName={APP_NAME} tagline={APP_TAGLINE} />
|
||||
|
||||
<main className="mx-auto w-full max-w-[1400px] px-4 pb-24 pt-6 sm:px-6 lg:px-8">
|
||||
{children}
|
||||
@@ -39,10 +51,8 @@ export default function RootLayout({
|
||||
|
||||
<footer className="mx-auto w-full max-w-[1400px] px-4 pb-10 text-xs text-slate-500 sm:px-6 lg:px-8">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 border-t border-white/5 pt-6">
|
||||
<span>
|
||||
Nebula · lokal betrieben, Daten bleiben in deiner PostgreSQL.
|
||||
</span>
|
||||
<span className="font-mono text-slate-600">v0.1.0</span>
|
||||
<span>{APP_NAME} · lokal betrieben, Daten bleiben in deiner PostgreSQL.</span>
|
||||
<span className="font-mono text-slate-600">v0.2.0</span>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user