Skip to content

Vollständige Skills-Referenz: Detaillierte Erklärung der 11 Skill-Bibliotheken

Was Sie nach diesem Kurs können

  • Schnelles Suchen und Verstehen des Inhalts und Zwecks aller 11 Skill-Bibliotheken
  • Korrekte Anwendung von Codierungsstandards, Architekturmustern und Best Practices während der Entwicklung
  • Wissen, wann Sie welche Skill zur Steigerung der Entwicklungseffizienz und Codequalität verwenden
  • Beherrschung von TDD-Workflows, Sicherheitsüberprüfungen, kontinuierlichem Lernen und anderen Schlüsselkompetenzen

Ihre aktuellen Herausforderungen

面对项目中的 11 个技能库,您 könnten:

  • Nicht alle Skills erinnern: coding-standards, backend-patterns, security-review... Welche Skills wann verwenden?
  • Nicht wissen, wie man anwendet: Die Skills erwähnen unveränderliche Muster, TDD-Abläufe, aber wie genau funktioniert das?
  • Nicht wissen, wen man um Hilfe bittet: Welchen Skill bei Sicherheitsproblemen verwenden? Welchen bei der Backend-Entwicklung?
  • Verhältnis Skills zu Agents: Was ist der Unterschied zwischen Skills und Agents? Wann verwendet man Agenten, wann Skills?

Diese Referenzdokumentation hilft Ihnen, den Inhalt, Anwendungsszenarien und Verwendungsmethoden jeder Skill umfassend zu verstehen.


Skills-Übersicht

Everything Claude Code enthält 11 Skill-Bibliotheken, jede mit klaren Zielen und Anwendungsszenarien:

Skill-BibliothekZielPrioritätAnwendungsszenarien
coding-standardsEinheitliche Codierungsstandards, Best PracticesP0Allgemeines Codieren, TypeScript/JavaScript/React
backend-patternsBackend-Architekturmuster, API-DesignP0Node.js, Express, Next.js API-Routen-Entwicklung
frontend-patternsFrontend-Entwicklungsmuster, Performance-OptimierungP0React, Next.js, Zustandsverwaltung
tdd-workflowTestgetriebene Entwicklungs-WorkflowsP0Neue Funktionen, Bug-Fixes, Refactoring
security-reviewSicherheitsüberprüfung und SchwachstellenerkennungP0Authentifizierung/Autorisierung, Eingabevalidierung, Verarbeitung sensibler Daten
continuous-learningAutomatische Extraktion wiederverwendbarer MusterP1Langfristige Projekte, Wissensakkumulation
strategic-compactStrategische KontextkomprimierungP1Lange Sitzungen, komplexe Aufgaben
eval-harnessEvaluationsgetriebenes Entwicklungs-FrameworkP1AI-Entwicklungsevaluierung, Zuverlässigkeitstests
verification-loopUmfassendes VerifikationssystemP1PR-Vorverifizierung, Qualitätsprüfung
project-guidelines-exampleBeispiel für ProjektrichtlinienP2Benutzerdefinierte Projektspezifikationen
clickhouse-ioClickHouse-AnalysenmusterP2Hochleistungsanalyseabfragen

Skills vs Agents

Skills sind Workflow-Definitionen und Wissensdatenbanken, die Muster, Best Practices und Spezifikationsrichtlinien bereitstellen.

Agents sind spezialisierte Unter-Agenten, die komplexe Aufgaben in spezifischen Bereichen ausführen (wie Planung, Überprüfung, Debugging).

Beide ergänzen sich gegenseitig: Skills stellen den Wissensrahmen bereit, Agents führen spezifische Aufgaben aus.


1. coding-standards (Codierungsstandards)

Kernprinzipien

1. Lesbarkeit hat Vorrang

  • Code wird häufiger gelesen als geschrieben
  • Klare Variablen- und Funktionsbenennung
  • Selbsterklärender Code ist besser als Kommentare
  • Einheitliches Format

2. KISS-Prinzip (Keep It Simple, Stupid)

  • Verwenden Sie die einfachste wirksame Lösung
  • Vermeiden Sie Over-Engineering
  • Keine vorzeitige Optimierung
  • Verständlichkeit > schlauber Code

3. DRY-Prinzip (Don't Repeat Yourself)

  • Extrahieren Sie gemeinsame Logik in Funktionen
  • Erstellen Sie wiederverwendbare Komponenten
  • Teilen Sie Utility-Funktionen modulübergreifend
  • Vermeiden Sie Copy-Paste-Programmierung

4. YAGNI-Prinzip (You Aren't Gonna Need It)

  • Erstellen Sie keine Funktionen, bevor Sie sie brauchen
  • Vermeiden Sie spekulative Verallgemeinerung
  • Fügen Sie nur bei Bedarf Komplexität hinzu
  • Beginnen Sie einfach, refaktorisieren Sie bei Bedarf

Unveränderliches Muster (CRITICAL)

Wichtige Regel

Erstellen Sie immer neue Objekte, ändern Sie niemals vorhandene Objekte! Dies ist eines der wichtigsten Prinzipien der Codequalität.

❌ Falscher Ansatz: Objekt direkt ändern

javascript
function updateUser(user, name) {
  user.name = name  // MUTATION!
  return user
}

✅ Richtiger Ansatz: Neues Objekt erstellen

javascript
function updateUser(user, name) {
  return {
    ...user,
    name
  }
}

TypeScript/JavaScript Best Practices

Variablennamen

typescript
// ✅ GUT: Beschreibende Benennung
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000

// ❌ SCHLECHT: Unklare Benennung
const q = 'election'
const flag = true
const x = 1000

Funktionsnamen

typescript
// ✅ GUT: Verb-Substantiv-Muster
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }

// ❌ SCHLECHT: Unklar oder nur Substantive
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }

Fehlerbehandlung

typescript
// ✅ GUT: Umfassende Fehlerbehandlung
async function fetchData(url: string) {
  try {
    const response = await fetch(url)

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }

    return await response.json()
  } catch (error) {
    console.error('Fetch failed:', error)
    throw new Error('Failed to fetch data')
  }
}

// ❌ SCHLECHT: Keine Fehlerbehandlung
async function fetchData(url) {
  const response = await fetch(url)
  return response.json()
}

Parallele Ausführung

typescript
// ✅ GUT: Parallele Ausführung wo möglich
const [users, markets, stats] = await Promise.all([
  fetchUsers(),
  fetchMarkets(),
  fetchStats()
])

// ❌ SCHLECHT: Unnötige sequenzielle Ausführung
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()

React Best Practices

Komponentenstruktur

typescript
// ✅ GUT: Funktionskomponente mit Typen
interface ButtonProps {
  children: React.ReactNode
  onClick: () => void
  disabled?: boolean
  variant?: 'primary' | 'secondary'
}

export function Button({
  children,
  onClick,
  disabled = false,
  variant = 'primary'
}: ButtonProps) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`btn btn-${variant}`}
    >
      {children}
    </button>
  )
}

// ❌ SCHLECHT: Keine Typen, unklare Struktur
export function Button(props) {
  return <button onClick={props.onClick}>{props.children}</button>
}

Benutzerdefinierte Hooks

typescript
// ✅ GUT: Wiederverwendbarer benutzerdefinierter Hook
export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => clearTimeout(handler)
  }, [value, delay])

  return debouncedValue
}

// Verwendung
const debouncedQuery = useDebounce(searchQuery, 500)

Zustandsaktualisierung

typescript
// ✅ GUT: Funktionale Zustandsaktualisierung
const [count, setCount] = useState(0)

// Aktualisierung basierend auf vorherigem Zustand
setCount(prev => prev + 1)

// ❌ SCHLECHT: Direkter Zustandsbezug
setCount(count + 1)  // Könnte in asynchronen Szenarien veraltet sein

API-Design-Standards

REST-API-Konventionen

GET    /api/markets              # Alle Märkte auflisten
GET    /api/markets/:id          # Bestimmten Markt abrufen
POST   /api/markets              # Neuen Markt erstellen
PUT    /api/markets/:id          # Markt aktualisieren (vollständig)
PATCH  /api/markets/:id          # Markt aktualisieren (teilweise)
DELETE /api/markets/:id          # Markt löschen

# Abfrageparameter für Filterung
GET /api/markets?status=active&limit=10&offset=0

Antwortformat

typescript
// ✅ GUT: Konsistente Antwortstruktur
interface ApiResponse<T> {
  success: boolean
  data?: T
  error?: string
  meta?: {
    total: number
    page: number
    limit: number
  }
}

// Erfolgsantwort
return NextResponse.json({
  success: true,
  data: markets,
  meta: { total: 100, page: 1, limit: 10 }
})

// Fehlerantwort
return NextResponse.json({
  success: false,
  error: 'Invalid request'
}, { status: 400 })

Eingabevalidierung

typescript
import { z } from 'zod'

// ✅ GUT: Schema-Validierung
const CreateMarketSchema = z.object({
  name: z.string().min(1).max(200),
  description: z.string().min(1).max(2000),
  endDate: z.string().datetime(),
  categories: z.array(z.string()).min(1)
})

export async function POST(request: Request) {
  const body = await request.json()

  try {
    const validated = CreateMarketSchema.parse(body)
    // Mit validierten Daten fortfahren
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json({
        success: false,
        error: 'Validation failed',
        details: error.errors
      }, { status: 400 })
    }
  }
}

Dateiorganisation

Projektstruktur

src/
├── app/                    # Next.js App Router
│   ├── api/               # API-Routen
│   ├── markets/           # Marktseiten
│   └── (auth)/           # Authentifizierungsseiten (Routing-Gruppe)
├── components/            # React-Komponenten
│   ├── ui/               # Allgemeine UI-Komponenten
│   ├── forms/            # Formularkomponenten
│   └── layouts/          # Layout-Komponenten
├── hooks/                # Benutzerdefinierte React-Hooks
├── lib/                  # Utilities und Konfiguration
│   ├── api/             # API-Clients
│   ├── utils/           # Hilfsfunktionen
│   └── constants/       # Konstanten
├── types/                # TypeScript-Typen
└── styles/              # Globale Styles

Performance-Best Practices

Memoisierung

typescript
import { useMemo, useCallback } from 'react'

// ✅ GUT: Teure Berechnungen memoisieren
const sortedMarkets = useMemo(() => {
  return markets.sort((a, b) => b.volume - a.volume)
}, [markets])

// ✅ GUT: Callback-Funktionen memoisieren
const handleSearch = useCallback((query: string) => {
  setSearchQuery(query)
}, [])

Lazy Loading

typescript
import { lazy, Suspense } from 'react'

// ✅ GUT: Lazy Loading für schwere Komponenten
const HeavyChart = lazy(() => import('./HeavyChart'))

export function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <HeavyChart />
    </Suspense>
  )
}

Teststandards

Teststruktur (AAA-Muster)

typescript
test('calculates similarity correctly', () => {
  // Arrange (Vorbereiten)
  const vector1 = [1, 0, 0]
  const vector2 = [0, 1, 0]

  // Act (Ausführen)
  const similarity = calculateCosineSimilarity(vector1, vector2)

  // Assert (Bestätigen)
  expect(similarity).toBe(0)
})

Testnamen

typescript
// ✅ GUT: Beschreibende Testnamen
test('returns empty array when no markets match query', () => { })
test('throws error when OpenAI API key is missing', () => { })
test('falls back to substring search when Redis unavailable', () => { })

// ❌ SCHLECHT: Vage Testnamen
test('works', () => { })
test('test search', () => { })

Code-Geruchserkennung

1. Lange Funktionen

typescript
// ❌ SCHLECHT: Funktion über 50 Zeilen
function processMarketData() {
  // 100 Zeilen Code
}

// ✅ GUT: In kleine Funktionen aufteilen
function processMarketData() {
  const validated = validateData()
  const transformed = transformData(validated)
  return saveData(transformed)
}

2. Tiefe Verschachtelung

typescript
// ❌ SCHLECHT: 5+ Ebenen Verschachtelung
if (user) {
  if (user.isAdmin) {
    if (market) {
      if (market.isActive) {
        if (hasPermission) {
          // Etwas tun
        }
      }
    }
  }
}

// ✅ GUT: Vorzeitiges Return
if (!user) return
if (!user.isAdmin) return
if (!market) return
if (!market.isActive) return
if (!hasPermission) return

// Etwas tun

3. Magische Zahlen

typescript
// ❌ SCHLECHT: Unerklärte Zahlen
if (retryCount > 3) { }
setTimeout(callback, 500)

// ✅ GUT: Benannte Konstanten
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500

if (retryCount > MAX_RETRIES) { }
setTimeout(callback, DEBOUNCE_DELAY_MS)

2. backend-patterns (Backend-Muster)

API-Design-Muster

RESTful-API-Struktur

typescript
// ✅ Ressourcenbasierte URLs
GET    /api/markets                 # Ressourcen auflisten
GET    /api/markets/:id             # Einzelne Ressource abrufen
POST   /api/markets                 # Ressource erstellen
PUT    /api/markets/:id             # Ressource ersetzen
PATCH  /api/markets/:id             # Ressource aktualisieren
DELETE /api/markets/:id             # Ressource löschen

// ✅ Abfrageparameter für Filterung, Sortierung, Paginierung
GET /api/markets?status=active&sort=volume&limit=20&offset=0

Repository-Muster

typescript
// Datenzugriffslogik abstrahieren
interface MarketRepository {
  findAll(filters?: MarketFilters): Promise<Market[]>
  findById(id: string): Promise<Market | null>
  create(data: CreateMarketDto): Promise<Market>
  update(id: string, data: UpdateMarketDto): Promise<Market>
  delete(id: string): Promise<void>
}

class SupabaseMarketRepository implements MarketRepository {
  async findAll(filters?: MarketFilters): Promise<Market[]> {
    let query = supabase.from('markets').select('*')

    if (filters?.status) {
      query = query.eq('status', filters.status)
    }

    if (filters?.limit) {
      query = query.limit(filters.limit)
    }

    const { data, error } = await query

    if (error) throw new Error(error.message)
    return data
  }

  // Andere Methoden...
}

Service-Layer-Muster

typescript
// Geschäftslogik vom Datenzugang trennen
class MarketService {
  constructor(private marketRepo: MarketRepository) {}

  async searchMarkets(query: string, limit: number = 10): Promise<Market[]> {
    // Geschäftslogik
    const embedding = await generateEmbedding(query)
    const results = await this.vectorSearch(embedding, limit)

    // Vollständige Daten abrufen
    const markets = await this.marketRepo.findByIds(results.map(r => r.id))

    // Nach Ähnlichkeit sortieren
    return markets.sort((a, b) => {
      const scoreA = results.find(r => r.id === a.id)?.score || 0
      const scoreB = results.find(r => r.id === b.id)?.score || 0
      return scoreA - scoreB
    })
  }

  private async vectorSearch(embedding: number[], limit: number) {
    // Vektorsuche-Implementierung
  }
}

Middleware-Muster

typescript
// Request/Response-Verarbeitungspipeline
export function withAuth(handler: NextApiHandler): NextApiHandler {
  return async (req, res) => {
    const token = req.headers.authorization?.replace('Bearer ', '')

    if (!token) {
      return res.status(401).json({ error: 'Unauthorized' })
    }

    try {
      const user = await verifyToken(token)
      req.user = user
      return handler(req, res)
    } catch (error) {
      return res.status(401).json({ error: 'Invalid token' })
    }
  }
}

// Verwendung
export default withAuth(async (req, res) => {
  // Handler hat Zugriff auf req.user
})

Datenbankmuster

Abfrageoptimierung

typescript
// ✅ GUT: Nur benötigte Spalten auswählen
const { data } = await supabase
  .from('markets')
  .select('id, name, status, volume')
  .eq('status', 'active')
  .order('volume', { ascending: false })
  .limit(10)

// ❌ SCHLECHT: Alles auswählen
const { data } = await supabase
  .from('markets')
  .select('*')

N+1-Abfrage-Verhinderung

typescript
// ❌ SCHLECHT: N+1-Abfrage-Problem
const markets = await getMarkets()
for (const market of markets) {
  market.creator = await getUser(market.creator_id)  // N Abfragen
}

// ✅ GUT: Batch-Abfrage
const markets = await getMarkets()
const creatorIds = markets.map(m => m.creator_id)
const creators = await getUsers(creatorIds)  // 1 Abfrage
const creatorMap = new Map(creators.map(c => [c.id, c]))

markets.forEach(market => {
  market.creator = creatorMap.get(market.creator_id)
})

Transaktionsmuster

typescript
async function createMarketWithPosition(
  marketData: CreateMarketDto,
  positionData: CreatePositionDto
) {
  // Supabase-Transaktion verwenden
  const { data, error } = await supabase.rpc('create_market_with_position', {
    market_data: marketData,
    position_data: positionData
  })

  if (error) throw new Error('Transaction failed')
  return data
}

// SQL-Funktion in Supabase
CREATE OR REPLACE FUNCTION create_market_with_position(
  market_data jsonb,
  position_data jsonb
)
RETURNS jsonb
LANGUAGE plpgsql
AS $$
BEGIN
  -- Transaktion beginnt automatisch
  INSERT INTO markets VALUES (market_data);
  INSERT INTO positions VALUES (position_data);
  RETURN jsonb_build_object('success', true);
EXCEPTION
  WHEN OTHERS THEN
    -- Rollback erfolgt automatisch
    RETURN jsonb_build_object('success', false, 'error', SQLERRM);
END;
$$;

Caching-Strategien

Redis-Caching-Layer

typescript
class CachedMarketRepository implements MarketRepository {
  constructor(
    private baseRepo: MarketRepository,
    private redis: RedisClient
  ) {}

  async findById(id: string): Promise<Market | null> {
    // Zuerst Cache prüfen
    const cached = await this.redis.get(`market:${id}`)

    if (cached) {
      return JSON.parse(cached)
    }

    // Cache-Miss - aus Datenbank abrufen
    const market = await this.baseRepo.findById(id)

    if (market) {
      // 5 Minuten cachen
      await this.redis.setex(`market:${id}`, 300, JSON.stringify(market))
    }

    return market
  }

  async invalidateCache(id: string): Promise<void> {
    await this.redis.del(`market:${id}`)
  }
}

Fehlerbehandlungsmuster

Zentralisierter Fehler-Handler

typescript
class ApiError extends Error {
  constructor(
    public statusCode: number,
    public message: string,
    public isOperational = true
  ) {
    super(message)
    Object.setPrototypeOf(this, ApiError.prototype)
  }
}

export function errorHandler(error: unknown, req: Request): Response {
  if (error instanceof ApiError) {
    return NextResponse.json({
      success: false,
      error: error.message
    }, { status: error.statusCode })
  }

  if (error instanceof z.ZodError) {
    return NextResponse.json({
      success: false,
      error: 'Validation failed',
      details: error.errors
    }, { status: 400 })
  }

  // Unerwartete Fehler protokollieren
  console.error('Unexpected error:', error)

  return NextResponse.json({
    success: false,
    error: 'Internal server error'
  }, { status: 500 })
}

// Verwendung
export async function GET(request: Request) {
  try {
    const data = await fetchData()
    return NextResponse.json({ success: true, data })
  } catch (error) {
    return errorHandler(error, request)
  }
}

Exponentielles Backoff-Retry

typescript
async function fetchWithRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3
): Promise<T> {
  let lastError: Error

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn()
    } catch (error) {
      lastError = error as Error

      if (i < maxRetries - 1) {
        // Exponentielles Backoff: 1s, 2s, 4s
        const delay = Math.pow(2, i) * 1000
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }
  }

  throw lastError!
}

// Verwendung
const data = await fetchWithRetry(() => fetchFromAPI())

Authentifizierung und Autorisierung

JWT-Token-Verifizierung

typescript
import jwt from 'jsonwebtoken'

interface JWTPayload {
  userId: string
  email: string
  role: 'admin' | 'user'
}

export function verifyToken(token: string): JWTPayload {
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload
    return payload
  } catch (error) {
    throw new ApiError(401, 'Invalid token')
  }
}

export async function requireAuth(request: Request) {
  const token = request.headers.get('authorization')?.replace('Bearer ', '')

  if (!token) {
    throw new ApiError(401, 'Missing authorization token')
  }

  return verifyToken(token)
}

// In API-Route verwenden
export async function GET(request: Request) {
  const user = await requireAuth(request)

  const data = await getDataForUser(user.userId)

  return NextResponse.json({ success: true, data })
}

Rollenbasierte Zugriffssteuerung

typescript
type Permission = 'read' | 'write' | 'delete' | 'admin'

interface User {
  id: string
  role: 'admin' | 'moderator' | 'user'
}

const rolePermissions: Record<User['role'], Permission[]> = {
  admin: ['read', 'write', 'delete', 'admin'],
  moderator: ['read', 'write', 'delete'],
  user: ['read', 'write']
}

export function hasPermission(user: User, permission: Permission): boolean {
  return rolePermissions[user.role].includes(permission)
}

export function requirePermission(permission: Permission) {
  return async (request: Request) => {
    const user = await requireAuth(request)

    if (!hasPermission(user, permission)) {
      throw new ApiError(403, 'Insufficient permissions')
    }

    return user
  }
}

// Verwendung
export const DELETE = requirePermission('delete')(async (request: Request) => {
  // Handler mit Berechtigungsprüfung
})

Rate Limiting

Einfacher In-Memory-Rate-Limiter

typescript
class RateLimiter {
  private requests = new Map<string, number[]>()

  async checkLimit(
    identifier: string,
    maxRequests: number,
    windowMs: number
  ): Promise<boolean> {
    const now = Date.now()
    const requests = this.requests.get(identifier) || []

    // Alte Anfragen außerhalb des Fensters entfernen
    const recentRequests = requests.filter(time => now - time < windowMs)

    if (recentRequests.length >= maxRequests) {
      return false  // Rate-Limit überschritten
    }

    // Aktuelle Anfrage hinzufügen
    recentRequests.push(now)
    this.requests.set(identifier, recentRequests)

    return true
  }
}

const limiter = new RateLimiter()

export async function GET(request: Request) {
  const ip = request.headers.get('x-forwarded-for') || 'unknown'

  const allowed = await limiter.checkLimit(ip, 100, 60000)  // 100 Anfragen/Minute

  if (!allowed) {
    return NextResponse.json({
      error: 'Rate limit exceeded'
    }, { status: 429 })
  }

  // Mit Anfrage fortfahren
}

Hintergrundtasks und Warteschlangen

Einfaches Warteschlangenmuster

typescript
class JobQueue<T> {
  private queue: T[] = []
  private processing = false

  async add(job: T): Promise<void> {
    this.queue.push(job)

    if (!this.processing) {
      this.process()
    }
  }

  private async process(): Promise<void> {
    this.processing = true

    while (this.queue.length > 0) {
      const job = this.queue.shift()!

      try {
        await this.execute(job)
      } catch (error) {
        console.error('Job failed:', error)
      }
    }

    this.processing = false
  }

  private async execute(job: T): Promise<void> {
    // Aufgaben-Ausführungslogik
  }
}

// Für Markt-Indizierung
interface IndexJob {
  marketId: string
}

const indexQueue = new JobQueue<IndexJob>()

export async function POST(request: Request) {
  const { marketId } = await request.json()

  // Zur Warteschlange hinzufügen statt zu blockieren
  await indexQueue.add({ marketId })

  return NextResponse.json({ success: true, message: 'Job queued' })
}

Logging und Monitoring

Strukturiertes Logging

typescript
interface LogContext {
  userId?: string
  requestId?: string
  method?: string
  path?: string
  [key: string]: unknown
}

class Logger {
  log(level: 'info' | 'warn' | 'error', message: string, context?: LogContext) {
    const entry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      ...context
    }

    console.log(JSON.stringify(entry))
  }

  info(message: string, context?: LogContext) {
    this.log('info', message, context)
  }

  warn(message: string, context?: LogContext) {
    this.log('warn', message, context)
  }

  error(message: string, error: Error, context?: LogContext) {
    this.log('error', message, {
      ...context,
      error: error.message,
      stack: error.stack
    })
  }
}

const logger = new Logger()

// Verwendung
export async function GET(request: Request) {
  const requestId = crypto.randomUUID()

  logger.info('Fetching markets', {
    requestId,
    method: 'GET',
    path: '/api/markets'
  })

  try {
    const markets = await fetchMarkets()
    return NextResponse.json({ success: true, data: markets })
  } catch (error) {
    logger.error('Failed to fetch markets', error as Error, { requestId })
    return NextResponse.json({ error: 'Internal error' }, { status: 500 })
  }
}

3. frontend-patterns (Frontend-Muster)

Komponentenmuster

Komposition über Vererbung

typescript
// ✅ GUT: Komponentenkomposition
interface CardProps {
  children: React.ReactNode
  variant?: 'default' | 'outlined'
}

export function Card({ children, variant = 'default' }: CardProps) {
  return <div className={`card card-${variant}`}>{children}</div>
}

export function CardHeader({ children }: { children: React.ReactNode }) {
  return <div className="card-header">{children}</div>
}

export function CardBody({ children }: { children: React.ReactNode }) {
  return <div className="card-body">{children}</div>
}

// Verwendung
<Card>
  <CardHeader>Title</CardHeader>
  <CardBody>Content</CardBody>
</Card>

Compound Components

typescript
interface TabsContextValue {
  activeTab: string
  setActiveTab: (tab: string) => void
}

const TabsContext = createContext<TabsContextValue | undefined>(undefined)

export function Tabs({ children, defaultTab }: {
  children: React.ReactNode
  defaultTab: string
}) {
  const [activeTab, setActiveTab] = useState(defaultTab)

  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabsContext.Provider>
  )
}

export function TabList({ children }: { children: React.ReactNode }) {
  return <div className="tab-list">{children}</div>
}

export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
  const context = useContext(TabsContext)
  if (!context) throw new Error('Tab must be used within Tabs')

  return (
    <button
      className={context.activeTab === id ? 'active' : ''}
      onClick={() => context.setActiveTab(id)}
    >
      {children}
    </button>
  )
}

// Verwendung
<Tabs defaultTab="overview">
  <TabList>
    <Tab id="overview">Overview</Tab>
    <Tab id="details">Details</Tab>
  </TabList>
</Tabs>

Render Props-Muster

typescript
interface DataLoaderProps<T> {
  url: string
  children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode
}

export function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false))
  }, [url])

  return <>{children(data, loading, error)}</>
}

// Verwendung
<DataLoader<Market[]> url="/api/markets">
  {(markets, loading, error) => {
    if (loading) return <Spinner />
    if (error) return <Error error={error} />
    return <MarketList markets={markets!} />
  }}
</DataLoader>

Benutzerdefinierte Hooks-Muster

Zustandsverwaltungs-Hook

typescript
export function useToggle(initialValue = false): [boolean, () => void] {
  const [value, setValue] = useState(initialValue)

  const toggle = useCallback(() => {
    setValue(v => !v)
  }, [])

  return [value, toggle]
}

// Verwendung
const [isOpen, toggleOpen] = useToggle()

Asynchroner Datenabruf-Hook

typescript
interface UseQueryOptions<T> {
  onSuccess?: (data: T) => void
  onError?: (error: Error) => void
  enabled?: boolean
}

export function useQuery<T>(
  key: string,
  fetcher: () => Promise<T>,
  options?: UseQueryOptions<T>
) {
  const [data, setData] = useState<T | null>(null)
  const [error, setError] = useState<Error | null>(null)
  const [loading, setLoading] = useState(false)

  const refetch = useCallback(async () => {
    setLoading(true)
    setError(null)

    try {
      const result = await fetcher()
      setData(result)
      options?.onSuccess?.(result)
    } catch (err) {
      const error = err as Error
      setError(error)
      options?.onError?.(error)
    } finally {
      setLoading(false)
    }
  }, [fetcher, options])

  useEffect(() => {
    if (options?.enabled !== false) {
      refetch()
    }
  }, [key, refetch, options?.enabled])

  return { data, error, loading, refetch }
}

// Verwendung
const { data: markets, loading, error, refetch } = useQuery(
  'markets',
  () => fetch('/api/markets').then(r => r.json()),
  {
    onSuccess: data => console.log('Fetched', data.length, 'markets'),
    onError: err => console.error('Failed:', err)
  }
)

Debounce-Hook

typescript
export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => clearTimeout(handler)
  }, [value, delay])

  return debouncedValue
}

// Verwendung
const [searchQuery, setSearchQuery] = useState('')
const debouncedQuery = useDebounce(searchQuery, 500)

useEffect(() => {
  if (debouncedQuery) {
    performSearch(debouncedQuery)
  }
}, [debouncedQuery])

Zustandsverwaltungsmuster

Context + Reducer-Muster

typescript
interface State {
  markets: Market[]
  selectedMarket: Market | null
  loading: boolean
}

type Action =
  | { type: 'SET_MARKETS'; payload: Market[] }
  | { type: 'SELECT_MARKET'; payload: Market }
  | { type: 'SET_LOADING'; payload: boolean }

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'SET_MARKETS':
      return { ...state, markets: action.payload }
    case 'SELECT_MARKET':
      return { ...state, selectedMarket: action.payload }
    case 'SET_LOADING':
      return { ...state, loading: action.payload }
    default:
      return state
  }
}

const MarketContext = createContext<{
  state: State
  dispatch: Dispatch<Action>
} | undefined>(undefined)

export function MarketProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(reducer, {
    markets: [],
    selectedMarket: null,
    loading: false
  })

  return (
    <MarketContext.Provider value={{ state, dispatch }}>
      {children}
    </MarketContext.Provider>
  )
}

export function useMarkets() {
  const context = useContext(MarketContext)
  if (!context) throw new Error('useMarkets must be used within MarketProvider')
  return context
}

Performance-Optimierung

Memoisierung

typescript
// ✅ useMemo für teure Berechnungen
const sortedMarkets = useMemo(() => {
  return markets.sort((a, b) => b.volume - a.volume)
}, [markets])

// ✅ useCallback für Funktionen, die an untergeordnete Komponenten übergeben werden
const handleSearch = useCallback((query: string) => {
  setSearchQuery(query)
}, [])

// ✅ React.memo für reine Komponenten
export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
  return (
    <div className="market-card">
      <h3>{market.name}</h3>
      <p>{market.description}</p>
    </div>
  )
})

Code-Splitting und Lazy Loading

typescript
import { lazy, Suspense } from 'react'

// ✅ Lazy Loading für schwere Komponenten
const HeavyChart = lazy(() => import('./HeavyChart'))
const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))

export function Dashboard() {
  return (
    <div>
      <Suspense fallback={<ChartSkeleton />}>
        <HeavyChart data={data} />
      </Suspense>

      <Suspense fallback={null}>
        <ThreeJsBackground />
      </Suspense>
    </div>
  )
}

Virtualisierung langer Listen

typescript
import { useVirtualizer } from '@tanstack/react-virtual'

export function VirtualMarketList({ markets }: { markets: Market[] }) {
  const parentRef = useRef<HTMLDivElement>(null)

  const virtualizer = useVirtualizer({
    count: markets.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 100,  // Geschätzte Zeilenhöhe
    overscan: 5  // Zusätzlich gerenderte Elemente
  })

  return (
    <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
      <div
        style={{
          height: `${virtualizer.getTotalSize()}px`,
          position: 'relative'
        }}
      >
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.index}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualRow.size}px`,
              transform: `translateY(${virtualRow.start}px)`
            }}
          >
            <MarketCard market={markets[virtualRow.index]} />
          </div>
        ))}
      </div>
    </div>
  )
}

Formularverarbeitungsmuster

Kontrolliertes Formular mit Validierung

typescript
interface FormData {
  name: string
  description: string
  endDate: string
}

interface FormErrors {
  name?: string
  description?: string
  endDate?: string
}

export function CreateMarketForm() {
  const [formData, setFormData] = useState<FormData>({
    name: '',
    description: '',
    endDate: ''
  })

  const [errors, setErrors] = useState<FormErrors>({})

  const validate = (): boolean => {
    const newErrors: FormErrors = {}

    if (!formData.name.trim()) {
      newErrors.name = 'Name is required'
    } else if (formData.name.length > 200) {
      newErrors.name = 'Name must be under 200 characters'
    }

    if (!formData.description.trim()) {
      newErrors.description = 'Description is required'
    }

    if (!formData.endDate) {
      newErrors.endDate = 'End date is required'
    }

    setErrors(newErrors)
    return Object.keys(newErrors).length === 0
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()

    if (!validate()) return

    try {
      await createMarket(formData)
      // Erfolgshandling
    } catch (error) {
      // Fehlerbehandlung
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={formData.name}
        onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}
        placeholder="Market name"
      />
      {errors.name && <span className="error">{errors.name}</span>}

      {/* Andere Felder */}

      <button type="submit">Create Market</button>
    </form>
  )
}

Fehlergrenze-Muster

typescript
interface ErrorBoundaryState {
  hasError: boolean
  error: Error | null
}

export class ErrorBoundary extends React.Component<
  { children: React.ReactNode },
  ErrorBoundaryState
> {
  state: ErrorBoundaryState = {
    hasError: false,
    error: null
  }

  static getDerivedStateFromError(error: Error): ErrorBoundaryState {
    return { hasError: true, error }
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error boundary caught:', error, errorInfo)
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-fallback">
          <h2>Something went wrong</h2>
          <p>{this.state.error?.message}</p>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </div>
      )
    }

    return this.props.children
  }
}

// Verwendung
<ErrorBoundary>
  <App />
</ErrorBoundary>

Animationsmuster

Framer Motion Animationen

typescript
import { motion, AnimatePresence } from 'framer-motion'

// ✅ Listenanimationen
export function AnimatedMarketList({ markets }: { markets: Market[] }) {
  return (
    <AnimatePresence>
      {markets.map(market => (
        <motion.div
          key={market.id}
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: -20 }}
          transition={{ duration: 0.3 }}
        >
          <MarketCard market={market} />
        </motion.div>
      ))}
    </AnimatePresence>
  )
}

// ✅ Modal-Animationen
export function Modal({ isOpen, onClose, children }: ModalProps) {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          <motion.div
            className="modal-overlay"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            onClick={onClose}
          />
          <motion.div
            className="modal-content"
            initial={{ opacity: 0, scale: 0.9, y: 20 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.9, y: 20 }}
          >
            {children}
          </motion.div>
        </>
      )}
    </AnimatePresence>
  )
}

Barrierefreiheitsmuster

Tastaturnavigation

typescript
export function Dropdown({ options, onSelect }: DropdownProps) {
  const [isOpen, setIsOpen] = useState(false)
  const [activeIndex, setActiveIndex] = useState(0)

  const handleKeyDown = (e: React.KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault()
        setActiveIndex(i => Math.min(i + 1, options.length - 1))
        break
      case 'ArrowUp':
        e.preventDefault()
        setActiveIndex(i => Math.max(i - 1, 0))
        break
      case 'Enter':
        e.preventDefault()
        onSelect(options[activeIndex])
        setIsOpen(false)
        break
      case 'Escape':
        setIsOpen(false)
        break
    }
  }

  return (
    <div
      role="combobox"
      aria-expanded={isOpen}
      aria-haspopup="listbox"
      onKeyDown={handleKeyDown}
    >
      {/* Dropdown-Implementierung */}
    </div>
  )
}

Fokus-Management

typescript
export function Modal({ isOpen, onClose, children }: ModalProps) {
  const modalRef = useRef<HTMLDivElement>(null)
  const previousFocusRef = useRef<HTMLElement | null>(null)

  useEffect(() => {
    if (isOpen) {
      // Aktuelles Fokus-Element speichern
      previousFocusRef.current = document.activeElement as HTMLElement

      // Fokus zum Modal bewegen
      modalRef.current?.focus()
    } else {
      // Fokus beim Schließen wiederherstellen
      previousFocusRef.current?.focus()
    }
  }, [isOpen])

  return isOpen ? (
    <div
      ref={modalRef}
      role="dialog"
      aria-modal="true"
      tabIndex={-1}
      onKeyDown={e => e.key === 'Escape' && onClose()}
    >
      {children}
    </div>
  ) : null
}

4. tdd-workflow (TDD-Workflow)

Wann aktivieren

  • Neue Funktionen oder Features schreiben
  • Bugs oder Probleme beheben
  • Bestehenden Code refaktorieren
  • API-Endpunkte hinzufügen
  • Neue Komponenten erstellen

Kernprinzipien

1. Test zuerst

Schreiben Sie immer zuerst Tests, dann Code, damit die Tests bestanden werden.

2. Abdeckungsanforderungen

  • Mindestens 80% Abdeckung (Unit + Integration + E2E)
  • Alle Randfälle abdecken
  • Fehlerszenarien testen
  • Grenzwerte validieren

3. Testtypen

Unit-Tests
  • Unabhängige Funktionen und Utility-Funktionen
  • Komponentenlogik
  • Reine Funktionen
  • Hilfsfunktionen und Utilities
Integrationstests
  • API-Endpunkte
  • Datenbankoperationen
  • Dienstinteraktionen
  • Externe API-Aufrufe
E2E-Tests (Playwright)
  • Wichtige Benutzerabläufe
  • Vollständige Workflows
  • Browser-Automatisierung
  • UI-Interaktionen

TDD-Workflow-Schritte

Schritt 1: Benutzerreise schreiben

Als [Rolle] möchte ich [Aktion], damit [Vorteil]

Beispiel:
Als Benutzer möchte ich Märkte semantisch durchsuchen,
damit ich auch ohne genaue Schlüsselwörter relevante Märkte finde.

Schritt 2: Testfälle generieren

Erstellen Sie umfassende Testfälle für jede Benutzerreise:

typescript
describe('Semantic Search', () => {
  it('returns relevant markets for query', async () => {
    // Test-Implementierung
  })

  it('handles empty query gracefully', async () => {
    // Randfall testen
  })

  it('falls back to substring search when Redis unavailable', async () => {
    // Fallback-Verhalten testen
  })

  it('sorts results by similarity score', async () => {
    // Sortierlogik testen
  })
})

Schritt 3: Tests ausführen (sollten fehlschlagen)

bash
npm test
# Tests sollten fehlschlagen - wir haben noch nicht implementiert

Schritt 4: Code implementieren

Schreiben Sie minimalen Code, damit die Tests bestanden werden:

typescript
// Durch Tests gesteuerte Implementierung
export async function searchMarkets(query: string) {
  // Implementierung hier
}

Schritt 5: Tests erneut ausführen

bash
npm test
# Tests sollten jetzt bestehen

Schritt 6: Refactoring

Codequalität verbessern, während Tests grün bleiben:

  • Duplizierten Code entfernen
  • Benennung verbessern
  • Performance optimieren
  • Lesbarkeit erhöhen

Schritt 7: Abdeckung validieren

bash
npm run test:coverage
# Validieren, dass 80%+ Abdeckung erreicht ist

Testmuster

Unit-Test-Muster (Jest/Vitest)

typescript
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'

describe('Button Component', () => {
  it('renders with correct text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('calls onClick when clicked', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click</Button>)

    fireEvent.click(screen.getByRole('button'))

    expect(handleClick).toHaveBeenCalledTimes(1)
  })

  it('is disabled when disabled prop is true', () => {
    render(<Button disabled>Click</Button>)
    expect(screen.getByRole('button')).toBeDisabled()
  })
})

API-Integrationstest-Muster

typescript
import { NextRequest } from 'next/server'
import { GET } from './route'

describe('GET /api/markets', () => {
  it('returns markets successfully', async () => {
    const request = new NextRequest('http://localhost/api/markets')
    const response = await GET(request)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.success).toBe(true)
    expect(Array.isArray(data.data)).toBe(true)
  })

  it('validates query parameters', async () => {
    const request = new NextRequest('http://localhost/api/markets?limit=invalid')
    const response = await GET(request)

    expect(response.status).toBe(400)
  })

  it('handles database errors gracefully', async () => {
    // Datenbankausfall simulieren
    const request = new NextRequest('http://localhost/api/markets')
    // Fehlerbehandlung testen
  })
})

E2E-Test-Muster (Playwright)

typescript
import { test, expect } from '@playwright/test'

test('user can search and filter markets', async ({ page }) => {
  // Zu Marktseite navigieren
  await page.goto('/')
  await page.click('a[href="/markets"]')

  // Validieren, dass Seite geladen ist
  await expect(page.locator('h1')).toContainText('Markets')

  // Märkte suchen
  await page.fill('input[placeholder="Search markets"]', 'election')

  // Auf Debounce und Ergebnisse warten
  await page.waitForTimeout(600)

  // Validieren, dass Suchergebnisse angezeigt werden
  const results = page.locator('[data-testid="market-card"]')
  await expect(results).toHaveCount(5, { timeout: 5000 })

  // Validieren, dass Ergebnisse Suchbegriff enthalten
  const firstResult = results.first()
  await expect(firstResult).toContainText('election', { ignoreCase: true })

  // Nach Status filtern
  await page.click('button:has-text("Active")')

  // Gefilterte Ergebnisse validieren
  await expect(results).toHaveCount(3)
})

test('user can create a new market', async ({ page }) => {
  // Zuerst einloggen
  await page.goto('/creator-dashboard')

  // Markterstellungsformular ausfüllen
  await page.fill('input[name="name"]', 'Test Market')
  await page.fill('textarea[name="description"]', 'Test description')
  await page.fill('input[name="endDate"]', '2025-12-31')

  // Formular absenden
  await page.click('button[type="submit"]')

  // Erfolgsnachricht validieren
  await expect(page.locator('text=Market created successfully')).toBeVisible()

  // Umleitung zur Marktseite validieren
  await expect(page).toHaveURL(/\/markets\/test-market/)
})

Testdateiorganisation

src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.test.tsx          # Unit-Tests
│   │   └── Button.stories.tsx       # Storybook
│   └── MarketCard/
│       ├── MarketCard.tsx
│       └── MarketCard.test.tsx
├── app/
│   └── api/
│       └── markets/
│           ├── route.ts
│           └── route.test.ts         # Integrationstests
└── e2e/
    ├── markets.spec.ts               # E2E-Tests
    ├── trading.spec.ts
    └── auth.spec.ts

Externe Services mocken

Supabase-Mock

typescript
jest.mock('@/lib/supabase', () => ({
  supabase: {
    from: jest.fn(() => ({
      select: jest.fn(() => ({
        eq: jest.fn(() => Promise.resolve({
          data: [{ id: 1, name: 'Test Market' }],
          error: null
        }))
      }))
    }))
  }
}))

Redis-Mock

typescript
jest.mock('@/lib/redis', () => ({
  searchMarketsByVector: jest.fn(() => Promise.resolve([
    { slug: 'test-market', similarity_score: 0.95 }
  ])),
  checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))
}))

OpenAI-Mock

typescript
jest.mock('@/lib/openai', () => ({
  generateEmbedding: jest.fn(() => Promise.resolve(
    new Array(1536).fill(0.1) // Mock für 1536-dimensionales Embedding
  ))
}))

Testabdeckungsvalidierung

Abdeckungsbericht ausführen

bash
npm run test:coverage

Abdeckungsschwellenwerte

json
{
  "jest": {
    "coverageThresholds": {
      "global": {
        "branches": 80,
        "functions": 80,
        "lines": 80,
        "statements": 80
      }
    }
  }
}

Häufige Testfehler

❌ Fehler: Implementierungsdetails testen

typescript
// Internen Zustand nicht testen
expect(component.state.count).toBe(5)

✅ Richtig: Benutzer Sichtbares Verhalten testen

typescript
// Was der Benutzer sieht
expect(screen.getByText('Count: 5')).toBeInTheDocument()

❌ Fehler: Selektoren anfällig für Änderungen

typescript
// Brechen leicht
await page.click('.css-class-xyz')

✅ Richtig: Semantische Selektoren

typescript
 resilient gegenüber Änderungen
await page.click('button:has-text("Submit")')
await page.click('[data-testid="submit-button"]')

❌ Fehler: Keine Testisolierung

typescript
// Tests voneinander abhängig
test('creates user', () => { /* ... */ })
test('updates same user', () => { /* hängt vom vorherigen Test ab */ })

✅ Richtig: Unabhängige Tests

typescript
// Jeder Test setzt seine eigenen Daten
test('creates user', () => {
  const user = createTestUser()
  // Testlogik
})

test('updates user', () => {
  const user = createTestUser()
  // Aktualisierungslogik
})

Kontinuierliches Testen

Watch-Modus während der Entwicklung

bash
npm test -- --watch
# Tests laufen automatisch bei Dateiänderungen

Pre-Commit-Hooks

bash
# Vor jedem Commit ausführen
npm test && npm run lint

CI/CD-Integration

yaml
# GitHub Actions
- name: Run Tests
  run: npm test -- --coverage
- name: Upload Coverage
  uses: codecov/codecov-action@v3

Best Practices

  1. Zuerst Tests schreiben - Immer TDD
  2. Ein Assertion pro Test - Fokus auf ein Verhalten
  3. Beschreibende Testnamen - Erklären, was getestet wird
  4. Arrange-Act-Assert - Klare Teststruktur
  5. Externe Abhängigkeiten mocken - Unit-Tests isolieren
  6. Randfälle testen - Null, undefined, leer, große Werte
  7. Fehlerpfade testen - Nicht nur Happy Path
  8. Tests schnell halten - Unit-Tests < 50ms
  9. Nach Tests aufräumen - Keine Nebenwirkungen
  10. Abdeckungsberichte prüfen - Lücken identifizieren

Erfolgskriterien

  • 80%+ Codeabdeckung erreicht
  • Alle Tests bestehen (grün)
  • Keine übersprungenen oder deaktivierten Tests
  • Schnelle Testausführung (Unit-Tests < 30s)
  • E2E-Tests decken wichtige Benutzerabläufe ab
  • Tests fangen Bugs vor der Produktion ab

Erinnern Sie sich

Tests sind nicht optional. Sie sind ein Sicherheitsnetz, das selbstbewusstes Refactoring, schnelle Entwicklung und Produktionszuverlässigkeit ermöglicht.


5. security-review (Sicherheitsüberprüfung)

Wann aktivieren

  • Authentifizierung oder Autorisierung implementieren
  • Benutzereingaben oder Dateiuploads verarbeiten
  • Neue API-Endpunkte erstellen
  • Schlüssel oder Anmeldeinformationen verarbeiten
  • Zahlungsfunktionen implementieren
  • Sensitive Daten speichern oder übertragen
  • Drittanbieter-APIs integrieren

Sicherheitscheckliste

1. Schlüsselverwaltung

❌ Niemals tun
typescript
const apiKey = "sk-proj-xxxxx"  // Hardcodierter Schlüssel
const dbPassword = "password123" // Im Quellcode
✅ Immer tun
typescript
const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL

// Schlüsselexistenz validieren
if (!apiKey) {
  throw new Error('OPENAI_API_KEY not configured')
}
Validierungsschritte
  • [ ] Keine hardcodierten API-Schlüssel, Token oder Passwörter
  • [ ] Alle Schlüssel in Umgebungsvariablen
  • [ ] .env.local in .gitignore
  • [ ] Keine Schlüssel im Git-Verlauf
  • [ ] Produktionsschlüssel auf Hosting-Plattform (Vercel, Railway)

2. Eingabevalidierung

Benutzereingaben immer validieren
typescript
import { z } from 'zod'

// Validierungsschema definieren
const CreateUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
  age: z.number().int().min(0).max(150)
})

// Vor Verarbeitung validieren
export async function createUser(input: unknown) {
  try {
    const validated = CreateUserSchema.parse(input)
    return await db.users.create(validated)
  } catch (error) {
    if (error instanceof z.ZodError) {
      return { success: false, errors: error.errors }
    }
    throw error
  }
}
Dateiupload-Validierung
typescript
function validateFileUpload(file: File) {
  // Größenprüfung (5 MB Maximum)
  const maxSize = 5 * 1024 * 1024
  if (file.size > maxSize) {
    throw new Error('File too large (max 5MB)')
  }

  // Typprüfung
  const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
  if (!allowedTypes.includes(file.type)) {
    throw new Error('Invalid file type')
  }

  // Erweiterungsprüfung
  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
  const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
  if (!extension || !allowedExtensions.includes(extension)) {
    throw new Error('Invalid file extension')
  }

  return true
}
Validierungsschritte
  • [ ] Alle Benutzereingaben mit Schema validiert
  • [ ] Dateiuploads eingeschränkt (Größe, Typ, Erweiterung)
  • [ ] Benutzereingaben nicht direkt in Abfragen verwenden
  • [ ] Whitelist-Validierung (nicht Blacklist)
  • [ ] Fehlermeldungen geben keine sensiblen Informationen preis

3. SQL-Injection-Verhinderung

❌ Niemals SQL verketten
typescript
// Gefährlich - SQL-Injection-Schwachstelle
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
✅ Immer parametrisierte Abfragen verwenden
typescript
// Sicher - parametrisierte Abfrage
const { data } = await supabase
  .from('users')
  .select('*')
  .eq('email', userEmail)

// Oder rohes SQL verwenden
await db.query(
  'SELECT * FROM users WHERE email = $1',
  [userEmail]
)
Validierungsschritte
  • [ ] Alle Datenbankabfragen verwenden parametrisierte Abfragen
  • [ ] Keine String-Verkettung in SQL
  • [ ] ORM/Query-Builder korrekt verwenden
  • [ ] Supabase-Abfragen korrekt bereinigt

4. Authentifizierung und Autorisierung

JWT-Token-Verarbeitung
typescript
// ❌ Falsch: localStorage (anfällig für XSS)
localStorage.setItem('token', token)

// ✅ Richtig: httpOnly cookies
res.setHeader('Set-Cookie',
  `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
Autorisierungsprüfung
typescript
export async function deleteUser(userId: string, requesterId: string) {
  // Immer zuerst Autorisierung validieren
  const requester = await db.users.findUnique({
    where: { id: requesterId }
  })

  if (requester.role !== 'admin') {
    return NextResponse.json(
      { error: 'Unauthorized' },
      { status: 403 }
    )
  }

  // Mit Löschung fortfahren
  await db.users.delete({ where: { id: userId } })
}
Row Level Security (Supabase)
sql
-- RLS auf allen Tabellen aktivieren
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

-- Benutzer können nur ihre eigenen Daten sehen
CREATE POLICY "Users view own data"
  ON users FOR SELECT
  USING (auth.uid() = id);

-- Benutzer können nur ihre eigenen Daten aktualisieren
CREATE POLICY "Users update own data"
  ON users FOR UPDATE
  USING (auth.uid() = id);
Validierungsschritte
  • [ ] Token in httpOnly cookies (nicht localStorage)
  • [ ] Autorisierungsprüfung vor sensiblen Operationen
  • [ ] Row Level Security in Supabase aktiviert
  • [ ] Rollenbasierte Zugriffssteuerung implementiert
  • [ ] Sichere Sitzungsverwaltung

5. XSS-Verhinderung

HTML bereinigen
typescript
import DOMPurify from 'isomorphic-dompurify'

// Benutzer bereitgestelltes HTML immer bereinigen
function renderUserContent(html: string) {
  const clean = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
    ALLOWED_ATTR: []
  })
  return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
Content Security Policy
typescript
// next.config.js
const securityHeaders = [
  {
    key: 'Content-Security-Policy',
    value: `
      default-src 'self';
      script-src 'self' 'unsafe-eval' 'unsafe-inline';
      style-src 'self' 'unsafe-inline';
      img-src 'self' data: https:;
      font-src 'self';
      connect-src 'self' https://api.example.com;
    `.replace(/\s{2,}/g, ' ').trim()
  }
]
Validierungsschritte
  • [ ] Benutzer bereitgestelltes HTML bereinigt
  • [ ] CSP-Header konfiguriert
  • [ ] Keine unvalidierte dynamische Inhaltswiedergabe
  • [ ] React-interne XSS-Schutz verwenden

6. CSRF-Schutz

CSRF-Token
typescript
import { csrf } from '@/lib/csrf'

export async function POST(request: Request) {
  const token = request.headers.get('X-CSRF-Token')

  if (!csrf.verify(token)) {
    return NextResponse.json(
      { error: 'Invalid CSRF token' },
      { status: 403 }
    )
  }

  // Anfrage verarbeiten
}
SameSite Cookies
typescript
res.setHeader('Set-Cookie',
  `session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
Validierungsschritte
  • [ ] CSRF-Token bei Zustandsänderungsoperationen
  • [ ] Alle Cookies mit SameSite=Strict
  • [ ] Double Submit Cookie-Muster implementiert

7. Rate Limiting

API-Rate Limiting
typescript
import rateLimit from 'express-rate-limit'

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 Minuten
  max: 100, // 100 Anfragen pro Fenster
  message: 'Too many requests'
})

// Auf Route anwenden
app.use('/api/', limiter)
Teure Operationen
typescript
// Aggressives Rate Limiting für Suche
const searchLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 Minute
  max: 10, // 10 Anfragen pro Minute
  message: 'Too many search requests'
})

app.use('/api/search', searchLimiter)
Validierungsschritte
  • [ ] Rate Limiting auf allen API-Endpunkten
  • [ ] Strengere Limits auf teure Operationen
  • [ ] IP-basiertes Rate Limiting
  • [ ] Benutzerbasiertes Rate Limiting (authentifiziert)

8. Exposition sensibler Daten

Protokollierung
typescript
// ❌ Falsch: Sensible Daten protokollieren
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })

// ✅ Richtig: Sensible Daten redigieren
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
Fehlermeldungen
typescript
// ❌ Falsch: Interne Details exponieren
catch (error) {
  return NextResponse.json(
    { error: error.message, stack: error.stack },
    { status: 500 }
  )
}

// ✅ Richtig: Generische Fehlermeldungen
catch (error) {
  console.error('Internal error:', error)
  return NextResponse.json(
    { error: 'An error occurred. Please try again.' },
    { status: 500 }
  )
}
Validierungsschritte
  • [ ] Keine Passwörter, Token oder Schlüssel in Protokollen
  • [ ] Generische Fehlermeldungen für Benutzer
  • [ ] Detaillierte Fehler in Serverprotokollen
  • [ ] Keine Stack-Traces für Benutzer

9. Blockchain-Sicherheit (Solana)

Wallet-Verifizierung
typescript
import { verify } from '@solana/web3.js'

async function verifyWalletOwnership(
  publicKey: string,
  signature: string,
  message: string
) {
  try {
    const isValid = verify(
      Buffer.from(message),
      Buffer.from(signature, 'base64'),
      Buffer.from(publicKey, 'base64')
    )
    return isValid
  } catch (error) {
    return false
  }
}
Transaktionsverifizierung
typescript
async function verifyTransaction(transaction: Transaction) {
  // Empfänger verifizieren
  if (transaction.to !== expectedRecipient) {
    throw new Error('Invalid recipient')
  }

  // Betrag verifizieren
  if (transaction.amount > maxAmount) {
    throw new Error('Amount exceeds limit')
  }

  // Verifizieren, dass Benutzer genügend Guthaben hat
  const balance = await getBalance(transaction.from)
  if (balance < transaction.amount) {
    throw new Error('Insufficient balance')
  }

  return true
}
Validierungsschritte
  • [ ] Wallet-Signatur verifiziert
  • [ ] Transaktionsdetails verifiziert
  • [ ] Guthabenprüfung vor Transaktion
  • [ ] Keine Blind-Transaktionssignaturen

10. Abhängigkeitssicherheit

Regelmäßige Updates
bash
# Schwachstellen prüfen
npm audit

# Automatisch behebbare Probleme beheben
npm audit fix

# Abhängigkeiten aktualisieren
npm update

# Veraltete Pakete prüfen
npm outdated
Lock-Dateien
bash
# Immer Lock-Dateien committen
git add package-lock.json

# Für reproduzierbare Builds in CI/CD
npm ci  # nicht npm install
Validierungsschritte
  • [ ] Abhängigkeiten sind aktuell
  • [ ] Keine bekannten Schwachstellen (npm audit clean)
  • [ ] Lock-Dateien committet
  • [ ] Dependabot auf GitHub aktiviert
  • [ ] Regelmäßige Sicherheitsupdates

Sicherheitstests

Automatisierte Sicherheitstests

typescript
// Authentifizierung testen
test('requires authentication', async () => {
  const response = await fetch('/api/protected')
  expect(response.status).toBe(401)
})

// Autorisierung testen
test('requires admin role', async () => {
  const response = await fetch('/api/admin', {
    headers: { Authorization: `Bearer ${userToken}` }
  })
  expect(response.status).toBe(403)
})

// Eingabevalidierung testen
test('rejects invalid input', async () => {
  const response = await fetch('/api/users', {
    method: 'POST',
    body: JSON.stringify({ email: 'not-an-email' })
  })
  expect(response.status).toBe(400)
})

// Rate Limiting testen
test('enforces rate limits', async () => {
  const requests = Array(101).fill(null).map(() =>
    fetch('/api/endpoint')
  )

  const responses = await Promise.all(requests)
  const tooManyRequests = responses.filter(r => r.status === 429)

  expect(tooManyRequests.length).toBeGreaterThan(0)
})

Sicherheitscheckliste vor der Bereitstellung

Vor jeder Produktionsbereitstellung:

  • [ ] Schlüssel: Keine hardcodierten Schlüssel, alle in Umgebungsvariablen
  • [ ] Eingabevalidierung: Alle Benutzereingaben validiert
  • [ ] SQL-Injection: Alle Abfragen parametrisiert
  • [ ] XSS: Benutzerinhalte bereinigt
  • [ ] CSRF: Schutz aktiviert
  • [ ] Authentifizierung: Korrekte Token-Verarbeitung
  • [ ] Autorisierung: Rollenprüfungen vorhanden
  • [ ] Rate Limiting: Auf allen Endpunkten aktiviert
  • [ ] HTTPS: In Produktion erzwungen
  • [ ] Sicherheitsheader: CSP, X-Frame-Options konfiguriert
  • [ ] Fehlerbehandlung: Keine sensiblen Daten in Fehlern
  • [ ] Protokollierung: Keine sensiblen Daten in Protokollen
  • [ ] Abhängigkeiten: Aktuell, keine Schwachstellen
  • [ ] Row Level Security: In Supabase aktiviert
  • [ ] CORS: Korrekt konfiguriert
  • [ ] Dateiuploads: Validiert (Größe, Typ)
  • [ ] Wallet-Signaturen: Verifiziert (falls Blockchain)

Erinnern Sie sich

Sicherheit ist nicht optional. Eine einzige Schwachstelle kann die gesamte Plattform gefährden. Im Zweifel wählen Sie die vorsichtigere Seite.


6. continuous-learning (Kontinuierliches Lernen)

Funktionsweise

Dieser Skill wird als Stop hook am Ende jeder Sitzung ausgeführt:

  1. Sitzungsauswertung: Prüft, ob die Sitzung genügend Nachrichten hat (Standard: 10+)
  2. Musterverdeckung: Identifiziert extrahierbare Muster aus der Sitzung
  3. Skill-Extraktion: Speichert nützliche Muster in ~/.claude/skills/learned/

Konfiguration

Bearbeiten Sie config.json zur Anpassung:

json
{
  "min_session_length": 10,
  "extraction_threshold": "medium",
  "auto_approve": false,
  "learned_skills_path": "~/.claude/skills/learned/",
  "patterns_to_detect": [
    "error_resolution",
    "user_corrections",
    "workarounds",
    "debugging_techniques",
    "project_specific"
  ],
  "ignore_patterns": [
    "simple_typos",
    "one_time_fixes",
    "external_api_issues"
  ]
}

Mustertypen

MusterBeschreibung
error_resolutionWie bestimmte Fehler gelöst werden
user_correctionsMuster aus Benutzerkorrekturen
workaroundsLösungen für Framework/Library-Quirks
debugging_techniquesEffektive Debugging-Methoden
project_specificProjektspezifische Konventionen

Hook-Einrichtung

Fügen Sie zu Ihrem ~/.claude/settings.json hinzu:

json
{
  "hooks": {
    "Stop": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "~/.claude/skills/continuous-learning/evaluate-session.sh"
      }]
    }]
  }
}

Warum Stop Hook verwenden?

  • Leichtgewicht: Läuft nur einmal am Ende der Sitzung
  • Nicht blockierend: Fügt keiner Nachricht Verzögerungen hinzu
  • Vollständiger Kontext: Hat Zugriff auf den kompletten Sitzungsverlauf

Verwandt

  • The Longform Guide - Abschnitt kontinuierliches Lernen
  • /learn Befehl - Manuelle Musterverarbeitung während einer Sitzung

7. strategic-compact (Strategische Komprimierung)

Warum strategische Komprimierung?

Automatische Komprimierung wird an beliebigen Punkten ausgelöst:

  • Meistens mitten in einer Aufgabe, verliert wichtigen Kontext
  • Kein Bewusstsein für logische Aufgabengrenzen
  • Kann komplexe Multi-Schritt-Operationen unterbrechen

Strategische Komprimierung an logischen Grenzen:

  • Nach Erkundung, vor Ausführung - Forschungskontext komprimieren, Implementierungsplan behalten
  • Nach Meilensteinen - Neuer Start für nächste Phase
  • Vor größeren Kontextwechseln - Forschungskontext vor anderen Aufgaben bereinigen

Funktionsweise

Das Skript suggest-compact.sh läuft auf PreToolUse (Edit/Write) und:

  1. Tool-Aufrufe verfolgen - Zählt Tool-Aufrufe in der Sitzung
  2. Schwellenerkennung - Schlägt bei konfigurierbarem Schwellenwert vor (Standard: 50 Aufrufe)
  3. Regelmäßige Erinnerungen - Erinnert alle 25 Aufrufe nach Erreichen des Schwellenwerts

Hook-Einrichtung

Fügen Sie zu Ihrem ~/.claude/settings.json hinzu:

json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "tool == \"Edit\" || tool == \"Write\"",
      "hooks": [{
        "type": "command",
        "command": "~/.claude/skills/strategic-compact/suggest-compact.sh"
      }]
    }]
  }
}

Konfiguration

Umgebungsvariablen:

  • COMPACT_THRESHOLD - Tool-Aufrufe vor erstem Vorschlag (Standard: 50)

Best Practices

  1. Nach Planung komprimieren - Nach Planabschluss neu beginnen
  2. Nach Debugging komprimieren - Fehlerlösungskontext vor Fortfahren bereinigen
  3. Nicht während Implementierung komprimieren - Kontext für verwandte Änderungen behalten
  4. Vorschläge lesen - Hook sagt Ihnen wann, Sie entscheiden ob

Verwandt

  • The Longform Guide - Abschnitt Token-Optimierung
  • Memory persistence hooks - Persistenz des Zustands nach Komprimierung

8. eval-harness (Evaluierungs-Harness)

Philosophie

Evaluationsgetriebene Entwicklung betrachtet Evaluierungen als "Unit-Tests für AI-Entwicklung":

  • Erwartetes Verhalten vor Implementierung definieren
  • Während der Entwicklung kontinuierlich Evaluierungen ausführen
  • Regressionen bei jeder Änderung verfolgen
  • Zuverlässigkeit mit pass@k-Metriken messen

Evaluierungstypen

Funktionsevaluationen

Testet Dinge, die Claude vorher nicht konnte:

markdown
[CAPABILITY EVAL: feature-name]
Task: Beschreibung dessen, was Claude erreichen soll
Success Criteria:
  - [ ] Kriterium1
  - [ ] Kriterium2
  - [ ] Kriterium3
Expected Output: Beschreibung des erwarteten Ergebnisses

Regressionsevaluationen

Stellt sicher, dass Änderungen vorhandene Funktionen nicht beschädigen:

markdown
[REGRESSION EVAL: feature-name]
Baseline: SHA oder Checkpoint-Name
Tests:
  - existing-test-1: PASS/FAIL
  - existing-test-2: PASS/FAIL
  - existing-test-3: PASS/FAIL
Result: X/Y bestanden (zuvor Y/Y)

Bewertertypen

1. Code-basierte Bewerters

Verwenden Sie deterministische Codeprüfungen:

bash
# Prüft, ob Datei erwartetes Muster enthält
grep -q "export function handleAuth" src/auth.ts && echo "PASS" || echo "FAIL"

# Prüft, ob Tests bestehen
npm test -- --testPathPattern="auth" && echo "PASS" || echo "FAIL"

# Prüft, ob Build erfolgreich ist
npm run build && echo "PASS" || echo "FAIL"

2. Modellbasierte Bewerters

Verwenden Sie Claude zur Bewertung offener Ausgaben:

markdown
[MODEL GRADER PROMPT]
Bewerten Sie folgende Codeänderung:
1. Löst sie das genannte Problem?
2. Ist sie gut strukturiert?
3. Werden Randfälle behandelt?
4. Ist Fehlerbehandlung angemessen?

Score: 1-5 (1=schlecht, 5=ausgezeichnet)
Reasoning: [Erklärung]

3. Manuelle Bewerters

Markiert für manuelle Überprüfung:

markdown
[HUMAN REVIEW REQUIRED]
Change: Beschreibung dessen, was geändert wurde
Reason: Warum manuelle Überprüfung benötigt wird
Risk Level: LOW/MEDIUM/HIGH

Metriken

pass@k

"Mindestens ein Erfolg in k Versuchen"

  • pass@1: Erfolgsrate beim ersten Versuch
  • pass@3: Erfolgsrate innerhalb von 3 Versuchen
  • Typisches Ziel: pass@3 > 90%

pass^k

"Alle k Versuche erfolgreich"

  • Höhere Zuverlässigkeitsschwelle
  • pass^3: 3 aufeinanderfolgende Erfolge
  • Für kritische Pfade

Evaluierungs-Workflow

1. Definition (vor Codierung)

markdown
## EVAL DEFINITION: feature-xyz

### Capability Evals
1. Kann neues Benutzerkonto erstellen
2. Kann E-Mail-Format validieren
3. Kann Passwort sicher hashen

### Regression Evals
1. Vorhandener Login funktioniert noch
2. Sitzungsverwaltung unverändert
3. Logout-Flow intakt

### Success Metrics
- pass@3 > 90% für Funktionsevaluationen
- pass^3 = 100% für Regressionsevaluationen

2. Implementierung

Code schreiben, der definierte Evaluationen besteht.

3. Evaluation

bash
# Funktionsevaluationen ausführen
[Run each capability eval, record PASS/FAIL]

# Regressionsevaluationen ausführen
npm test -- --testPathPattern="existing"

# Bericht generieren

4. Bericht

markdown
EVAL REPORT: feature-xyz
=======================

Capability Evals:
  create-user:     PASS (pass@1)
  validate-email:  PASS (pass@2)
  hash-password:   PASS (pass@1)
  Overall:         3/3 bestanden

Regression Evals:
  login-flow:      PASS
  session-mgmt:    PASS
  logout-flow:     PASS
  Overall:         3/3 bestanden

Metrics:
  pass@1: 67% (2/3)
  pass@3: 100% (3/3)

Status: READY FOR REVIEW

Integrationsmuster

Vor Implementierung

/eval define feature-name

Erstellt Evaluierungsdefinitionsdatei in .claude/evals/feature-name.md

Während Implementierung

/eval check feature-name

Führt aktuelle Evaluation aus und meldet Status

Nach Implementierung

/eval report feature-name

Generiert vollständigen Evaluierungsbericht

Evaluierungsspeicherung

Speichern Sie Evaluationen im Projekt:

.claude/
  evals/
    feature-xyz.md      # Evaluierungsdefinition
    feature-xyz.log     # Evaluierungsausführungs-Verlauf
    baseline.json       # Regressionsbaseline

Best Practices

  1. Evaluierungen vor Codierung definieren - Erzwingt klares Nachdenken über Erfolgskriterien
  2. Evaluationen häufig ausführen - Regressionen frühzeitig erkennen
  3. pass@k über Zeit verfolgen - Zuverlässigkeitstrends überwachen
  4. Code-Bewerter wenn möglich verwenden - Deterministisch > probabilistisch
  5. Sichere manuelle Überprüfung - Sicherheitsprüfungen niemals vollständig automatisieren
  6. Evaluationen schnell halten - Langsame Evaluierungen werden nicht ausgeführt
  7. Evaluationen mit Code versionieren - Evaluationen sind erstklassige Artefakte

Beispiel: Authentifizierung hinzufügen

markdown
## EVAL: add-authentication

### Phase 1: Define (10 min)
Capability Evals:
- [ ] User kann sich mit E-Mail/Passwort registrieren
- [ ] User kann sich mit gültigen Anmeldeinformationen einloggen
- [ ] Ungültige Anmeldeinformationen werden mit ordentlichem Fehler abgelehnt
- [ ] Sitzungen bleiben über Seitenladevorgänge hinweg bestehen
- [ ] Logout bereinigt Sitzung

Regression Evals:
- [ ] Öffentliche Routen immer noch zugänglich
- [ ] API-Antworten unverändert
- [ ] Datenbankschema kompatibel

### Phase 2: Implement (variiert)
[Code schreiben]

### Phase 3: Evaluate
Run: /eval check add-authentication

### Phase 4: Report
EVAL REPORT: add-authentication
===============================
Capability: 5/5 bestanden (pass@3: 100%)
Regression: 3/3 bestanden (pass^3: 100%)
Status: SHIP IT

9. verification-loop (Verifikationsschleife)

Wann verwenden

Rufen Sie diesen Skill auf, wenn:

  • Eine Funktion oder große Codeänderung abgeschlossen ist
  • Vor Erstellung eines PR
  • Wenn Sie sicherstellen möchten, dass Qualitätsprüfungen bestehen
  • Nach Refactoring

Verifikationsphasen

Phase 1: Build-Verifizierung

bash
# Prüfen, ob Projekt erstellt wird
npm run build 2>&1 | tail -20
# oder
pnpm build 2>&1 | tail -20

Wenn Build fehlschlägt, stoppen und vor dem Fortfahren beheben.

Phase 2: Typprüfung

bash
# TypeScript-Projekt
npx tsc --noEmit 2>&1 | head -30

# Python-Projekt
pyright . 2>&1 | head -30

Alle Typfehler melden. Kritische Fehler vor dem Fortfahren beheben.

Phase 3: Lint-Prüfung

bash
# JavaScript/TypeScript
npm run lint 2>&1 | head -30

# Python
ruff check . 2>&1 | head -30

Phase 4: Testsuite

bash
# Tests mit Abdeckung ausführen
npm run test -- --coverage 2>&1 | tail -50

# Abdeckungsschwellen prüfen
# Ziel: 80% Minimum

Bericht:

  • Gesamtanzahl Tests: X
  • Bestanden: X
  • Fehlgeschlagen: X
  • Abdeckung: X%

Phase 5: Sicherheits-Scan

bash
# Schlüssel prüfen
grep -rn "sk-" --include="*.ts" --include="*.js" . 2>/dev/null | head -10
grep -rn "api_key" --include="*.ts" --include="*.js" . 2>/dev/null | head -10

# console.log prüfen
grep -rn "console.log" --include="*.ts" --include="*.tsx" src/ 2>/dev/null | head -10

Phase 6: Diff-Überprüfung

bash
# Geänderte Inhalte anzeigen
git diff --stat
git diff HEAD~1 --name-only

Für jede geänderte Datei überprüfen:

  • Unerwartete Änderungen
  • Fehlende Fehlerbehandlung
  • Mögliche Randfälle

Ausgabeformat

Nach Ausführen aller Phasen Verifikationsbericht generieren:

VERIFICATION REPORT
=================

Build:     [PASS/FAIL]
Types:     [PASS/FAIL] (X errors)
Lint:      [PASS/FAIL] (X warnings)
Tests:     [PASS/FAIL] (X/Y bestanden, Z% Abdeckung)
Security:  [PASS/FAIL] (X Probleme)
Diff:      [X Dateien geändert]

Overall:   [READY/NOT READY] für PR

Issues to Fix:
1. ...
2. ...

Kontinuierlicher Modus

Für lange Sitzungen Verifizierung alle 15 Minuten oder nach großen Änderungen ausführen:

markdown
Psychischen Checkpoint setzen:
- Nach jeder Funktion
- Nach jeder Komponente
- Vor Wechsel zur nächsten Aufgabe

Run: /verify

Integration mit Hooks

Dieser Skill ergänzt PostToolUse-Hooks, bietet aber tiefere Verifizierung. Hooks fangen Probleme sofort; dieser Skill bietet umfassende Überprüfung.


10. project-guidelines-example (Projektrichtlinien-Beispiel)

Dies ist ein Beispiel für ein projektspezifischen Skill. Verwenden Sie es als Vorlage für Ihre eigenen Projekte.

Basierend auf einer echten Produktionsanwendung: Zenith - KI-gestützte Kundenentdeckungsplattform.

Wann verwenden

Beziehen Sie sich bei der Arbeit an einem bestimmten Projekt, für das es entworfen wurde, auf diesen Skill. Projektskills enthalten:

  • Architekturübersicht
  • Dateistruktur
  • Codierungsmuster
  • Testanforderungen
  • Deployment-Workflows

11. clickhouse-io (ClickHouse I/O)

Übersicht

ClickHouse ist ein spaltenorientiertes Datenbankverwaltungssystem für Online Analytical Processing (OLAP). Es ist für schnelle Analyseabfragen auf großen Datensätzen optimiert.

Wichtige Funktionen:

  • Spaltenorientierte Speicherung
  • Datenkomprimierung
  • Parallele Abfrageausführung
  • Verteilte Abfragen
  • Echtzeitanalyse

Tabellen-Design-Muster

MergeTree-Engine (am häufigsten)

sql
CREATE TABLE markets_analytics (
    date Date,
    market_id String,
    market_name String,
    volume UInt64,
    trades UInt32,
    unique_traders UInt32,
    avg_trade_size Float64,
    created_at DateTime
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, market_id)
SETTINGS index_granularity = 8192;

ReplacingMergeTree (Deduplizierung)

sql
-- Für Daten, die Duplikate haben können (z.B. aus mehreren Quellen)
CREATE TABLE user_events (
    event_id String,
    user_id String,
    event_type String,
    timestamp DateTime,
    properties String
) ENGINE = ReplacingMergeTree()
PARTITION BY toYYYYMM(timestamp)
ORDER BY (user_id, event_id, timestamp)
PRIMARY KEY (user_id, event_id);

AggregatingMergeTree (Voraggregation)

sql
-- Zur Aufrechterhaltung aggregierter Kennzahlen
CREATE TABLE market_stats_hourly (
    hour DateTime,
    market_id String,
    total_volume AggregateFunction(sum, UInt64),
    total_trades AggregateFunction(count, UInt32),
    unique_users AggregateFunction(uniq, String)
) ENGINE = AggregatingMergeTree()
PARTITION BY toYYYYMM(hour)
ORDER BY (hour, market_id);

-- Aggregierte Daten abfragen
SELECT
    hour,
    market_id,
    sumMerge(total_volume) AS volume,
    countMerge(total_trades) AS trades,
    uniqMerge(unique_users) AS users
FROM market_stats_hourly
WHERE hour >= toStartOfHour(now() - INTERVAL 24 HOUR)
GROUP BY hour, market_id
ORDER BY hour DESC;

Abfrageoptimierungsmuster

Effiziente Filterung

sql
-- ✅ GUT: Indexspalten zuerst verwenden
SELECT *
FROM markets_analytics
WHERE date >= '2025-01-01'
  AND market_id = 'market-123'
  AND volume > 1000
ORDER BY date DESC
LIMIT 100;

-- ❌ SCHLECHT: Nicht-indexierte Spalten zuerst filtern
SELECT *
FROM markets_analytics
WHERE volume > 1000
  AND market_name LIKE '%election%'
  AND date >= '2025-01-01';

Aggregation

sql
-- ✅ GUT: ClickHouse-spezifische Aggregationsfunktionen verwenden
SELECT
    toStartOfDay(created_at) AS day,
    market_id,
    sum(volume) AS total_volume,
    count() AS total_trades,
    uniq(trader_id) AS unique_traders,
    avg(trade_size) AS avg_size
FROM trades
WHERE created_at >= today() - INTERVAL 7 DAY
GROUP BY day, market_id
ORDER BY day DESC, total_volume DESC;

-- ✅ quantile für Perzentile verwenden (effizienter als percentile)
SELECT
    quantile(0.50)(trade_size) AS median,
    quantile(0.95)(trade_size) AS p95,
    quantile(0.99)(trade_size) AS p99
FROM trades
WHERE created_at >= now() - INTERVAL 1 HOUR;

Dateneinfügungsmuster

Masseneinfügung (empfohlen)

typescript
import { ClickHouse } from 'clickhouse'

const clickhouse = new ClickHouse({
  url: process.env.CLICKHOUSE_URL,
  port: 8123,
  basicAuth: {
    username: process.env.CLICKHOUSE_USER,
    password: process.env.CLICKHOUSE_PASSWORD
  }
})

// ✅ Masseneinfügung (effizient)
async function bulkInsertTrades(trades: Trade[]) {
  const values = trades.map(trade => `(
    '${trade.id}',
    '${trade.market_id}',
    '${trade.user_id}',
    ${trade.amount},
    '${trade.timestamp.toISOString()}'
  )`).join(',')

  await clickhouse.query(`
    INSERT INTO trades (id, market_id, user_id, amount, timestamp)
    VALUES ${values}
  `).toPromise()
}

// ❌ Einzelneinfügung (langsam)
async function insertTrade(trade: Trade) {
  // Nicht in einer Schleife tun!
  await clickhouse.query(`
    INSERT INTO trades VALUES ('${trade.id}', ...)
  `).toPromise()
}

Streaming-Einfügung

typescript
// Für kontinuierlichen Datenimport
import { createWriteStream } from 'fs'
import { pipeline } from 'stream/promises'

async function streamInserts() {
  const stream = clickhouse.insert('trades').stream()

  for await (const batch of dataSource) {
    stream.write(batch)
  }

  await stream.end()
}

Materialisierte Ansichten

Echtzeitaggregation

sql
-- Materialisierte Ansicht für stündliche Statistiken erstellen
CREATE MATERIALIZED VIEW market_stats_hourly_mv
TO market_stats_hourly
AS SELECT
    toStartOfHour(timestamp) AS hour,
    market_id,
    sumState(amount) AS total_volume,
    countState() AS total_trades,
    uniqState(user_id) AS unique_users
FROM trades
GROUP BY hour, market_id;

-- Materialisierte Ansicht abfragen
SELECT
    hour,
    market_id,
    sumMerge(total_volume) AS volume,
    countMerge(total_trades) AS trades,
    uniqMerge(unique_users) AS users
FROM market_stats_hourly
WHERE hour >= now() - INTERVAL 24 HOUR
GROUP BY hour, market_id;

Performance-Überwachung

Abfrageperformance

sql
-- Langsame Abfragen prüfen
SELECT
    query_id,
    user,
    query,
    query_duration_ms,
    read_rows,
    read_bytes,
    memory_usage
FROM system.query_log
WHERE type = 'QueryFinish'
  AND query_duration_ms > 1000
  AND event_time >= now() - INTERVAL 1 HOUR
ORDER BY query_duration_ms DESC
LIMIT 10;

Tabellenstatistiken

sql
-- Tabellengröße prüfen
SELECT
    database,
    table,
    formatReadableSize(sum(bytes)) AS size,
    sum(rows) AS rows,
    max(modification_time) AS latest_modification
FROM system.parts
WHERE active
GROUP BY database, table
ORDER BY sum(bytes) DESC;

Häufige Analyseabfragen

Zeitreihenanalyse

sql
-- Täglich aktive Benutzer
SELECT
    toDate(timestamp) AS date,
    uniq(user_id) AS daily_active_users
FROM events
WHERE timestamp >= today() - INTERVAL 30 DAY
GROUP BY date
ORDER BY date;

-- Retention-Analyse
SELECT
    signup_date,
    countIf(days_since_signup = 0) AS day_0,
    countIf(days_since_signup = 1) AS day_1,
    countIf(days_since_signup = 7) AS day_7,
    countIf(days_since_signup = 30) AS day_30
FROM (
    SELECT
        user_id,
        min(toDate(timestamp)) AS signup_date,
        toDate(timestamp) AS activity_date,
        dateDiff('day', signup_date, activity_date) AS days_since_signup
    FROM events
    GROUP BY user_id, activity_date
)
GROUP BY signup_date
ORDER BY signup_date DESC;

Trichteranalyse

sql
-- Konversionstrichter
SELECT
    countIf(step = 'viewed_market') AS viewed,
    countIf(step = 'clicked_trade') AS clicked,
    countIf(step = 'completed_trade') AS completed,
    round(clicked / viewed * 100, 2) AS view_to_click_rate,
    round(completed / clicked * 100, 2) AS click_to_completion_rate
FROM (
    SELECT
        user_id,
        session_id,
        event_type AS step
    FROM events
    WHERE event_date = today()
)
GROUP BY session_id;

Kohortenanalyse

sql
-- Benutzerkohorten nach Anmeldemonat
SELECT
    toStartOfMonth(signup_date) AS cohort,
    toStartOfMonth(activity_date) AS month,
    dateDiff('month', cohort, month) AS months_since_signup,
    count(DISTINCT user_id) AS active_users
FROM (
    SELECT
        user_id,
        min(toDate(timestamp)) OVER (PARTITION BY user_id) AS signup_date,
        toDate(timestamp) AS activity_date
    FROM events
)
GROUP BY cohort, month, months_since_signup
ORDER BY cohort, months_since_signup;

Datenpipelinemuster

ETL-Muster

typescript
// Extrahieren, Transformieren, Laden
async function etlPipeline() {
  // 1. Aus Quelle extrahieren
  const rawData = await extractFromPostgres()

  // 2. Transformieren
  const transformed = rawData.map(row => ({
    date: new Date(row.created_at).toISOString().split('T')[0],
    market_id: row.market_slug,
    volume: parseFloat(row.total_volume),
    trades: parseInt(row.trade_count)
  }))

  // 3. In ClickHouse laden
  await bulkInsertToClickHouse(transformed)
}

// Regelmäßig ausführen
setInterval(etlPipeline, 60 * 60 * 1000)  // Stündlich

Change Data Capture (CDC)

typescript
// PostgreSQL-Updates abhören und an ClickHouse synchronisieren
import { Client } from 'pg'

const pgClient = new Client({ connectionString: process.env.DATABASE_URL })

pgClient.query('LISTEN market_updates')

pgClient.on('notification', async (msg) => {
  const update = JSON.parse(msg.payload)

  await clickhouse.insert('market_updates', [
    {
      market_id: update.id,
      event_type: update.operation,  // INSERT, UPDATE, DELETE
      timestamp: new Date(),
      data: JSON.stringify(update.new_data)
    }
  ])
})

Best Practices

1. Partitionierungsstrategie

  • Nach Zeit partitionieren (meist Monat oder Tag)
  • Zu viele Partitionen vermeiden (Performance-Auswirkungen)
  • DATE-Typ als Partitionsschlüssel verwenden

2. Sortierschlüssel

  • Am häufigsten gefilterte Spalten zuerst platzieren
  • Kardinalität berücksichtigen (hohe Kardinalität priorisieren)
  • Sortierung beeinflusst Komprimierung

3. Datentypen

  • Kleinsten geeigneten Typ verwenden (UInt32 vs UInt64)
  • LowCardinality für wiederkehrende Strings verwenden
  • Enum für kategorische Daten verwenden

4. Vermeiden

  • SELECT * (Spalten angeben)
  • FINAL (Daten vor Abfrage zusammenführen)
  • Zu viele JOINs (bei Analyse denormalisieren)
  • Kleine häufige Einfügungen (stattdessen Batch)

5. Überwachung

  • Abfrageperformance verfolgen
  • Festplattennutzung überwachen
  • Zusammenführungsvorgänge prüfen
  • Langsame Abfrageprotokolle prüfen

Erinnern Sie sich

ClickHouse glänzt bei Analyseworkloads. Designen Sie Tabellen für Ihre Abfragemuster, fügen Sie massenhaft ein und nutzen Sie materialisierte Ansichten für Echtzeitaggregation.


Nächste Lektion Vorschau

In der nächsten Lektion lernen wir Scripts API-Referenz.

Sie werden lernen:

  • Node.js-Skriptschnittstellen und Utility-Funktionen
  • Paketmanager-Erkennungsmechanismen
  • Implementierungsdetails von Hooks-Skripten
  • Verwendungsmethoden der Testsuite

Zusammenfassung dieser Lektion

Die 11 Skill-Bibliotheken von Everything Claude Code bieten umfassende Wissensunterstützung für den Entwicklungsprozess:

  1. coding-standards - Einheitliche Codierungsstandards, unveränderliche Muster, Best Practices
  2. backend-patterns - Backend-Architekturmuster, API-Design, Datenbankoptimierung
  3. frontend-patterns - React/Next.js-Muster, Zustandsverwaltung, Performance-Optimierung
  4. tdd-workflow - Testgetriebene Entwicklungs-Workflows, 80%+ Abdeckung
  5. security-review - OWASP Top 10, Eingabevalidierung, Schwachstellenerkennung
  6. continuous-learning - Automatische Extraktion wiederverwendbarer Muster, Wissensakkumulation
  7. strategic-compact - Strategische Kontextkomprimierung, Token-Optimierung
  8. eval-harness - Evaluationsgetriebene Entwicklung, Zuverlässigkeitstests
  9. verification-loop - Umfassendes Verifikationssystem, Qualitätsprüfung
  10. project-guidelines-example - Projektkonfigurationsbeispiel, Architekturvorlage
  11. clickhouse-io - ClickHouse-Analysenmuster, Hochleistungsabfragen

Denken Sie daran, dass diese Skill-Bibliotheken der Kompass für Ihre Codequalität sind. Wenn Sie sie während der Entwicklung korrekt anwenden, können Sie die Entwicklungseffizienz und Codequalität erheblich steigern.


Anhang: Quellcode-Referenz

Klicken, um Quellcodeposition anzuzeigen

Aktualisiert am: 2026-01-25

Skill-BibliothekDateipfadZeilennummer
---------
---------
---------
---------
---------
---------
---------
---------
---------

Wichtige Prinzipien:

  • coding-standards: Unveränderliche Muster, Dateien < 800 Zeilen, Funktionen < 50 Zeilen, 80%+ Testabdeckung
  • backend-patterns: Repository-Muster, Service-Layer-Trennung, parametrisierte Abfragen, Redis-Caching
  • frontend-patterns: Komponentenkomposition, benutzerdefinierte Hooks, Context + Reducer, Memoisierung, Lazy Loading
  • tdd-workflow: Tests zuerst, Unit/Integration/E2E-Tests, Testabdeckungsvalidierung
  • security-review: OWASP Top 10-Prüfungen, Eingabevalidierung, SQL-Injection-Verhinderung, XSS-Verhinderung

Verwandte Agents:

  • tdd-guide: TDD-Workflow-Anleitung
  • code-reviewer: Codequalitäts- und Stilüberprüfung
  • security-reviewer: Sicherheitslückenerkennung
  • architect: Architekturdesign und Musterauswahl