TuBrief
구독 채널
비디오
커뮤니티

Wie man von Claude Code generierten UI-Code sicher in ein bestehendes Projekt integriert

TuBrief 편집팀
2026년 9월 12일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

Deutsch한국어EnglishEspañol中文हिन्दीFrançaisالعربيةPortuguêsРусскийBahasa Indonesia日本語

관련 영상

Claude Code hat gerade sein größtes Design-Update des Jahres erhalten (und so meisterst du es)10:58

Claude Code hat gerade sein größtes Design-Update des Jahres erhalten (und so meisterst du es)

Chase AI

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Wie man von Claude Code generierten UI-Code sicher in ein bestehendes Projekt integriert

Öffnet man Claude Code im Terminal und gibt /design ein, wirft das Tool innerhalb von Sekunden einen ersten UI-Entwurf aus. Für Solo-Entwickler ist das äusserst bequem, da es Arbeit abnimmt. Das Problem beginnt jedoch in dem Moment, in dem man diesen Code öffnet.

Die im Projekt bereits eingerichteten shadcn/ui-Komponenten werden komplett ignoriert, stattdessen werden rohe <button>-Tags neu geschrieben. Anstelle der im Farbpaletten-System registrierten semantischen Farben werden willkürliche Hex-Codes wie bg-[#1e293b] über jede Datei verstreut. Für jeden neu erstellten Bildschirm verschwendet man am Ende 40 Minuten damit, fehlerhafte Import-Pfade zu korrigieren und Inline-Styles zu löschen.

Das ist keine Einbildung. Eine Studie von GitClear aus dem Jahr 2024, die 211 Millionen Codezeilen in Commits analysierte, zeigt, dass der Anteil von Code, der innerhalb von zwei Wochen nach der Einführung von KI-Tools vollständig verworfen oder umgeschrieben wird, von 3,1 % auf 5,7 % und damit fast auf das Doppelte angestiegen ist. Die Refactoring-Quote ist gleichzeitig von 25 % auf unter 10 % eingebrochen. Die technische Schuld wächst im gleichen Tempo wie die Codebasis. Man muss sich von der Erwartung verabschieden, dass das Modell von selbst das bestehende Design-System einhält – stattdessen muss man es auf Systemebene an die Kandare nehmen.


Komponenten-Pfade durch Projekt-Regeldateien fixieren

Der Grund, warum Claude Code bestehenden Code ignoriert, ist simpel: Um das Context Window zu schonen, scannt es nur die minimal notwendigen Dateien. Ohne Einschränkungen kombiniert das Modell einfach die primitivsten HTML-Tags, um die Benutzeroberfläche zu zeichnen.

Dank Prompt Caching bleiben Konfigurationsdateien im Wurzelverzeichnis der Session bei etwa 10 % der normalen Eingabekosten. Sie gehen selbst dann nicht verloren, wenn Unterhaltungen zurückgesetzt oder komprimiert werden. Wenn man hier Regeln zur Wiederverwendung von Komponenten verankert, lässt sich verhindern, dass das Modell eigenmächtig rohe Tags generiert.

Tragen Sie die gemeinsamen Komponenten-Pfade und Stilregeln in die Datei CLAUDE.md im Projektstamm ein.

`markdown

Design System Guidelines

  1. Component Reuse (STRICT)
  • DO NOT use raw DOM tags (, , ).
  • MUST import from @/components/ui:
    • Button: import { Button } from "@/components/ui/button"
    • Input: import { Input } from "@/components/ui/input"
    • Card: import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"
    • Dialog: import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
  • If a component does not exist in @/components/ui, ask to run: "npx shadcn@latest add ".
  1. Token Boundaries
  • NEVER use arbitrary hex codes or pixel widths: NO bg-[#...], NO w-[...px].
  • Use Semantic CSS variables:
    • Surfaces: bg-background, bg-card, bg-muted
    • Text: text-foreground, text-muted-foreground, text-primary
    • Borders: border-border, border-input

`

Tausendzeilige globale CSS-Dateien müssen nicht jedes Mal komplett an den Prompt übergeben werden. Es reicht völlig aus, die Token-Namen aus der Tailwind-Konfiguration zu extrahieren und als JSON zu speichern.

`javascript
// scripts/extract-tokens.mjs
import fs from 'fs';
import resolveConfig from 'tailwindcss/resolveConfig.js';
import tailwindConfig from '../tailwind.config.js';

const fullConfig = resolveConfig(tailwindConfig);
const semanticTokens = {
colors: Object.keys(fullConfig.theme.colors || {}).filter(
(name) => !['inherit', 'current', 'transparent'].includes(name)
),
spacing: Object.keys(fullConfig.theme.spacing || {}),
borderRadius: Object.keys(fullConfig.theme.borderRadius || {}),
};

if (!fs.existsSync('.claude')) {
fs.mkdirSync('.claude');
}

fs.writeFileSync(
'.claude/design-tokens.json',
JSON.stringify(semanticTokens, null, 2)
);

`

Hängen Sie dieses Skript an postinstall und predev in der package.json an.

`json
{
"scripts": {
"postinstall": "node scripts/extract-tokens.mjs",
"predev": "node scripts/extract-tokens.mjs"
}
}

`

Die Liste der verfügbaren Klassen wird bei jedem Build aktualisiert. Die manuelle Arbeit, fehlerhafte Style-Klassen zu korrigieren, entfällt komplett.


Beliebige Styles automatisch durch Hook-Skripte ersetzen

Egal wie viele Warnhinweise im Prompt stehen, das Modell spuckt hin und wieder falsche Werte aus. Wenn man ihm einfach einen Screenshot hinwirft und um eine Benutzeroberfläche bittet, fügt es oft feste Breiten wie w-[380px] passend zum Bildformat ein. Das ist der Hauptgrund für horizontales Scrollen auf Mobilgeräten.

Um die Kriterien von WCAG 2.1 AA zu erfüllen, müssen auflösungsspezifische Standards klar definiert und der erstellte Code sofort durch einen Linter überprüft werden.

Prüfbereich Zielstandard Erforderliche Tailwind-Klassen Ausschlusskriterium
Mobil 390px (base) flex-col, w-full, grid-cols-1 Horizontales Scrollen durch feste w-[...px]-Breiten
Tablet 768px (md:) md:flex-row, md:grid-cols-2, md:p-6 Beibehaltung der mobilen Einspaltigkeit auf breiten Bildschirmen
Desktop 1440px (xl:) xl:max-w-7xl, mx-auto, xl:grid-cols-4 Unbegrenztes Vergrößern des Layout-Containers bei hoher Auflösung
Dark Mode .dark Selektor bg-background, text-foreground Unüberwachte Standardklassen wie bg-white oder text-black
Barrierefreiheit WCAG 2.1 AA aria-label, <main>, focus-visible:ring-2 Fehlender Alternativtext für Screenreader bei Icon-Buttons

Wenn man ein ungezähmtes Modell kontrollieren will, sind Lifecycle Hooks der sicherste Weg. Mit dem PostToolUse-Hook von Claude Code wird ein Skript ausgeführt, sobald Dateien auf die Festplatte geschrieben werden.

Registrieren Sie den Hook-Befehl in .claude/settings.json.

`json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/ast-lint-guard.mjs",
"timeout": 30
}
]
}
]
}
}

`

Schreiben Sie nun das Validierungsskript. Es fängt gängige Hex-Codes über reguläre Ausdrücke ab, ersetzt sie durch Projekt-Tokens und erzwingt Regeln über das Tailwind ESLint Plugin.

`javascript
// .claude/hooks/ast-lint-guard.mjs
import fs from 'fs';
import readline from 'readline';
import { execSync } from 'child_process';

const rl = readline.createInterface({ input: process.stdin });
let inputBuffer = '';

rl.on('line', (line) => { inputBuffer += line; });
rl.on('close', () => {
try {
const payload = JSON.parse(inputBuffer);
const filePath = payload.tool_input?.file_path || payload.tool_input?.path;

if (!filePath || !/\.(tsx|jsx)$/.test(filePath) || !fs.existsSync(filePath)) {
  process.exit(0);
}

let code = fs.readFileSync(filePath, 'utf-8');
let changed = false;

const replacementMap = {
  '#ffffff': 'bg-background',
  '#000000': 'text-foreground',
  '#020817': 'bg-background',
  '#0f172a': 'bg-card',
  '#1e293b': 'bg-muted',
  '#64748b': 'text-muted-foreground',
  '#2563eb': 'bg-primary',
};

for (const [hex, token] of Object.entries(replacementMap)) {
  const regex = new RegExp(`(bg|text|border)-\[${hex}\]`, 'gi');
  if (regex.test(code)) {
    code = code.replace(regex, token);
    changed = true;
  }
}

if (changed) {
  fs.writeFileSync(filePath, code, 'utf-8');
}

execSync(`npx eslint "${filePath}" --rule "tailwindcss/no-arbitrary-value: error"`, {
  stdio: 'pipe',
});

process.exit(0);

} catch (error) {
const failureLog = error.stdout?.toString() || error.stderr?.toString() || error.message;
console.error([Lint Pipeline Block] Stilregelverstoß:\n${failureLog});
process.exit(1);
}
});

`

Installieren Sie das Linter-Plugin im Projekt.

`bash
npm install -D eslint-plugin-tailwindcss

`

Gibt das Skript den Exit-Code 1 zurück, liest Claude Code das Fehlerprotokoll und korrigiert den Code im nächsten Durchlauf auf semantische Klassen. Das minimiert stundenlanges Frickeln an fehlerhaften Layouts in der QA-Phase.


Views und Geschäftslogik physisch trennen

Befiehlt man Claude Code, eine Benutzeroberfläche zu erstellen, wirft es häufig fetch-Funktionen, riesige Mock-Datenobjekte und JSX in einen einzigen Topf. Möchte man später eine echte API anbinden, muss man am Ende den gesamten Render-Code wieder herausreißen.

UI-Code muss nicht wissen, wie Zustandsänderungen gehandhabt werden. Es ist sicherer, ein Funktionsverzeichnis in vier Dateien zu unterteilen und das Datenschema im Voraus festzulegen.

Definieren Sie zuerst das Datenformat.

`typescript
// src/components/features/dashboard-card/schema.ts
import { z } from "zod";

export const MetricItemSchema = z.object({
id: z.string(),
label: z.string(),
value: z.string(),
changePercentage: z.number(),
trend: z.enum(["up", "down", "neutral"]),
});

export const DashboardCardSchema = z.object({
title: z.string().min(1),
metrics: z.array(MetricItemSchema),
});

export type DashboardCardData = z.infer;

export interface DashboardCardViewProps {
data: DashboardCardData;
isLoading?: boolean;
onActionClick?: (metricId: string) => void;
}

`

Unterbinden Sie beim Aufruf von Claude Code im Terminal jegliche Verwendung interner Zustände.

`bash
claude "Erstelle eine reine UI-Komponente src/components/features/dashboard-card/dashboard-card-view.tsx, die die DashboardCardViewProps aus src/components/features/dashboard-card/schema.ts implementiert. Verwende intern absolut kein useState, useEffect oder fetch, sondern baue sie rein responsiv unter ausschließlicher Nutzung der übergebenen Props und @/components/ui-Elemente."

`

Wickeln Sie die Datenanbindung in einen Hook ein. Halten Sie Mock-Daten und echte API-Aufrufe in derselben Struktur.

`typescript
// src/components/features/dashboard-card/use-dashboard-card.ts
import { useQuery } from "@tanstack/react-query";
import { DashboardCardData } from "./schema";

const MOCK_DATA: DashboardCardData = {
title: "Monatliche Aktivitätsmetriken",
metrics: [
{ id: "m-1", label: "Neuzugänge", value: "1.240", changePercentage: 12.5, trend: "up" },
{ id: "m-2", label: "Absprungrate", value: "2.1%", changePercentage: -0.4, trend: "down" },
],
};

export const useDashboardCard = (cardId: string, useMock = false) => {
return useQuery({
queryKey: ["dashboard-card", cardId],
queryFn: async () => {
if (useMock) {
return MOCK_DATA;
}
const res = await fetch(/api/dashboard/${cardId});
if (!res.ok) throw new Error("Fehler beim Abrufen der Daten");
return res.json();
},
});
};

`

Setzen Sie beide Teile in einer Container-Komponente zusammen.

`typescript
// src/components/features/dashboard-card/index.tsx
"use client";

import React from "react";
import { DashboardCardView } from "./dashboard-card-view";
import { useDashboardCard } from "./use-dashboard-card";

export function DashboardCardContainer({ cardId, useMock = false }: { cardId: string; useMock?: boolean }) {
const { data, isLoading } = useDashboardCard(cardId, useMock);

if (!data) return null;

return (
<DashboardCardView
data={data}
isLoading={isLoading}
onActionClick={(id) => console.log(id)}
/>
);
}

`

Vor dem Release des Backends lässt sich die UI mit useMock={true} verfeinern. Steht die API bereit, wird einfach das Flag entfernt. Die View-Datei muss dabei nicht ein einziges Mal angefasst werden.


Arbeitsbäume isolieren und Änderungen gezielt übernehmen

Führt man im Terminal längere Gespräche mit dem Modell und bastelt an der UI, findet man oft modifizierte globale Konfigurationsdateien oder temporäre Dateien im Verzeichnis vor. Es ist ratsam, die eigene Arbeitsumgebung unberührt zu lassen und Experimente in einem separaten Verzeichnis durchzuführen.

Mit Git Worktrees lässt sich Claude Code in einem völlig isolierten Ordner ausführen.

`bash
git worktree add ../saas-ui-sandbox -b experiment/ai-dashboard-ui
cd ../saas-ui-sandbox
claude

`

Schlägt das Experiment fehl, kann der Ordner ohne Bedenken gelöscht werden.

`bash
cd ../saas-platform
git worktree remove ../saas-ui-sandbox --force
git branch -D experiment/ai-dashboard-ui

`

Liefert das Ergebnis das gewünschte Resultat, sollte der Branch nicht blind gemergt werden; holen Sie stattdessen nur die gewünschten Code-Snippets der View-Datei im interaktiven Modus ab.

`bash
git checkout main
git checkout -p experiment/ai-dashboard-ui -- src/components/features/dashboard-card/dashboard-card-view.tsx

`

Prüfen Sie die im Terminal angezeigten Code-Blöcke und bestätigen Sie gewünschte Änderungen mit y, während Sie unerwünschte Modifikationen mit n verwerfen.

Sobald eine Session fünf Turns überschreitet, verschwimmt der Kontext und das Modell beginnt Unsinn zu reden. Die Session sollte in solchen Momenten bereinigt werden:

  1. Typüberprüfung: Führen Sie nach der Erstellung einer einzelnen Komponente sofort npx tsc --noEmit aus. Erst wenn null Typfehler vorliegen, geht es zum nächsten Prompt.
  2. Kontextkomprimierung: Wird das Gespräch zu lang, hilft ein sofortiges /compact, um Token-Verschwendung zu vermeiden.
  3. Session leeren: Nach Abschluss der UI-Arbeit wird ein Commit erstellt und der Speicher mit /clear vollständig bereinigt. Bei Verwirrung hilft /rewind, um zum vorherigen Checkpoint zurückzukehren.

Dass ein Modell hervorragend generieren kann, bedeutet noch lange nicht, dass dieser Code produktionsreif ist. Wenn man den Eingangskanal mit CLAUDE.md verengt, den ausgegebenen Code mit Lifecycle Hooks validiert und den Workspace über Worktrees trennt, bleibt einem das nächtliche Aufräumen von KI-generiertem Code erspart.