Files
nebula/src/lib/status.ts
T
florian.wildeandClaude Opus 5 c9e09a2762 feat(core): Verschluesselung, Validierung und gemeinsame Helfer
- crypto.ts: AES-256-GCM fuer die Git-Access-Tokens, Schluessel per scrypt
  aus APP_SECRET abgeleitet. Chiffrat ist versioniert (v1.<iv>.<tag>.<data>),
  damit ein spaeterer Formatwechsel moeglich bleibt. Fehlt APP_SECRET, warnt
  die App und faellt auf einen Entwicklungsschluessel zurueck.
- validation.ts: Zod-Schemas fuer alle Eingaben an der API-Grenze, inklusive
  Umwandlung leerer Strings zu null und Feldfehlern fuer die Oberflaeche.
- status.ts: Metadaten zu Status, Prioritaeten und Akzentfarben an einer
  Stelle, damit Board, Karte und Detailseite nicht auseinanderlaufen.
- utils.ts: Slug-Erzeugung, deutsche Datumsformate mit fester Zeitzone
  (verhindert Abweichungen zwischen Server-Render und Hydration) und
  relative Zeitangaben.
- projects.ts: wiederverwendete Prisma-Selects. Die Verbindungsauswahl laesst
  tokenCipher bewusst weg, damit kein Token in eine Client-Komponente gelangt.
- db.ts: Prisma-Client mit Cache ueber globalThis gegen Verbindungslecks beim
  Hot Reload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:33:35 +02:00

99 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { ProjectStatus } from "@prisma/client";
export type StatusMeta = {
value: ProjectStatus;
label: string;
short: string;
/** Tailwind-Klassen fuer Pills/Badges */
className: string;
/** Reine Farbe fuer Punkte, Balken und Glows */
color: string;
description: string;
};
export const STATUS_ORDER: ProjectStatus[] = [
"IDEA",
"PLANNING",
"OPEN",
"IN_DEVELOPMENT",
"DONE",
"ARCHIVED",
];
export const STATUS_META: Record<ProjectStatus, StatusMeta> = {
IDEA: {
value: "IDEA",
label: "Idee",
short: "Idee",
className: "bg-cyan-500/12 text-cyan-200 ring-cyan-400/30",
color: "#22d3ee",
description: "Noch ein Gedanke – nichts gebaut, nichts entschieden.",
},
PLANNING: {
value: "PLANNING",
label: "In Planung",
short: "Planung",
className: "bg-blue-500/12 text-blue-200 ring-blue-400/30",
color: "#60a5fa",
description: "Scope, Stack und Schnitt werden gerade festgelegt.",
},
OPEN: {
value: "OPEN",
label: "Offen",
short: "Offen",
className: "bg-amber-500/12 text-amber-200 ring-amber-400/30",
color: "#fbbf24",
description: "Startklar, aber aktuell liegt es still.",
},
IN_DEVELOPMENT: {
value: "IN_DEVELOPMENT",
label: "In Entwicklung",
short: "Aktiv",
className: "bg-violet-500/12 text-violet-200 ring-violet-400/30",
color: "#a78bfa",
description: "Wird gerade aktiv gebaut.",
},
DONE: {
value: "DONE",
label: "Fertig",
short: "Fertig",
className: "bg-emerald-500/12 text-emerald-200 ring-emerald-400/30",
color: "#34d399",
description: "Ausgeliefert und abgeschlossen.",
},
ARCHIVED: {
value: "ARCHIVED",
label: "Archiviert",
short: "Archiv",
className: "bg-slate-500/12 text-slate-300 ring-slate-400/25",
color: "#94a3b8",
description: "Ruht im Archiv – bleibt erhalten, stoert aber nicht mehr.",
},
};
export const PRIORITY_META: Record<number, { label: string; color: string }> = {
1: { label: "Niedrig", color: "#64748b" },
2: { label: "Normal", color: "#38bdf8" },
3: { label: "Hoch", color: "#fb923c" },
4: { label: "Kritisch", color: "#f43f5e" },
};
export type AccentKey = "violet" | "cyan" | "emerald" | "amber" | "rose" | "blue";
export const ACCENTS: Record<AccentKey, { label: string; from: string; to: string }> = {
violet: { label: "Violett", from: "#8b5cf6", to: "#d946ef" },
cyan: { label: "Cyan", from: "#06b6d4", to: "#3b82f6" },
emerald: { label: "Smaragd", from: "#10b981", to: "#84cc16" },
amber: { label: "Bernstein", from: "#f59e0b", to: "#f43f5e" },
rose: { label: "Rose", from: "#f43f5e", to: "#8b5cf6" },
blue: { label: "Blau", from: "#3b82f6", to: "#6366f1" },
};
export function accentOf(key: string | null | undefined) {
return ACCENTS[(key ?? "violet") as AccentKey] ?? ACCENTS.violet;
}
export function statusOf(status: ProjectStatus | string): StatusMeta {
return STATUS_META[status as ProjectStatus] ?? STATUS_META.IDEA;
}