'use client' /** * PCA Platform Admin Page * * Manages bot detection, session monitoring, and payment settings * for the Person-Corporate-Agent platform. */ import { useState, useEffect, useCallback } from 'react' import AdminLayout from '@/components/admin/AdminLayout' // Types interface SessionMetrics { session_id: string score: number dwell_ratio: number scroll_depth: number clicks: number mouse_moves: number action: string last_update: string } interface ServiceStatus { status: 'healthy' | 'unhealthy' | 'offline' service: string version: string uptime?: string } interface PCAConfig { thresholds: { score_pass: number score_challenge: number } weights: { dwell_ratio: number scroll_score: number pointer_variance: number click_rate: number } step_up: { methods: string[] primary: string } } interface Stats { activeSessions: number humanScore: number botScore: number challengesIssued: number paymentsReceived: number totalRevenue: string } export default function PCAAdminPage() { const [serviceStatus, setServiceStatus] = useState(null) const [config, setConfig] = useState(null) const [sessions, setSessions] = useState([]) const [stats, setStats] = useState({ activeSessions: 0, humanScore: 0, botScore: 0, challengesIssued: 0, paymentsReceived: 0, totalRevenue: '0.00 EUR' }) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [activeTab, setActiveTab] = useState<'overview' | 'sessions' | 'config' | 'payments'>('overview') // Fetch service status const fetchStatus = useCallback(async () => { try { const response = await fetch('/api/admin/pca?action=status') if (response.ok) { const data = await response.json() setServiceStatus(data) setError(null) } else { setServiceStatus({ status: 'offline', service: 'pca-heuristic-service', version: 'unknown' }) } } catch { setServiceStatus({ status: 'offline', service: 'pca-heuristic-service', version: 'unknown' }) } }, []) // Fetch config const fetchConfig = useCallback(async () => { try { const response = await fetch('/api/admin/pca?action=config') if (response.ok) { const data = await response.json() setConfig(data) } } catch { // Use defaults setConfig({ thresholds: { score_pass: 0.7, score_challenge: 0.4 }, weights: { dwell_ratio: 0.30, scroll_score: 0.25, pointer_variance: 0.20, click_rate: 0.25 }, step_up: { methods: ['webauthn', 'pow'], primary: 'webauthn' } }) } }, []) // Fetch sessions (mock for now) const fetchSessions = useCallback(async () => { // Mock data - in production would fetch from backend setSessions([ { session_id: 'pca_abc123', score: 0.85, dwell_ratio: 0.92, scroll_depth: 65, clicks: 12, mouse_moves: 234, action: 'allow', last_update: new Date().toISOString() }, { session_id: 'pca_def456', score: 0.32, dwell_ratio: 0.15, scroll_depth: 5, clicks: 0, mouse_moves: 3, action: 'challenge', last_update: new Date().toISOString() }, { session_id: 'pca_ghi789', score: 0.71, dwell_ratio: 0.78, scroll_depth: 45, clicks: 8, mouse_moves: 156, action: 'allow', last_update: new Date().toISOString() }, ]) }, []) useEffect(() => { const init = async () => { setLoading(true) await Promise.all([fetchStatus(), fetchConfig(), fetchSessions()]) setLoading(false) } init() // Refresh every 10 seconds const interval = setInterval(() => { fetchStatus() fetchSessions() }, 10000) return () => clearInterval(interval) }, [fetchStatus, fetchConfig, fetchSessions]) // Score color helper const getScoreColor = (score: number) => { if (score >= 0.7) return 'text-green-600 bg-green-100' if (score >= 0.4) return 'text-yellow-600 bg-yellow-100' return 'text-red-600 bg-red-100' } const getScoreLabel = (score: number) => { if (score >= 0.7) return 'Human' if (score >= 0.4) return 'Unsicher' return 'Bot' } return ( {/* Loading State */} {loading && (
Lade PCA Status...
)} {/* Error State */} {error && !loading && (
⚠️

{error}

)} {/* Service Status Banner */} {!loading && serviceStatus && (
{serviceStatus.service} v{serviceStatus.version}
{serviceStatus.status === 'healthy' ? 'Online' : serviceStatus.status === 'offline' ? 'Offline' : 'Degraded'}
)} {/* Tabs */} {!loading && (
)} {/* Overview Tab */} {!loading && activeTab === 'overview' && (
{/* Stats Grid */}
{stats.activeSessions}
Aktive Sessions
{stats.humanScore}%
Human Score Avg
{stats.challengesIssued}
Challenges ausgestellt
{stats.totalRevenue}
Umsatz (Bot-Zugriffe)
{/* Quick Actions */}

Quick Actions

{/* Heuristic Weights Visualization */} {config && (

Heuristik-Gewichtung

{[ { key: 'dwell_ratio', label: 'Verweildauer', value: config.weights.dwell_ratio }, { key: 'scroll_score', label: 'Scroll-Verhalten', value: config.weights.scroll_score }, { key: 'pointer_variance', label: 'Maus-Bewegungen', value: config.weights.pointer_variance }, { key: 'click_rate', label: 'Klick-Muster', value: config.weights.click_rate }, ].map(metric => (
{metric.label}
{(metric.value * 100).toFixed(0)}%
))}
)}
)} {/* Sessions Tab */} {!loading && activeTab === 'sessions' && (

Aktive Sessions

{sessions.map(session => ( ))}
Session ID Score Verweildauer Scroll Klicks Aktion
{session.session_id} {session.score.toFixed(2)} - {getScoreLabel(session.score)} {(session.dwell_ratio * 100).toFixed(0)}% {session.scroll_depth}% {session.clicks} {session.action === 'allow' ? 'Erlaubt' : 'Challenge'}
)} {/* Config Tab */} {!loading && activeTab === 'config' && config && (
{/* Thresholds */}

Score-Schwellenwerte

Score ab dem ein Besucher als Mensch gilt

Score unter dem Step-Up erforderlich ist

{/* Step-Up Methods */}

Step-Up Methoden

{config.step_up.methods.map(method => (
{method === 'webauthn' ? '🔐' : '⚡'}
{method === 'webauthn' ? 'WebAuthn' : 'Proof-of-Work'}
{method === 'webauthn' ? 'Biometrische Authentifizierung' : 'Rechenintensive Challenge'}
{method === config.step_up.primary && ( Primär )}
))}
{/* ai-access.json Preview */}

ai-access.json

{`{
  "thresholds": {
    "score_pass": ${config.thresholds.score_pass},
    "score_challenge": ${config.thresholds.score_challenge}
  },
  "weights": {
    "dwell_ratio": ${config.weights.dwell_ratio},
    "scroll_score": ${config.weights.scroll_score},
    "pointer_variance": ${config.weights.pointer_variance},
    "click_rate": ${config.weights.click_rate}
  },
  "step_up": {
    "methods": ${JSON.stringify(config.step_up.methods)},
    "primary": "${config.step_up.primary}"
  },
  "pca_roles": {
    "Person": { "access": "allow", "price": null },
    "Corporate": { "access": "allow", "price": null },
    "Agent": { "access": "charge", "price": "0.001 EUR" }
  }
}`}
            
)} {/* Payments Tab */} {!loading && activeTab === 'payments' && (
🚧

Payment Gateway in Entwicklung

HTTP 402 Payment Required und Stablecoin-Integration werden in einer zukünftigen Version verfügbar sein.

Geplante Features

  • 1 Micropayments per Request (Pay-per-Crawl)
  • 2 Stablecoin Support (USDC, EURC)
  • 3 Bitcoin Lightning Integration
  • 4 Agent Wallet Verwaltung
)} ) }