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>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import type { GitProvider, Note, Project, ProjectStatus, RepoSnapshot } from "@prisma/client";
|
||||
import type { BranchInfo, CommitInfo, ReleaseInfo, TagInfo } from "@/lib/git/types";
|
||||
|
||||
/** Verbindung ohne Geheimnisse – so wird sie an den Browser gegeben. */
|
||||
export interface ConnectionSafe {
|
||||
id: string;
|
||||
name: string;
|
||||
provider: GitProvider;
|
||||
baseUrl: string;
|
||||
username: string | null;
|
||||
tokenHint: string | null;
|
||||
lastCheckedAt: Date | string | null;
|
||||
lastCheckOk: boolean | null;
|
||||
lastCheckMessage: string | null;
|
||||
createdAt: Date | string;
|
||||
updatedAt: Date | string;
|
||||
}
|
||||
|
||||
export interface ConnectionWithCount extends ConnectionSafe {
|
||||
_count?: { projects: number };
|
||||
}
|
||||
|
||||
export interface ProjectListItem extends Project {
|
||||
connection: ConnectionSafe | null;
|
||||
snapshot: RepoSnapshot | null;
|
||||
_count: { notes: number };
|
||||
}
|
||||
|
||||
export interface ProjectDetail extends Project {
|
||||
connection: ConnectionSafe | null;
|
||||
snapshot: RepoSnapshot | null;
|
||||
notes: Note[];
|
||||
_count: { notes: number };
|
||||
}
|
||||
|
||||
export interface RepoListEntry {
|
||||
fullPath: string;
|
||||
owner: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
htmlUrl: string;
|
||||
defaultBranch: string | null;
|
||||
visibility: string | null;
|
||||
updatedAt: string | null;
|
||||
}
|
||||
|
||||
export type { BranchInfo, CommitInfo, Note, ProjectStatus, ReleaseInfo, RepoSnapshot, TagInfo };
|
||||
|
||||
/** Prisma liefert Json als unknown – hier bequem in Arrays zurueckholen. */
|
||||
export function asArray<T>(value: unknown): T[] {
|
||||
return Array.isArray(value) ? (value as T[]) : [];
|
||||
}
|
||||
|
||||
export function asRecord(value: unknown): Record<string, number> {
|
||||
if (value && typeof value === "object" && !Array.isArray(value)) {
|
||||
return value as Record<string, number>;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
Reference in New Issue
Block a user