fix(admin-v2): Restore complete admin-v2 application

The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-08 23:40:15 -08:00
parent f28244753f
commit 660295e218
385 changed files with 138126 additions and 3079 deletions

View File

@@ -0,0 +1,256 @@
import { DevPortalLayout, CodeBlock, InfoBox, ParameterTable } from '@/components/developers/DevPortalLayout'
export default function SDKConfigurationPage() {
return (
<DevPortalLayout
title="SDK Konfiguration"
description="Alle Konfigurationsoptionen des AI Compliance SDK"
>
<h2>SDKProvider Props</h2>
<p>
Der SDKProvider akzeptiert folgende Konfigurationsoptionen:
</p>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Ihre eindeutige Tenant-ID (erhalten nach Abo-Abschluss)',
},
{
name: 'apiKey',
type: 'string',
required: false,
description: 'API Key fuer authentifizierte Anfragen (nur serverseitig verwenden)',
},
{
name: 'userId',
type: 'string',
required: false,
description: 'Benutzer-ID fuer Audit-Trail und Checkpoints',
},
{
name: 'enableBackendSync',
type: 'boolean',
required: false,
description: 'Aktiviert automatische Synchronisation mit dem Backend (default: false)',
},
{
name: 'apiBaseUrl',
type: 'string',
required: false,
description: 'Custom API URL fuer Self-Hosted Installationen',
},
{
name: 'syncInterval',
type: 'number',
required: false,
description: 'Intervall fuer Auto-Sync in Millisekunden (default: 30000)',
},
{
name: 'enableOfflineSupport',
type: 'boolean',
required: false,
description: 'Aktiviert localStorage Fallback bei Offline (default: true)',
},
{
name: 'initialStep',
type: 'string',
required: false,
description: 'Initialer Schritt beim ersten Laden (default: "advisory-board")',
},
{
name: 'onError',
type: '(error: Error) => void',
required: false,
description: 'Callback fuer Fehlerbehandlung',
},
{
name: 'onStateChange',
type: '(state: SDKState) => void',
required: false,
description: 'Callback bei State-Aenderungen',
},
]}
/>
<h2>Vollstaendiges Beispiel</h2>
<CodeBlock language="typescript" filename="app/layout.tsx">
{`'use client'
import { SDKProvider } from '@breakpilot/compliance-sdk'
import { useRouter } from 'next/navigation'
export default function SDKLayout({ children }: { children: React.ReactNode }) {
const router = useRouter()
return (
<SDKProvider
tenantId={process.env.NEXT_PUBLIC_TENANT_ID!}
userId="user-123"
enableBackendSync={true}
syncInterval={60000} // Sync alle 60 Sekunden
enableOfflineSupport={true}
initialStep="use-case-workshop"
onError={(error) => {
console.error('SDK Error:', error)
// Optional: Sentry oder anderes Error-Tracking
}}
onStateChange={(state) => {
console.log('State changed:', state.currentStep)
// Optional: Analytics-Events
}}
>
{children}
</SDKProvider>
)
}`}
</CodeBlock>
<h2>Synchronisations-Strategien</h2>
<h3>1. Nur localStorage (Offline-Only)</h3>
<CodeBlock language="typescript" filename="Offline-Only">
{`<SDKProvider
tenantId="my-tenant"
enableBackendSync={false}
enableOfflineSupport={true}
>
{children}
</SDKProvider>`}
</CodeBlock>
<p>
Ideal fuer: Lokale Entwicklung, Demos, Privacy-fokussierte Installationen.
Daten werden nur im Browser gespeichert.
</p>
<h3>2. Backend-Sync mit Fallback</h3>
<CodeBlock language="typescript" filename="Backend + Fallback">
{`<SDKProvider
tenantId="my-tenant"
enableBackendSync={true}
enableOfflineSupport={true}
syncInterval={30000}
>
{children}
</SDKProvider>`}
</CodeBlock>
<p>
Empfohlen fuer: Produktionsumgebungen. Daten werden mit dem Backend
synchronisiert, localStorage dient als Fallback bei Netzwerkproblemen.
</p>
<h3>3. Nur Backend (kein lokaler Cache)</h3>
<CodeBlock language="typescript" filename="Backend-Only">
{`<SDKProvider
tenantId="my-tenant"
enableBackendSync={true}
enableOfflineSupport={false}
>
{children}
</SDKProvider>`}
</CodeBlock>
<p>
Ideal fuer: Strenge Compliance-Anforderungen, Multi-User-Szenarien.
Daten werden nur im Backend gespeichert.
</p>
<InfoBox type="warning" title="Backend-Only Modus">
Im Backend-Only Modus ist eine aktive Internetverbindung erforderlich.
Bei Netzwerkproblemen koennen Daten verloren gehen.
</InfoBox>
<h2>API URL Konfiguration</h2>
<h3>Cloud-Version (Standard)</h3>
<p>Keine zusaetzliche Konfiguration erforderlich:</p>
<CodeBlock language="typescript" filename="Cloud">
{`<SDKProvider tenantId="my-tenant">
{/* Nutzt automatisch https://api.breakpilot.io/sdk/v1 */}
</SDKProvider>`}
</CodeBlock>
<h3>Self-Hosted</h3>
<CodeBlock language="typescript" filename="Self-Hosted">
{`<SDKProvider
tenantId="my-tenant"
apiBaseUrl="https://your-server.com/sdk/v1"
>
{children}
</SDKProvider>`}
</CodeBlock>
<h3>Lokale Entwicklung</h3>
<CodeBlock language="typescript" filename="Local Dev">
{`<SDKProvider
tenantId="dev-tenant"
apiBaseUrl="http://localhost:8085/sdk/v1"
enableBackendSync={true}
>
{children}
</SDKProvider>`}
</CodeBlock>
<h2>Feature Flags</h2>
<p>
Das SDK unterstuetzt Feature Flags ueber Subscription-Levels:
</p>
<CodeBlock language="typescript" filename="Feature Checks">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function MyComponent() {
const { state } = useSDK()
// Subscription-basierte Features
const isEnterprise = state.subscription === 'ENTERPRISE'
const isProfessional = ['PROFESSIONAL', 'ENTERPRISE'].includes(state.subscription)
// Feature-Gates
const canExportPDF = isProfessional
const canUseRAG = isProfessional
const canCustomizeDSFA = isEnterprise
const canUseAPI = isProfessional
return (
<div>
{canExportPDF && <button>PDF Export</button>}
{canUseRAG && <RAGSearchPanel />}
</div>
)
}`}
</CodeBlock>
<h2>Logging & Debugging</h2>
<p>
Aktivieren Sie detailliertes Logging fuer die Entwicklung:
</p>
<CodeBlock language="typescript" filename="Debug Mode">
{`// In Ihrer .env.local
NEXT_PUBLIC_SDK_DEBUG=true
// Oder programmatisch
<SDKProvider
tenantId="my-tenant"
onStateChange={(state) => {
if (process.env.NODE_ENV === 'development') {
console.log('[SDK] State Update:', {
phase: state.currentPhase,
step: state.currentStep,
useCases: state.useCases.length,
risks: state.risks.length,
})
}
}}
>
{children}
</SDKProvider>`}
</CodeBlock>
<InfoBox type="info" title="React DevTools">
Der SDK-State ist im React DevTools unter dem SDKProvider-Context sichtbar.
Installieren Sie die React Developer Tools Browser-Extension fuer einfaches Debugging.
</InfoBox>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,482 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button
onClick={handleCopy}
className="p-2 hover:bg-gray-700 rounded transition-colors"
title="Kopieren"
>
{copied ? (
<Check className="w-4 h-4 text-green-400" />
) : (
<Copy className="w-4 h-4 text-gray-400" />
)}
</button>
)
}
function CodeBlock({ code }: { code: string }) {
return (
<div className="relative bg-gray-900 rounded-lg overflow-hidden">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
)
}
function MethodCard({
name,
signature,
description,
params,
returns,
example,
}: {
name: string
signature: string
description: string
params?: { name: string; type: string; description: string }[]
returns?: string
example?: string
}) {
return (
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<div className="px-6 py-4 border-b border-gray-200 bg-gray-50">
<code className="text-violet-600 font-mono font-semibold">{name}</code>
</div>
<div className="p-6">
<div className="bg-gray-100 rounded-lg p-3 mb-4">
<code className="text-sm font-mono text-gray-800">{signature}</code>
</div>
<p className="text-gray-600 mb-4">{description}</p>
{params && params.length > 0 && (
<div className="mb-4">
<h4 className="font-medium text-gray-900 mb-2">Parameter</h4>
<table className="min-w-full">
<tbody className="divide-y divide-gray-200">
{params.map((param) => (
<tr key={param.name}>
<td className="py-2 pr-4">
<code className="text-sm text-violet-600">{param.name}</code>
</td>
<td className="py-2 pr-4">
<code className="text-sm text-gray-500">{param.type}</code>
</td>
<td className="py-2 text-sm text-gray-600">{param.description}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
{returns && (
<div className="mb-4">
<h4 className="font-medium text-gray-900 mb-2">Rueckgabe</h4>
<code className="text-sm text-gray-600">{returns}</code>
</div>
)}
{example && (
<div>
<h4 className="font-medium text-gray-900 mb-2">Beispiel</h4>
<CodeBlock code={example} />
</div>
)}
</div>
</div>
)
}
export default function APIReferencePage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<h1 className="text-3xl font-bold text-gray-900 mb-2">API Referenz</h1>
<p className="text-lg text-gray-600 mb-8">
Vollstaendige Dokumentation aller Methoden und Konfigurationsoptionen des Consent SDK.
</p>
{/* ConsentManager */}
<section className="mb-12">
<h2 className="text-2xl font-semibold text-gray-900 mb-6">ConsentManager</h2>
<p className="text-gray-600 mb-6">
Die zentrale Klasse fuer das Consent Management. Verwaltet Einwilligungen, Script-Blocking und Events.
</p>
{/* Constructor */}
<div className="space-y-6">
<MethodCard
name="constructor"
signature="new ConsentManager(config: ConsentConfig)"
description="Erstellt eine neue Instanz des ConsentManagers mit der angegebenen Konfiguration."
params={[
{
name: 'config',
type: 'ConsentConfig',
description: 'Konfigurationsobjekt fuer den Manager',
},
]}
example={`const consent = new ConsentManager({
apiEndpoint: 'https://api.example.com/consent',
siteId: 'my-site',
debug: true,
});`}
/>
<MethodCard
name="init"
signature="async init(): Promise<void>"
description="Initialisiert das SDK, laedt bestehenden Consent und startet das Script-Blocking. Zeigt den Banner an falls noetig."
example={`await consent.init();`}
/>
<MethodCard
name="hasConsent"
signature="hasConsent(category: ConsentCategory): boolean"
description="Prueft ob Einwilligung fuer eine Kategorie vorliegt."
params={[
{
name: 'category',
type: 'ConsentCategory',
description: 'essential | functional | analytics | marketing | social',
},
]}
returns="boolean - true wenn Einwilligung vorliegt"
example={`if (consent.hasConsent('analytics')) {
// Analytics laden
loadGoogleAnalytics();
}`}
/>
<MethodCard
name="setConsent"
signature="async setConsent(input: ConsentInput): Promise<void>"
description="Setzt die Einwilligungen und speichert sie lokal sowie auf dem Server."
params={[
{
name: 'input',
type: 'ConsentInput',
description: 'Objekt mit Kategorien und optionalen Vendors',
},
]}
example={`await consent.setConsent({
essential: true,
functional: true,
analytics: true,
marketing: false,
social: false,
});`}
/>
<MethodCard
name="acceptAll"
signature="async acceptAll(): Promise<void>"
description="Akzeptiert alle Consent-Kategorien und schliesst den Banner."
example={`document.getElementById('accept-all').addEventListener('click', async () => {
await consent.acceptAll();
});`}
/>
<MethodCard
name="rejectAll"
signature="async rejectAll(): Promise<void>"
description="Lehnt alle nicht-essentiellen Kategorien ab und schliesst den Banner."
example={`document.getElementById('reject-all').addEventListener('click', async () => {
await consent.rejectAll();
});`}
/>
<MethodCard
name="revokeAll"
signature="async revokeAll(): Promise<void>"
description="Widerruft alle Einwilligungen und loescht den gespeicherten Consent."
example={`document.getElementById('revoke').addEventListener('click', async () => {
await consent.revokeAll();
location.reload();
});`}
/>
<MethodCard
name="on"
signature="on<T>(event: ConsentEventType, callback: (data: T) => void): () => void"
description="Registriert einen Event-Listener. Gibt eine Unsubscribe-Funktion zurueck."
params={[
{
name: 'event',
type: 'ConsentEventType',
description: 'init | change | accept_all | reject_all | banner_show | banner_hide | etc.',
},
{
name: 'callback',
type: 'function',
description: 'Callback-Funktion die bei Event aufgerufen wird',
},
]}
returns="() => void - Funktion zum Entfernen des Listeners"
example={`const unsubscribe = consent.on('change', (state) => {
console.log('Consent geaendert:', state);
});
// Spaeter: Listener entfernen
unsubscribe();`}
/>
<MethodCard
name="getConsent"
signature="getConsent(): ConsentState | null"
description="Gibt den aktuellen Consent-Status zurueck oder null falls kein Consent vorliegt."
returns="ConsentState | null"
example={`const state = consent.getConsent();
if (state) {
console.log('Consent ID:', state.consentId);
console.log('Kategorien:', state.categories);
}`}
/>
<MethodCard
name="exportConsent"
signature="async exportConsent(): Promise<string>"
description="Exportiert alle Consent-Daten als JSON-String (DSGVO Art. 20 Datenportabilitaet)."
returns="Promise<string> - JSON-formatierter Export"
example={`const exportData = await consent.exportConsent();
downloadAsFile(exportData, 'consent-export.json');`}
/>
</div>
</section>
{/* Configuration */}
<section className="mb-12">
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Konfiguration</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Option
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Typ
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Default
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Beschreibung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">apiEndpoint</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">string</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">erforderlich</td>
<td className="px-6 py-4 text-sm text-gray-600">URL des Consent-Backends</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">siteId</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">string</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">erforderlich</td>
<td className="px-6 py-4 text-sm text-gray-600">Eindeutige Site-ID</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">debug</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">boolean</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">false</td>
<td className="px-6 py-4 text-sm text-gray-600">Aktiviert Debug-Logging</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">language</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">string</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">&apos;de&apos;</td>
<td className="px-6 py-4 text-sm text-gray-600">Sprache fuer UI-Texte</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">consent.rememberDays</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">number</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">365</td>
<td className="px-6 py-4 text-sm text-gray-600">Gueltigkeitsdauer in Tagen</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">consent.recheckAfterDays</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">number</code>
</td>
<td className="px-6 py-4 text-sm text-gray-500">180</td>
<td className="px-6 py-4 text-sm text-gray-600">Erneute Abfrage nach X Tagen</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Events */}
<section className="mb-12">
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Events</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Event
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Daten
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Beschreibung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">init</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">ConsentState | null</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">SDK initialisiert</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">change</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">ConsentState</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Consent geaendert</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">accept_all</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">ConsentState</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Alle akzeptiert</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">reject_all</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">ConsentState</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Alle abgelehnt</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">banner_show</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">undefined</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Banner angezeigt</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">banner_hide</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">undefined</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Banner versteckt</td>
</tr>
<tr>
<td className="px-6 py-4">
<code className="text-sm text-violet-600">error</code>
</td>
<td className="px-6 py-4">
<code className="text-sm text-gray-500">Error</code>
</td>
<td className="px-6 py-4 text-sm text-gray-600">Fehler aufgetreten</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Types */}
<section>
<h2 className="text-2xl font-semibold text-gray-900 mb-6">TypeScript Types</h2>
<CodeBlock
code={`// Consent-Kategorien
type ConsentCategory = 'essential' | 'functional' | 'analytics' | 'marketing' | 'social';
// Consent-Status
interface ConsentState {
categories: Record<ConsentCategory, boolean>;
vendors: Record<string, boolean>;
timestamp: string;
version: string;
consentId?: string;
expiresAt?: string;
}
// Konfiguration
interface ConsentConfig {
apiEndpoint: string;
siteId: string;
debug?: boolean;
language?: string;
fallbackLanguage?: string;
ui?: ConsentUIConfig;
consent?: ConsentBehaviorConfig;
onConsentChange?: (state: ConsentState) => void;
onBannerShow?: () => void;
onBannerHide?: () => void;
onError?: (error: Error) => void;
}`}
/>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,281 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function AngularIntegrationPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-red-500 flex items-center justify-center">
<span className="text-white font-bold">A</span>
</div>
<h1 className="text-3xl font-bold text-gray-900">Angular Integration</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Service und Module fuer Angular 14+ Projekte.
</p>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<CodeBlock code="npm install @breakpilot/consent-sdk" />
</section>
{/* Module Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Module Setup</h2>
<CodeBlock
filename="app.module.ts"
code={`import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ConsentModule } from '@breakpilot/consent-sdk/angular';
import { environment } from '../environments/environment';
@NgModule({
imports: [
BrowserModule,
ConsentModule.forRoot({
apiEndpoint: environment.consentApi,
siteId: 'my-site',
debug: !environment.production,
}),
],
})
export class AppModule {}`}
/>
</section>
{/* Standalone Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Standalone Setup (Angular 15+)</h2>
<CodeBlock
filename="app.config.ts"
code={`import { ApplicationConfig } from '@angular/core';
import { provideConsent } from '@breakpilot/consent-sdk/angular';
import { environment } from '../environments/environment';
export const appConfig: ApplicationConfig = {
providers: [
provideConsent({
apiEndpoint: environment.consentApi,
siteId: 'my-site',
debug: !environment.production,
}),
],
};`}
/>
</section>
{/* Service Usage */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Service Usage</h2>
<CodeBlock
filename="components/analytics.component.ts"
code={`import { Component, OnInit } from '@angular/core';
import { ConsentService } from '@breakpilot/consent-sdk/angular';
@Component({
selector: 'app-analytics',
template: \`
<div *ngIf="hasAnalyticsConsent$ | async">
<!-- Analytics Code hier -->
</div>
\`,
})
export class AnalyticsComponent implements OnInit {
hasAnalyticsConsent$ = this.consentService.hasConsent$('analytics');
constructor(private consentService: ConsentService) {}
async loadAnalytics() {
if (await this.consentService.hasConsent('analytics')) {
// Load analytics
}
}
}`}
/>
</section>
{/* Cookie Banner */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Cookie Banner Component</h2>
<CodeBlock
filename="components/cookie-banner.component.ts"
code={`import { Component } from '@angular/core';
import { ConsentService } from '@breakpilot/consent-sdk/angular';
@Component({
selector: 'app-cookie-banner',
template: \`
<div
*ngIf="isBannerVisible$ | async"
class="fixed bottom-0 inset-x-0 bg-white border-t shadow-lg p-4 z-50"
>
<div class="max-w-4xl mx-auto flex items-center justify-between">
<p class="text-sm text-gray-600">
Wir verwenden Cookies um Ihr Erlebnis zu verbessern.
</p>
<div class="flex gap-2">
<button (click)="rejectAll()" class="px-4 py-2 border rounded">
Ablehnen
</button>
<button (click)="showSettings()" class="px-4 py-2 border rounded">
Einstellungen
</button>
<button (click)="acceptAll()" class="px-4 py-2 bg-blue-600 text-white rounded">
Alle akzeptieren
</button>
</div>
</div>
</div>
\`,
})
export class CookieBannerComponent {
isBannerVisible$ = this.consentService.isBannerVisible$;
constructor(private consentService: ConsentService) {}
async acceptAll() {
await this.consentService.acceptAll();
}
async rejectAll() {
await this.consentService.rejectAll();
}
showSettings() {
this.consentService.showSettings();
}
}`}
/>
</section>
{/* Directive */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">ConsentGate Directive</h2>
<CodeBlock
filename="template.html"
code={`<!-- Zeigt Element nur wenn Consent vorhanden -->
<iframe
*consentGate="'social'"
src="https://www.youtube.com/embed/VIDEO_ID"
width="560"
height="315"
></iframe>
<!-- Mit Custom Fallback -->
<div *consentGate="'analytics'; else noConsent">
<app-analytics-dashboard></app-analytics-dashboard>
</div>
<ng-template #noConsent>
<div class="bg-gray-100 p-4 rounded-lg text-center">
<p>Bitte stimmen Sie Statistik-Cookies zu.</p>
<button (click)="showSettings()">Einstellungen</button>
</div>
</ng-template>`}
/>
</section>
{/* Service API */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">Service API</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Property/Method
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Typ
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Beschreibung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">consent$</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Observable&lt;ConsentState&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Observable des aktuellen Consent</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent$()</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Observable&lt;boolean&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Reaktive Consent-Pruefung</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent()</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Promise&lt;boolean&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Async Consent-Pruefung</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">isBannerVisible$</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Observable&lt;boolean&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Banner-Sichtbarkeit</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll()</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Promise&lt;void&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Akzeptiert alle</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll()</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Promise&lt;void&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Lehnt alle ab</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent()</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Promise&lt;void&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Setzt spezifische Kategorien</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,98 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { ChevronRight } from 'lucide-react'
const frameworks = [
{
name: 'React',
href: '/developers/sdk/consent/frameworks/react',
logo: '/logos/react.svg',
description: 'Hooks und Provider fuer React 17+ und Next.js',
features: ['ConsentProvider', 'useConsent Hook', 'ConsentGate Component'],
color: 'bg-cyan-500',
},
{
name: 'Vue 3',
href: '/developers/sdk/consent/frameworks/vue',
logo: '/logos/vue.svg',
description: 'Composables und Plugin fuer Vue 3 und Nuxt',
features: ['Vue Plugin', 'useConsent Composable', 'ConsentGate Component'],
color: 'bg-emerald-500',
},
{
name: 'Angular',
href: '/developers/sdk/consent/frameworks/angular',
logo: '/logos/angular.svg',
description: 'Service und Module fuer Angular 14+',
features: ['ConsentService', 'ConsentModule', 'Dependency Injection'],
color: 'bg-red-500',
},
]
export default function FrameworksPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Framework Integration</h1>
<p className="text-lg text-gray-600 mb-8">
Das Consent SDK bietet native Integrationen fuer alle gaengigen Frontend-Frameworks.
</p>
<div className="space-y-4">
{frameworks.map((framework) => (
<Link
key={framework.name}
href={framework.href}
className="block bg-white rounded-xl border border-gray-200 p-6 hover:border-violet-300 hover:shadow-md transition-all group"
>
<div className="flex items-start gap-4">
<div className={`w-12 h-12 rounded-xl ${framework.color} flex items-center justify-center shrink-0`}>
<span className="text-white font-bold text-lg">{framework.name[0]}</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2">
<h2 className="text-xl font-semibold text-gray-900 group-hover:text-violet-600 transition-colors">
{framework.name}
</h2>
<ChevronRight className="w-5 h-5 text-gray-400 group-hover:text-violet-600 transition-colors" />
</div>
<p className="text-gray-600 mt-1">{framework.description}</p>
<div className="flex flex-wrap gap-2 mt-3">
{framework.features.map((feature) => (
<span
key={feature}
className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-md"
>
{feature}
</span>
))}
</div>
</div>
</div>
</Link>
))}
</div>
{/* Vanilla JS Note */}
<div className="mt-8 p-4 bg-blue-50 border border-blue-200 rounded-xl">
<h3 className="font-medium text-blue-900">Vanilla JavaScript</h3>
<p className="text-sm text-blue-700 mt-1">
Sie koennen das SDK auch ohne Framework verwenden. Importieren Sie einfach den ConsentManager direkt
aus dem Hauptpaket. Siehe{' '}
<Link href="/developers/sdk/consent/installation" className="underline">
Installation
</Link>{' '}
fuer Details.
</p>
</div>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,277 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function ReactIntegrationPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-cyan-500 flex items-center justify-center">
<span className="text-white font-bold">R</span>
</div>
<h1 className="text-3xl font-bold text-gray-900">React Integration</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Hooks und Provider fuer React 17+ und Next.js Projekte.
</p>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<CodeBlock code="npm install @breakpilot/consent-sdk" />
</section>
{/* Provider Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Provider Setup</h2>
<p className="text-gray-600 mb-4">
Umschliessen Sie Ihre App mit dem ConsentProvider:
</p>
<CodeBlock
filename="app/layout.tsx"
code={`import { ConsentProvider } from '@breakpilot/consent-sdk/react';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="de">
<body>
<ConsentProvider
config={{
apiEndpoint: process.env.NEXT_PUBLIC_CONSENT_API!,
siteId: 'my-site',
debug: process.env.NODE_ENV === 'development',
}}
>
{children}
</ConsentProvider>
</body>
</html>
);
}`}
/>
</section>
{/* useConsent Hook */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">useConsent Hook</h2>
<p className="text-gray-600 mb-4">
Verwenden Sie den Hook in jeder Komponente:
</p>
<CodeBlock
filename="components/Analytics.tsx"
code={`import { useConsent } from '@breakpilot/consent-sdk/react';
export function Analytics() {
const { hasConsent, acceptAll, rejectAll, showSettings } = useConsent();
if (!hasConsent('analytics')) {
return null;
}
return (
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_ID"
strategy="afterInteractive"
/>
);
}`}
/>
</section>
{/* ConsentGate */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">ConsentGate Component</h2>
<p className="text-gray-600 mb-4">
Zeigt Inhalte nur wenn Consent vorhanden ist:
</p>
<CodeBlock
filename="components/YouTubeEmbed.tsx"
code={`import { ConsentGate } from '@breakpilot/consent-sdk/react';
export function YouTubeEmbed({ videoId }: { videoId: string }) {
return (
<ConsentGate
category="social"
fallback={
<div className="bg-gray-100 p-4 rounded-lg text-center">
<p>Video erfordert Ihre Zustimmung.</p>
<button onClick={() => showSettings()}>
Einstellungen oeffnen
</button>
</div>
}
>
<iframe
src={\`https://www.youtube.com/embed/\${videoId}\`}
width="560"
height="315"
allowFullScreen
/>
</ConsentGate>
);
}`}
/>
</section>
{/* Custom Banner */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Custom Cookie Banner</h2>
<CodeBlock
filename="components/CookieBanner.tsx"
code={`import { useConsent } from '@breakpilot/consent-sdk/react';
export function CookieBanner() {
const {
isBannerVisible,
acceptAll,
rejectAll,
showSettings,
} = useConsent();
if (!isBannerVisible) return null;
return (
<div className="fixed bottom-0 inset-x-0 bg-white border-t shadow-lg p-4">
<div className="max-w-4xl mx-auto flex items-center justify-between">
<p className="text-sm text-gray-600">
Wir verwenden Cookies um Ihr Erlebnis zu verbessern.
</p>
<div className="flex gap-2">
<button
onClick={rejectAll}
className="px-4 py-2 text-sm border rounded"
>
Ablehnen
</button>
<button
onClick={showSettings}
className="px-4 py-2 text-sm border rounded"
>
Einstellungen
</button>
<button
onClick={acceptAll}
className="px-4 py-2 text-sm bg-blue-600 text-white rounded"
>
Alle akzeptieren
</button>
</div>
</div>
</div>
);
}`}
/>
</section>
{/* Hook API */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">Hook API</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Property
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Typ
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Beschreibung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">(category) =&gt; boolean</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Prueft Consent fuer Kategorie</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">consent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">ConsentState | null</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Aktueller Consent-Status</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Akzeptiert alle Kategorien</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Lehnt alle ab (ausser essential)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">(input) =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Setzt spezifische Kategorien</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">isBannerVisible</code></td>
<td className="px-6 py-4"><code className="text-gray-500">boolean</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Banner sichtbar?</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">showBanner</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; void</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Zeigt den Banner</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">showSettings</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; void</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Oeffnet Einstellungen</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,277 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function VueIntegrationPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-emerald-500 flex items-center justify-center">
<span className="text-white font-bold">V</span>
</div>
<h1 className="text-3xl font-bold text-gray-900">Vue 3 Integration</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Composables und Plugin fuer Vue 3 und Nuxt Projekte.
</p>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<CodeBlock code="npm install @breakpilot/consent-sdk" />
</section>
{/* Plugin Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Plugin Setup</h2>
<CodeBlock
filename="main.ts"
code={`import { createApp } from 'vue';
import App from './App.vue';
import { ConsentPlugin } from '@breakpilot/consent-sdk/vue';
const app = createApp(App);
app.use(ConsentPlugin, {
apiEndpoint: import.meta.env.VITE_CONSENT_API,
siteId: 'my-site',
debug: import.meta.env.DEV,
});
app.mount('#app');`}
/>
</section>
{/* Composable */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">useConsent Composable</h2>
<CodeBlock
filename="components/Analytics.vue"
code={`<script setup lang="ts">
import { useConsent } from '@breakpilot/consent-sdk/vue';
const { hasConsent, acceptAll, rejectAll } = useConsent();
</script>
<template>
<div v-if="hasConsent('analytics')">
<!-- Analytics Code hier -->
</div>
</template>`}
/>
</section>
{/* Cookie Banner */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Cookie Banner Component</h2>
<CodeBlock
filename="components/CookieBanner.vue"
code={`<script setup lang="ts">
import { useConsent } from '@breakpilot/consent-sdk/vue';
const {
isBannerVisible,
acceptAll,
rejectAll,
showSettings,
} = useConsent();
</script>
<template>
<Transition name="slide">
<div
v-if="isBannerVisible"
class="fixed bottom-0 inset-x-0 bg-white border-t shadow-lg p-4 z-50"
>
<div class="max-w-4xl mx-auto flex items-center justify-between">
<p class="text-sm text-gray-600">
Wir verwenden Cookies um Ihr Erlebnis zu verbessern.
</p>
<div class="flex gap-2">
<button
@click="rejectAll"
class="px-4 py-2 text-sm border rounded hover:bg-gray-50"
>
Ablehnen
</button>
<button
@click="showSettings"
class="px-4 py-2 text-sm border rounded hover:bg-gray-50"
>
Einstellungen
</button>
<button
@click="acceptAll"
class="px-4 py-2 text-sm bg-blue-600 text-white rounded hover:bg-blue-700"
>
Alle akzeptieren
</button>
</div>
</div>
</div>
</Transition>
</template>
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateY(100%);
}
</style>`}
/>
</section>
{/* ConsentGate */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">ConsentGate Component</h2>
<CodeBlock
filename="components/YouTubeEmbed.vue"
code={`<script setup lang="ts">
import { ConsentGate } from '@breakpilot/consent-sdk/vue';
defineProps<{
videoId: string;
}>();
</script>
<template>
<ConsentGate category="social">
<template #default>
<iframe
:src="\`https://www.youtube.com/embed/\${videoId}\`"
width="560"
height="315"
allowfullscreen
/>
</template>
<template #fallback>
<div class="bg-gray-100 p-4 rounded-lg text-center">
<p>Video erfordert Ihre Zustimmung.</p>
<button class="mt-2 px-4 py-2 bg-blue-600 text-white rounded">
Zustimmen
</button>
</div>
</template>
</ConsentGate>
</template>`}
/>
</section>
{/* Nuxt */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Nuxt 3 Setup</h2>
<CodeBlock
filename="plugins/consent.client.ts"
code={`import { ConsentPlugin } from '@breakpilot/consent-sdk/vue';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(ConsentPlugin, {
apiEndpoint: useRuntimeConfig().public.consentApi,
siteId: 'my-site',
});
});`}
/>
</section>
{/* Composable API */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">Composable API</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Property
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Typ
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Beschreibung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">(category) =&gt; boolean</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Reaktive Consent-Pruefung</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">consent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Ref&lt;ConsentState&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Reaktiver Consent-Status</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">isBannerVisible</code></td>
<td className="px-6 py-4"><code className="text-gray-500">Ref&lt;boolean&gt;</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Reaktive Banner-Sichtbarkeit</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Akzeptiert alle</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll</code></td>
<td className="px-6 py-4"><code className="text-gray-500">() =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Lehnt alle ab</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent</code></td>
<td className="px-6 py-4"><code className="text-gray-500">(input) =&gt; Promise</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Setzt spezifische Kategorien</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,303 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check, Info, AlertTriangle } from 'lucide-react'
type PackageManager = 'npm' | 'yarn' | 'pnpm'
const installCommands: Record<PackageManager, string> = {
npm: 'npm install @breakpilot/consent-sdk',
yarn: 'yarn add @breakpilot/consent-sdk',
pnpm: 'pnpm add @breakpilot/consent-sdk',
}
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button
onClick={handleCopy}
className="p-2 hover:bg-gray-700 rounded transition-colors"
title="Kopieren"
>
{copied ? (
<Check className="w-4 h-4 text-green-400" />
) : (
<Copy className="w-4 h-4 text-gray-400" />
)}
</button>
)
}
function CodeBlock({ code, language = 'typescript' }: { code: string; language?: string }) {
return (
<div className="relative bg-gray-900 rounded-lg overflow-hidden">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
)
}
function InfoBox({ type = 'info', children }: { type?: 'info' | 'warning'; children: React.ReactNode }) {
const styles = {
info: 'bg-blue-50 border-blue-200 text-blue-800',
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
}
const Icon = type === 'warning' ? AlertTriangle : Info
return (
<div className={`p-4 border rounded-lg ${styles[type]} flex items-start gap-3`}>
<Icon className="w-5 h-5 shrink-0 mt-0.5" />
<div className="text-sm">{children}</div>
</div>
)
}
export default function InstallationPage() {
const [selectedPM, setSelectedPM] = useState<PackageManager>('npm')
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Installation</h1>
<p className="text-lg text-gray-600 mb-8">
Installieren Sie das Consent SDK in Ihrem Projekt.
</p>
{/* Package Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">NPM Package</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<div className="px-4 py-3 border-b border-gray-200 flex gap-1 bg-gray-50">
{(['npm', 'yarn', 'pnpm'] as const).map((pm) => (
<button
key={pm}
onClick={() => setSelectedPM(pm)}
className={`px-3 py-1.5 text-sm rounded-md transition-colors ${
selectedPM === pm
? 'bg-white text-gray-900 shadow-sm border border-gray-200'
: 'text-gray-600 hover:text-gray-900'
}`}
>
{pm}
</button>
))}
</div>
<div className="bg-gray-900 px-4 py-4 flex items-center justify-between">
<code className="text-green-400 font-mono text-sm">
$ {installCommands[selectedPM]}
</code>
<CopyButton text={installCommands[selectedPM]} />
</div>
</div>
</section>
{/* Framework-specific */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Framework-spezifische Imports</h2>
<div className="space-y-6">
<div>
<h3 className="font-medium text-gray-900 mb-2">Vanilla JavaScript</h3>
<CodeBlock
code={`import { ConsentManager } from '@breakpilot/consent-sdk';
const consent = new ConsentManager({
apiEndpoint: 'https://api.example.com/consent',
siteId: 'your-site-id',
});
await consent.init();`}
/>
</div>
<div>
<h3 className="font-medium text-gray-900 mb-2">React</h3>
<CodeBlock
code={`import { ConsentProvider, useConsent } from '@breakpilot/consent-sdk/react';
function App() {
return (
<ConsentProvider
config={{
apiEndpoint: 'https://api.example.com/consent',
siteId: 'your-site-id',
}}
>
<YourApp />
</ConsentProvider>
);
}`}
/>
</div>
<div>
<h3 className="font-medium text-gray-900 mb-2">Vue 3</h3>
<CodeBlock
code={`import { createApp } from 'vue';
import { ConsentPlugin } from '@breakpilot/consent-sdk/vue';
const app = createApp(App);
app.use(ConsentPlugin, {
apiEndpoint: 'https://api.example.com/consent',
siteId: 'your-site-id',
});`}
/>
</div>
</div>
</section>
{/* Script Blocking Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Script Blocking einrichten</h2>
<p className="text-gray-600 mb-4">
Um Third-Party Scripts automatisch zu blockieren, verwenden Sie das{' '}
<code className="px-1.5 py-0.5 bg-gray-100 rounded text-sm">data-consent</code> Attribut:
</p>
<CodeBlock
language="html"
code={`<!-- Analytics Script (blockiert bis Consent) -->
<script
data-consent="analytics"
data-src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
type="text/plain"
></script>
<!-- Marketing Script (blockiert bis Consent) -->
<script data-consent="marketing" type="text/plain">
fbq('init', 'YOUR_PIXEL_ID');
</script>
<!-- Embedded iFrame (blockiert bis Consent) -->
<iframe
data-consent="social"
data-src="https://www.youtube.com/embed/VIDEO_ID"
width="560"
height="315"
></iframe>`}
/>
</section>
{/* Requirements */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Systemvoraussetzungen</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Anforderung
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Minimum
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Node.js</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 18.0.0</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">React (optional)</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 17.0.0</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Vue (optional)</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 3.0.0</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">TypeScript (optional)</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 4.7.0</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Browser Support */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Browser-Unterstuetzung</h2>
<InfoBox type="info">
Das SDK unterstuetzt alle modernen Browser mit ES2017+ Unterstuetzung.
Fuer aeltere Browser wird ein automatischer Fallback fuer Crypto-Funktionen bereitgestellt.
</InfoBox>
<div className="mt-4 bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Browser
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Minimum Version
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Chrome</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 60</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Firefox</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 55</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Safari</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 11</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm text-gray-900">Edge</td>
<td className="px-6 py-4 text-sm text-gray-600">&gt;= 79 (Chromium)</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Next Steps */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">Naechste Schritte</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<a
href="/developers/sdk/consent/api-reference"
className="p-4 bg-white rounded-xl border border-gray-200 hover:border-violet-300 hover:shadow-md transition-all"
>
<h3 className="font-medium text-gray-900">API Referenz</h3>
<p className="text-sm text-gray-500 mt-1">
Vollstaendige Dokumentation aller Methoden und Konfigurationsoptionen.
</p>
</a>
<a
href="/developers/sdk/consent/frameworks"
className="p-4 bg-white rounded-xl border border-gray-200 hover:border-violet-300 hover:shadow-md transition-all"
>
<h3 className="font-medium text-gray-900">Framework Integration</h3>
<p className="text-sm text-gray-500 mt-1">
Detaillierte Anleitungen fuer React, Vue und Angular.
</p>
</a>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,269 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check, Smartphone } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function AndroidSDKPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-green-600 flex items-center justify-center">
<Smartphone className="w-6 h-6 text-white" />
</div>
<h1 className="text-3xl font-bold text-gray-900">Android SDK (Kotlin)</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Native Kotlin SDK fuer Android API 26+ mit Jetpack Compose Unterstuetzung.
</p>
{/* Requirements */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Systemvoraussetzungen</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Kotlin Version</td>
<td className="px-6 py-4 text-sm text-gray-600">1.9+</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Min SDK</td>
<td className="px-6 py-4 text-sm text-gray-600">API 26 (Android 8.0)</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Compile SDK</td>
<td className="px-6 py-4 text-sm text-gray-600">34+</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<CodeBlock
filename="build.gradle.kts (Module)"
code={`dependencies {
implementation("com.breakpilot:consent-sdk:1.0.0")
// Fuer Jetpack Compose
implementation("com.breakpilot:consent-sdk-compose:1.0.0")
}`}
/>
</section>
{/* Basic Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Grundlegende Einrichtung</h2>
<CodeBlock
filename="MyApplication.kt"
code={`import android.app.Application
import com.breakpilot.consent.ConsentManager
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// Consent Manager konfigurieren
ConsentManager.configure(
context = this,
config = ConsentConfig(
apiEndpoint = "https://api.example.com/consent",
siteId = "my-android-app"
)
)
// Initialisieren
lifecycleScope.launch {
ConsentManager.initialize()
}
}
}`}
/>
</section>
{/* Jetpack Compose */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Jetpack Compose Integration</h2>
<CodeBlock
filename="MainActivity.kt"
code={`import androidx.compose.runtime.*
import com.breakpilot.consent.compose.*
@Composable
fun MainScreen() {
val consent = rememberConsentState()
Column {
// Consent-abhaengige UI
if (consent.hasConsent(ConsentCategory.ANALYTICS)) {
AnalyticsView()
}
// Buttons
Button(onClick = { consent.acceptAll() }) {
Text("Alle akzeptieren")
}
Button(onClick = { consent.rejectAll() }) {
Text("Alle ablehnen")
}
}
// Consent Banner (automatisch angezeigt wenn noetig)
ConsentBanner()
}
// ConsentGate Composable
@Composable
fun ProtectedContent() {
ConsentGate(
category = ConsentCategory.MARKETING,
fallback = {
Text("Marketing-Zustimmung erforderlich")
}
) {
MarketingContent()
}
}`}
/>
</section>
{/* Traditional Android */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">View-basierte Integration</h2>
<CodeBlock
filename="MainActivity.kt"
code={`import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.breakpilot.consent.ConsentManager
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.collect
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Auf Consent-Aenderungen reagieren
lifecycleScope.launch {
ConsentManager.consentFlow.collect { state ->
updateUI(state)
}
}
// Banner anzeigen wenn noetig
if (ConsentManager.needsConsent()) {
ConsentManager.showBanner(this)
}
}
private fun updateUI(state: ConsentState?) {
if (state?.hasConsent(ConsentCategory.ANALYTICS) == true) {
loadAnalytics()
}
}
fun onAcceptAllClick(view: View) {
lifecycleScope.launch {
ConsentManager.acceptAll()
}
}
}`}
/>
</section>
{/* API Reference */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">API Referenz</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Methode</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">configure()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">SDK konfigurieren</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">initialize()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">SDK initialisieren (suspend)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Consent fuer Kategorie pruefen</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">consentFlow</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Flow fuer reaktive Updates</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle akzeptieren (suspend)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle ablehnen (suspend)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Kategorien setzen (suspend)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">showBanner()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Banner als DialogFragment</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,313 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check, Smartphone } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function FlutterSDKPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-blue-500 flex items-center justify-center">
<Smartphone className="w-6 h-6 text-white" />
</div>
<h1 className="text-3xl font-bold text-gray-900">Flutter SDK</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Cross-Platform SDK fuer Flutter 3.16+ mit iOS, Android und Web Support.
</p>
{/* Requirements */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Systemvoraussetzungen</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Dart Version</td>
<td className="px-6 py-4 text-sm text-gray-600">3.0+</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Flutter Version</td>
<td className="px-6 py-4 text-sm text-gray-600">3.16+</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Plattformen</td>
<td className="px-6 py-4 text-sm text-gray-600">iOS, Android, Web</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<CodeBlock
filename="pubspec.yaml"
code={`dependencies:
consent_sdk: ^1.0.0`}
/>
<div className="mt-4">
<CodeBlock code="flutter pub get" />
</div>
</section>
{/* Basic Setup */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Grundlegende Einrichtung</h2>
<CodeBlock
filename="main.dart"
code={`import 'package:flutter/material.dart';
import 'package:consent_sdk/consent_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Consent SDK initialisieren
await ConsentManager.instance.initialize(
config: ConsentConfig(
apiEndpoint: 'https://api.example.com/consent',
siteId: 'my-flutter-app',
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const ConsentWrapper(
child: HomeScreen(),
),
);
}
}`}
/>
</section>
{/* Widget Usage */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Widget Integration</h2>
<CodeBlock
filename="home_screen.dart"
code={`import 'package:flutter/material.dart';
import 'package:consent_sdk/consent_sdk.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// StreamBuilder fuer reaktive Updates
StreamBuilder<ConsentState?>(
stream: ConsentManager.instance.consentStream,
builder: (context, snapshot) {
final consent = snapshot.data;
if (consent?.hasConsent(ConsentCategory.analytics) ?? false) {
return const AnalyticsWidget();
}
return const SizedBox.shrink();
},
),
// ConsentGate Widget
ConsentGate(
category: ConsentCategory.marketing,
fallback: const Center(
child: Text('Marketing-Zustimmung erforderlich'),
),
child: const MarketingWidget(),
),
// Buttons
ElevatedButton(
onPressed: () => ConsentManager.instance.acceptAll(),
child: const Text('Alle akzeptieren'),
),
ElevatedButton(
onPressed: () => ConsentManager.instance.rejectAll(),
child: const Text('Alle ablehnen'),
),
TextButton(
onPressed: () => ConsentManager.instance.showSettings(context),
child: const Text('Einstellungen'),
),
],
),
);
}
}`}
/>
</section>
{/* Custom Banner */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Custom Cookie Banner</h2>
<CodeBlock
filename="cookie_banner.dart"
code={`import 'package:flutter/material.dart';
import 'package:consent_sdk/consent_sdk.dart';
class CustomCookieBanner extends StatelessWidget {
const CustomCookieBanner({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
stream: ConsentManager.instance.isBannerVisibleStream,
builder: (context, snapshot) {
if (!(snapshot.data ?? false)) {
return const SizedBox.shrink();
}
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
),
],
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Wir verwenden Cookies um Ihr Erlebnis zu verbessern.',
style: TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => ConsentManager.instance.rejectAll(),
child: const Text('Ablehnen'),
),
TextButton(
onPressed: () => ConsentManager.instance.showSettings(context),
child: const Text('Einstellungen'),
),
ElevatedButton(
onPressed: () => ConsentManager.instance.acceptAll(),
child: const Text('Alle akzeptieren'),
),
],
),
],
),
),
);
},
);
}
}`}
/>
</section>
{/* API Reference */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">API Referenz</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Methode/Property</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">initialize()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">SDK initialisieren (Future)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Consent pruefen</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">consentStream</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Stream fuer Consent-Updates</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">isBannerVisibleStream</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Stream fuer Banner-Sichtbarkeit</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle akzeptieren (Future)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle ablehnen (Future)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Kategorien setzen (Future)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">showSettings()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Einstellungs-Dialog oeffnen</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,283 @@
'use client'
import React, { useState } from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Copy, Check, Apple } from 'lucide-react'
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button onClick={handleCopy} className="p-2 hover:bg-gray-700 rounded transition-colors">
{copied ? <Check className="w-4 h-4 text-green-400" /> : <Copy className="w-4 h-4 text-gray-400" />}
</button>
)
}
function CodeBlock({ code, filename }: { code: string; filename?: string }) {
return (
<div className="bg-gray-900 rounded-lg overflow-hidden">
{filename && (
<div className="px-4 py-2 bg-gray-800 text-gray-400 text-xs border-b border-gray-700">
{filename}
</div>
)}
<div className="relative">
<div className="absolute top-2 right-2">
<CopyButton text={code} />
</div>
<pre className="p-4 text-sm text-gray-300 font-mono overflow-x-auto">
<code>{code}</code>
</pre>
</div>
</div>
)
}
export default function iOSSDKPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<div className="flex items-center gap-3 mb-2">
<div className="w-10 h-10 rounded-lg bg-gray-900 flex items-center justify-center">
<Apple className="w-6 h-6 text-white" />
</div>
<h1 className="text-3xl font-bold text-gray-900">iOS SDK (Swift)</h1>
</div>
<p className="text-lg text-gray-600 mb-8">
Native Swift SDK fuer iOS 15+ und iPadOS mit SwiftUI-Unterstuetzung.
</p>
{/* Requirements */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Systemvoraussetzungen</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Swift Version</td>
<td className="px-6 py-4 text-sm text-gray-600">5.9+</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">iOS Deployment Target</td>
<td className="px-6 py-4 text-sm text-gray-600">iOS 15.0+</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Xcode Version</td>
<td className="px-6 py-4 text-sm text-gray-600">15.0+</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Installation */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Installation</h2>
<h3 className="font-medium text-gray-900 mb-2">Swift Package Manager</h3>
<CodeBlock
filename="Package.swift"
code={`dependencies: [
.package(url: "https://github.com/breakpilot/consent-sdk-ios.git", from: "1.0.0")
]`}
/>
<p className="text-sm text-gray-600 mt-4">
Oder in Xcode: File Add Package Dependencies URL eingeben
</p>
</section>
{/* Basic Usage */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Grundlegende Verwendung</h2>
<CodeBlock
filename="AppDelegate.swift"
code={`import ConsentSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Consent Manager konfigurieren
ConsentManager.shared.configure(
apiEndpoint: "https://api.example.com/consent",
siteId: "my-ios-app"
)
// Initialisieren
Task {
await ConsentManager.shared.initialize()
}
return true
}
}`}
/>
</section>
{/* SwiftUI Integration */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">SwiftUI Integration</h2>
<CodeBlock
filename="ContentView.swift"
code={`import SwiftUI
import ConsentSDK
struct ContentView: View {
@StateObject private var consent = ConsentManager.shared
var body: some View {
VStack {
if consent.hasConsent(.analytics) {
AnalyticsView()
}
Button("Alle akzeptieren") {
Task {
await consent.acceptAll()
}
}
}
.consentBanner() // Zeigt Banner automatisch
}
}
// Consent Gate Modifier
struct ProtectedView: View {
var body: some View {
Text("Geschuetzter Inhalt")
.requiresConsent(.marketing) {
// Fallback wenn kein Consent
Text("Marketing-Zustimmung erforderlich")
}
}
}`}
/>
</section>
{/* UIKit Integration */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">UIKit Integration</h2>
<CodeBlock
filename="ViewController.swift"
code={`import UIKit
import ConsentSDK
import Combine
class ViewController: UIViewController {
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
// Reaktiv auf Consent-Aenderungen reagieren
ConsentManager.shared.$consent
.receive(on: DispatchQueue.main)
.sink { [weak self] state in
self?.updateUI(consent: state)
}
.store(in: &cancellables)
}
private func updateUI(consent: ConsentState?) {
if consent?.hasConsent(.analytics) == true {
loadAnalytics()
}
}
@IBAction func acceptAllTapped(_ sender: UIButton) {
Task {
await ConsentManager.shared.acceptAll()
}
}
}`}
/>
</section>
{/* Consent Categories */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Consent-Kategorien</h2>
<CodeBlock
code={`// Verfuegbare Kategorien
enum ConsentCategory {
case essential // Immer aktiv
case functional // Funktionale Features
case analytics // Statistik & Analyse
case marketing // Werbung & Tracking
case social // Social Media Integration
}
// Consent pruefen
if ConsentManager.shared.hasConsent(.analytics) {
// Analytics laden
}
// Mehrere Kategorien pruefen
if ConsentManager.shared.hasConsent([.analytics, .marketing]) {
// Beide Kategorien haben Consent
}`}
/>
</section>
{/* API Reference */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-4">API Referenz</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Methode</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4"><code className="text-violet-600">configure()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">SDK konfigurieren</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">initialize()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">SDK initialisieren (async)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">hasConsent(_:)</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Consent fuer Kategorie pruefen</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">acceptAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle Kategorien akzeptieren (async)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">rejectAll()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Alle ablehnen (async)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">setConsent(_:)</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Spezifische Kategorien setzen (async)</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">showBanner()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Banner anzeigen</td>
</tr>
<tr>
<td className="px-6 py-4"><code className="text-violet-600">exportConsent()</code></td>
<td className="px-6 py-4 text-sm text-gray-600">Consent-Daten exportieren (DSGVO)</td>
</tr>
</tbody>
</table>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,95 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { ChevronRight, Apple, Smartphone } from 'lucide-react'
const platforms = [
{
name: 'iOS (Swift)',
href: '/developers/sdk/consent/mobile/ios',
description: 'Native Swift SDK fuer iOS 15+ und iPadOS',
features: ['Swift 5.9+', 'iOS 15.0+', 'SwiftUI Support', 'Combine Integration'],
color: 'bg-gray-900',
icon: Apple,
},
{
name: 'Android (Kotlin)',
href: '/developers/sdk/consent/mobile/android',
description: 'Native Kotlin SDK fuer Android API 26+',
features: ['Kotlin 1.9+', 'API 26+', 'Jetpack Compose', 'Coroutines'],
color: 'bg-green-600',
icon: Smartphone,
},
{
name: 'Flutter',
href: '/developers/sdk/consent/mobile/flutter',
description: 'Cross-Platform SDK fuer Flutter 3.16+',
features: ['Dart 3.0+', 'Flutter 3.16+', 'iOS & Android', 'Web Support'],
color: 'bg-blue-500',
icon: Smartphone,
},
]
export default function MobileSDKsPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Mobile SDKs</h1>
<p className="text-lg text-gray-600 mb-8">
Native SDKs fuer iOS, Android und Flutter mit vollstaendiger DSGVO-Konformitaet.
</p>
<div className="space-y-4">
{platforms.map((platform) => (
<Link
key={platform.name}
href={platform.href}
className="block bg-white rounded-xl border border-gray-200 p-6 hover:border-violet-300 hover:shadow-md transition-all group"
>
<div className="flex items-start gap-4">
<div className={`w-12 h-12 rounded-xl ${platform.color} flex items-center justify-center shrink-0`}>
<platform.icon className="w-6 h-6 text-white" />
</div>
<div className="flex-1">
<div className="flex items-center gap-2">
<h2 className="text-xl font-semibold text-gray-900 group-hover:text-violet-600 transition-colors">
{platform.name}
</h2>
<ChevronRight className="w-5 h-5 text-gray-400 group-hover:text-violet-600 transition-colors" />
</div>
<p className="text-gray-600 mt-1">{platform.description}</p>
<div className="flex flex-wrap gap-2 mt-3">
{platform.features.map((feature) => (
<span
key={feature}
className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-md"
>
{feature}
</span>
))}
</div>
</div>
</div>
</Link>
))}
</div>
{/* Cross-Platform Note */}
<div className="mt-8 p-4 bg-blue-50 border border-blue-200 rounded-xl">
<h3 className="font-medium text-blue-900">Cross-Platform Konsistenz</h3>
<p className="text-sm text-blue-700 mt-1">
Alle Mobile SDKs bieten dieselbe API-Oberflaeche wie das Web SDK.
Consent-Daten werden ueber die API synchronisiert, sodass Benutzer auf allen Geraeten
denselben Consent-Status haben.
</p>
</div>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,262 @@
'use client'
import React, { useState } from 'react'
import Link from 'next/link'
import {
Shield, Code, Download, Smartphone, FileCode, Lock,
ChevronRight, Copy, Check, Zap, Globe, Layers,
BookOpen, Terminal
} from 'lucide-react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
type Framework = 'npm' | 'yarn' | 'pnpm'
const installCommands: Record<Framework, string> = {
npm: 'npm install @breakpilot/consent-sdk',
yarn: 'yarn add @breakpilot/consent-sdk',
pnpm: 'pnpm add @breakpilot/consent-sdk',
}
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false)
const handleCopy = async () => {
await navigator.clipboard.writeText(text)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
return (
<button
onClick={handleCopy}
className="p-2 hover:bg-gray-700 rounded transition-colors"
title="Kopieren"
>
{copied ? (
<Check className="w-4 h-4 text-green-400" />
) : (
<Copy className="w-4 h-4 text-gray-400" />
)}
</button>
)
}
export default function ConsentSDKHubPage() {
const [selectedPM, setSelectedPM] = useState<Framework>('npm')
const quickLinks = [
{
title: 'Installation',
description: 'SDK in wenigen Minuten einrichten',
href: '/developers/sdk/consent/installation',
icon: Download,
color: 'bg-blue-500',
},
{
title: 'API Referenz',
description: 'Vollstaendige API-Dokumentation',
href: '/developers/sdk/consent/api-reference',
icon: FileCode,
color: 'bg-purple-500',
},
{
title: 'Frameworks',
description: 'React, Vue, Angular Integration',
href: '/developers/sdk/consent/frameworks',
icon: Layers,
color: 'bg-green-500',
},
{
title: 'Mobile SDKs',
description: 'iOS, Android, Flutter',
href: '/developers/sdk/consent/mobile',
icon: Smartphone,
color: 'bg-orange-500',
},
{
title: 'Sicherheit',
description: 'Best Practices & Compliance',
href: '/developers/sdk/consent/security',
icon: Lock,
color: 'bg-red-500',
},
]
const features = [
{
title: 'DSGVO & TTDSG Konform',
description: 'Vollstaendige Unterstuetzung fuer EU-Datenschutzverordnungen mit revisionssicherer Consent-Speicherung.',
icon: Shield,
},
{
title: 'Google Consent Mode v2',
description: 'Native Integration mit automatischer Synchronisation zu Google Analytics und Ads.',
icon: Globe,
},
{
title: 'Script Blocking',
description: 'Automatisches Blockieren von Third-Party Scripts bis zur Einwilligung.',
icon: Code,
},
{
title: 'Multi-Platform',
description: 'Unterstuetzung fuer Web, PWA, iOS, Android und Flutter aus einer Codebasis.',
icon: Smartphone,
},
]
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-5xl mx-auto px-8 py-12">
{/* Header */}
<div className="mb-12">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-violet-600 to-purple-600 flex items-center justify-center">
<Shield className="w-7 h-7 text-white" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900">Consent SDK</h1>
<div className="flex items-center gap-2 mt-1">
<span className="px-2 py-0.5 bg-green-100 text-green-800 text-xs font-medium rounded-full">
v1.0.0
</span>
<span className="text-sm text-gray-500">DSGVO/TTDSG Compliant</span>
</div>
</div>
</div>
<p className="text-lg text-gray-600 max-w-3xl">
Das Consent SDK ermoeglicht DSGVO-konforme Einwilligungsverwaltung fuer Web, PWA und Mobile Apps.
Mit nativer Unterstuetzung fuer React, Vue, Angular und Mobile Platforms.
</p>
</div>
{/* Quick Install */}
<div className="mb-12 bg-white rounded-xl border border-gray-200 overflow-hidden">
<div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
<h2 className="font-semibold text-gray-900">Schnellinstallation</h2>
<div className="flex gap-1 bg-gray-100 rounded-lg p-1">
{(['npm', 'yarn', 'pnpm'] as const).map((pm) => (
<button
key={pm}
onClick={() => setSelectedPM(pm)}
className={`px-3 py-1 text-sm rounded-md transition-colors ${
selectedPM === pm
? 'bg-white text-gray-900 shadow-sm'
: 'text-gray-600 hover:text-gray-900'
}`}
>
{pm}
</button>
))}
</div>
</div>
<div className="bg-gray-900 px-6 py-4 flex items-center justify-between">
<code className="text-green-400 font-mono text-sm">
$ {installCommands[selectedPM]}
</code>
<CopyButton text={installCommands[selectedPM]} />
</div>
</div>
{/* Quick Links */}
<div className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Dokumentation</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{quickLinks.map((link) => (
<Link
key={link.href}
href={link.href}
className="group p-4 bg-white rounded-xl border border-gray-200 hover:border-violet-300 hover:shadow-md transition-all"
>
<div className="flex items-start gap-3">
<div className={`w-10 h-10 rounded-lg ${link.color} flex items-center justify-center shrink-0`}>
<link.icon className="w-5 h-5 text-white" />
</div>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 group-hover:text-violet-600 transition-colors flex items-center gap-1">
{link.title}
<ChevronRight className="w-4 h-4 opacity-0 group-hover:opacity-100 transition-opacity" />
</h3>
<p className="text-sm text-gray-500 mt-1">{link.description}</p>
</div>
</div>
</Link>
))}
</div>
</div>
{/* Quick Start Code */}
<div className="mb-12 bg-white rounded-xl border border-gray-200 overflow-hidden">
<div className="px-6 py-4 border-b border-gray-200">
<h2 className="font-semibold text-gray-900">Schnellstart</h2>
</div>
<div className="bg-gray-900 p-6">
<pre className="text-sm text-gray-300 font-mono overflow-x-auto">
{`import { ConsentManager } from '@breakpilot/consent-sdk';
// Manager initialisieren
const consent = new ConsentManager({
apiEndpoint: 'https://api.example.com/consent',
siteId: 'your-site-id',
});
// SDK starten
await consent.init();
// Consent pruefen
if (consent.hasConsent('analytics')) {
// Analytics laden
}
// Events abonnieren
consent.on('change', (state) => {
console.log('Consent geaendert:', state);
});`}
</pre>
</div>
</div>
{/* Features */}
<div className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-4">Features</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{features.map((feature) => (
<div
key={feature.title}
className="p-4 bg-white rounded-xl border border-gray-200"
>
<div className="flex items-start gap-3">
<div className="w-10 h-10 rounded-lg bg-violet-100 flex items-center justify-center shrink-0">
<feature.icon className="w-5 h-5 text-violet-600" />
</div>
<div>
<h3 className="font-medium text-gray-900">{feature.title}</h3>
<p className="text-sm text-gray-500 mt-1">{feature.description}</p>
</div>
</div>
</div>
))}
</div>
</div>
{/* Compliance Notice */}
<div className="p-4 bg-blue-50 border border-blue-200 rounded-xl">
<div className="flex items-start gap-3">
<Shield className="w-5 h-5 text-blue-600 mt-0.5" />
<div>
<h3 className="font-medium text-blue-900">DSGVO & TTDSG Compliance</h3>
<p className="text-sm text-blue-700 mt-1">
Das Consent SDK erfuellt alle Anforderungen der DSGVO (Art. 6, 7, 13, 14, 17, 20) und des TTDSG (§ 25).
Alle Einwilligungen werden revisionssicher gespeichert und koennen jederzeit exportiert werden.
</p>
</div>
</div>
</div>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,290 @@
'use client'
import React from 'react'
import { SDKDocsSidebar } from '@/components/developers/SDKDocsSidebar'
import { Shield, Lock, Eye, Database, Key, AlertTriangle, CheckCircle } from 'lucide-react'
function SecurityCard({
title,
description,
icon: Icon,
items,
}: {
title: string
description: string
icon: React.ComponentType<{ className?: string }>
items: string[]
}) {
return (
<div className="bg-white rounded-xl border border-gray-200 p-6">
<div className="flex items-start gap-4">
<div className="w-10 h-10 rounded-lg bg-violet-100 flex items-center justify-center shrink-0">
<Icon className="w-5 h-5 text-violet-600" />
</div>
<div>
<h3 className="font-semibold text-gray-900">{title}</h3>
<p className="text-sm text-gray-600 mt-1">{description}</p>
<ul className="mt-3 space-y-1">
{items.map((item, i) => (
<li key={i} className="flex items-center gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 shrink-0" />
{item}
</li>
))}
</ul>
</div>
</div>
</div>
)
}
export default function SecurityPage() {
return (
<div className="min-h-screen bg-gray-50 flex">
<SDKDocsSidebar />
<main className="flex-1 ml-64">
<div className="max-w-4xl mx-auto px-8 py-12">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Sicherheit & Compliance</h1>
<p className="text-lg text-gray-600 mb-8">
Best Practices fuer sichere Implementierung und DSGVO-konforme Nutzung des Consent SDK.
</p>
{/* Security Features */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-6">Sicherheits-Features</h2>
<div className="grid gap-4">
<SecurityCard
title="Datenverschluesselung"
description="Alle Daten werden verschluesselt uebertragen und gespeichert."
icon={Lock}
items={[
'TLS 1.3 fuer alle API-Kommunikation',
'HMAC-Signatur fuer lokale Storage-Integritaet',
'Keine Klartextspeicherung sensibler Daten',
]}
/>
<SecurityCard
title="Datenschutzkonformes Fingerprinting"
description="Anonymisiertes Fingerprinting ohne invasive Techniken."
icon={Eye}
items={[
'Kein Canvas/WebGL/Audio Fingerprinting',
'Nur anonymisierte Browser-Eigenschaften',
'SHA-256 Hash der Komponenten',
'Nicht eindeutig identifizierend',
]}
/>
<SecurityCard
title="Sichere Speicherung"
description="Lokale Speicherung mit Manipulationsschutz."
icon={Database}
items={[
'Signierte localStorage-Eintraege',
'Automatische Signaturverifikation',
'HttpOnly Cookies fuer SSR',
'SameSite=Lax gegen CSRF',
]}
/>
<SecurityCard
title="API-Sicherheit"
description="Sichere Backend-Kommunikation."
icon={Key}
items={[
'Request-Signierung mit Timestamp',
'Credentials-Include fuer Session-Cookies',
'CORS-Konfiguration erforderlich',
'Rate-Limiting auf Server-Seite',
]}
/>
</div>
</section>
{/* DSGVO Compliance */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-6">DSGVO Compliance</h2>
<div className="bg-white rounded-xl border border-gray-200 overflow-hidden">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
DSGVO Artikel
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
Anforderung
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">
SDK-Unterstuetzung
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Art. 6</td>
<td className="px-6 py-4 text-sm text-gray-600">Rechtmaessigkeit der Verarbeitung</td>
<td className="px-6 py-4">
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
Vollstaendig
</span>
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Art. 7</td>
<td className="px-6 py-4 text-sm text-gray-600">Bedingungen fuer Einwilligung</td>
<td className="px-6 py-4">
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
Vollstaendig
</span>
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Art. 13/14</td>
<td className="px-6 py-4 text-sm text-gray-600">Informationspflichten</td>
<td className="px-6 py-4">
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
Vollstaendig
</span>
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Art. 17</td>
<td className="px-6 py-4 text-sm text-gray-600">Recht auf Loeschung</td>
<td className="px-6 py-4">
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
Vollstaendig
</span>
</td>
</tr>
<tr>
<td className="px-6 py-4 text-sm font-medium text-gray-900">Art. 20</td>
<td className="px-6 py-4 text-sm text-gray-600">Datenportabilitaet</td>
<td className="px-6 py-4">
<span className="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
Vollstaendig
</span>
</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* TTDSG Compliance */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-6">TTDSG Compliance</h2>
<div className="bg-white rounded-xl border border-gray-200 p-6">
<div className="flex items-start gap-4">
<div className="w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center shrink-0">
<Shield className="w-5 h-5 text-blue-600" />
</div>
<div>
<h3 className="font-semibold text-gray-900">§ 25 TTDSG - Schutz der Privatsphaere</h3>
<p className="text-sm text-gray-600 mt-1">
Das SDK erfuellt alle Anforderungen des § 25 TTDSG (Telemediengesetz):
</p>
<ul className="mt-3 space-y-2">
<li className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 shrink-0 mt-0.5" />
<span>
<strong>Einwilligung vor Speicherung:</strong> Cookies und localStorage werden erst nach
Einwilligung gesetzt (ausser technisch notwendige).
</span>
</li>
<li className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 shrink-0 mt-0.5" />
<span>
<strong>Informierte Einwilligung:</strong> Klare Kategorisierung und Beschreibung
aller Cookies und Tracker.
</span>
</li>
<li className="flex items-start gap-2 text-sm text-gray-600">
<CheckCircle className="w-4 h-4 text-green-500 shrink-0 mt-0.5" />
<span>
<strong>Widerrufsrecht:</strong> Jederzeit widerrufbare Einwilligung mit einem Klick.
</span>
</li>
</ul>
</div>
</div>
</div>
</section>
{/* Best Practices */}
<section className="mb-12">
<h2 className="text-xl font-semibold text-gray-900 mb-6">Best Practices</h2>
<div className="space-y-4">
<div className="bg-green-50 border border-green-200 rounded-xl p-4">
<h3 className="font-medium text-green-900 flex items-center gap-2">
<CheckCircle className="w-5 h-5" />
Empfohlen
</h3>
<ul className="mt-2 space-y-1 text-sm text-green-800">
<li> HTTPS fuer alle API-Aufrufe verwenden</li>
<li> Consent-Banner vor dem Laden von Third-Party Scripts anzeigen</li>
<li> Alle Kategorien klar und verstaendlich beschreiben</li>
<li> Ablehnen-Button gleichwertig zum Akzeptieren-Button darstellen</li>
<li> Consent-Aenderungen serverseitig protokollieren</li>
<li> Regelmaessige Ueberpruefung der Consent-Gultigkeit (recheckAfterDays)</li>
</ul>
</div>
<div className="bg-red-50 border border-red-200 rounded-xl p-4">
<h3 className="font-medium text-red-900 flex items-center gap-2">
<AlertTriangle className="w-5 h-5" />
Vermeiden
</h3>
<ul className="mt-2 space-y-1 text-sm text-red-800">
<li> Dark Patterns (versteckte Ablehnen-Buttons)</li>
<li> Pre-checked Consent-Optionen</li>
<li> Tracking vor Einwilligung</li>
<li> Cookie-Walls ohne echte Alternative</li>
<li> Unklare oder irrefuehrende Kategoriebezeichnungen</li>
</ul>
</div>
</div>
</section>
{/* Audit Trail */}
<section>
<h2 className="text-xl font-semibold text-gray-900 mb-6">Audit Trail</h2>
<div className="bg-white rounded-xl border border-gray-200 p-6">
<p className="text-gray-600 mb-4">
Das SDK speichert fuer jeden Consent-Vorgang revisionssichere Daten:
</p>
<div className="bg-gray-50 rounded-lg p-4 font-mono text-sm">
<pre className="text-gray-700">
{`{
"consentId": "consent_abc123...",
"timestamp": "2024-01-15T10:30:00.000Z",
"categories": {
"essential": true,
"analytics": true,
"marketing": false
},
"metadata": {
"userAgent": "Mozilla/5.0...",
"language": "de-DE",
"platform": "web",
"screenResolution": "1920x1080"
},
"signature": "sha256=...",
"version": "1.0.0"
}`}
</pre>
</div>
<p className="text-sm text-gray-500 mt-4">
Diese Daten werden sowohl lokal als auch auf dem Server gespeichert und koennen
jederzeit fuer Audits exportiert werden.
</p>
</div>
</section>
</div>
</main>
</div>
)
}

View File

@@ -0,0 +1,186 @@
import { DevPortalLayout, CodeBlock, InfoBox, ParameterTable } from '@/components/developers/DevPortalLayout'
export default function SDKInstallationPage() {
return (
<DevPortalLayout
title="SDK Installation"
description="Installationsanleitung fuer das AI Compliance SDK"
>
<h2>Voraussetzungen</h2>
<ul>
<li>Node.js 18 oder hoeher</li>
<li>React 18+ / Next.js 14+</li>
<li>TypeScript 5.0+ (empfohlen)</li>
</ul>
<h2>Installation</h2>
<p>
Installieren Sie das SDK ueber Ihren bevorzugten Paketmanager:
</p>
<CodeBlock language="bash" filename="npm">
{`npm install @breakpilot/compliance-sdk`}
</CodeBlock>
<CodeBlock language="bash" filename="yarn">
{`yarn add @breakpilot/compliance-sdk`}
</CodeBlock>
<CodeBlock language="bash" filename="pnpm">
{`pnpm add @breakpilot/compliance-sdk`}
</CodeBlock>
<h2>Peer Dependencies</h2>
<p>
Das SDK hat folgende Peer Dependencies, die automatisch installiert werden sollten:
</p>
<CodeBlock language="json" filename="package.json">
{`{
"peerDependencies": {
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
}
}`}
</CodeBlock>
<h2>Zusaetzliche Pakete (optional)</h2>
<p>
Fuer erweiterte Funktionen koennen Sie folgende Pakete installieren:
</p>
<ParameterTable
parameters={[
{
name: 'jspdf',
type: 'npm package',
required: false,
description: 'Fuer PDF-Export (wird automatisch geladen wenn verfuegbar)',
},
{
name: 'jszip',
type: 'npm package',
required: false,
description: 'Fuer ZIP-Export aller Dokumente',
},
]}
/>
<h2>TypeScript Konfiguration</h2>
<p>
Das SDK ist vollstaendig in TypeScript geschrieben. Stellen Sie sicher,
dass Ihre tsconfig.json folgende Optionen enthaelt:
</p>
<CodeBlock language="json" filename="tsconfig.json">
{`{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}`}
</CodeBlock>
<h2>Next.js Integration</h2>
<p>
Fuer Next.js 14+ mit App Router, fuegen Sie den Provider in Ihr Root-Layout ein:
</p>
<CodeBlock language="typescript" filename="app/layout.tsx">
{`import { SDKProvider } from '@breakpilot/compliance-sdk'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="de">
<body>
<SDKProvider
tenantId={process.env.NEXT_PUBLIC_TENANT_ID!}
apiKey={process.env.BREAKPILOT_API_KEY}
enableBackendSync={true}
>
{children}
</SDKProvider>
</body>
</html>
)
}`}
</CodeBlock>
<InfoBox type="warning" title="Wichtig fuer Server Components">
Der SDKProvider ist ein Client-Component. Wenn Sie Server Components
verwenden, wrappen Sie nur die Teile der App, die das SDK benoetigen.
</InfoBox>
<h2>Umgebungsvariablen</h2>
<p>
Erstellen Sie eine .env.local Datei mit folgenden Variablen:
</p>
<CodeBlock language="bash" filename=".env.local">
{`# Pflicht
NEXT_PUBLIC_TENANT_ID=your-tenant-id
# Optional (fuer Backend-Sync)
BREAKPILOT_API_KEY=sk_live_...
# Optional (fuer Self-Hosted)
NEXT_PUBLIC_SDK_API_URL=https://your-server.com/sdk/v1`}
</CodeBlock>
<InfoBox type="info" title="API Key Sicherheit">
Der API Key sollte niemals im Frontend-Code oder in NEXT_PUBLIC_ Variablen
erscheinen. Verwenden Sie Server-Side API Routes fuer authentifizierte Anfragen.
</InfoBox>
<h2>Verifizierung</h2>
<p>
Testen Sie die Installation mit einer einfachen Komponente:
</p>
<CodeBlock language="typescript" filename="app/test/page.tsx">
{`'use client'
import { useSDK } from '@breakpilot/compliance-sdk'
export default function TestPage() {
const { state, completionPercentage } = useSDK()
return (
<div>
<h1>SDK Test</h1>
<p>Fortschritt: {completionPercentage}%</p>
<p>Aktuelle Phase: {state.currentPhase}</p>
<p>Use Cases: {state.useCases.length}</p>
</div>
)
}`}
</CodeBlock>
<h2>Fehlerbehebung</h2>
<h3>Error: useSDK must be used within SDKProvider</h3>
<p>
Stellen Sie sicher, dass der SDKProvider das gesamte Layout umschliesst
und dass Sie {'\'use client\''} in Client-Komponenten verwenden.
</p>
<h3>Error: Module not found</h3>
<p>
Loeschen Sie node_modules und package-lock.json, dann reinstallieren:
</p>
<CodeBlock language="bash" filename="Terminal">
{`rm -rf node_modules package-lock.json
npm install`}
</CodeBlock>
<h3>TypeScript Errors</h3>
<p>
Stellen Sie sicher, dass TypeScript 5.0+ installiert ist:
</p>
<CodeBlock language="bash" filename="Terminal">
{`npm install typescript@latest`}
</CodeBlock>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,281 @@
import Link from 'next/link'
import { DevPortalLayout, CodeBlock, InfoBox } from '@/components/developers/DevPortalLayout'
export default function SDKOverviewPage() {
return (
<DevPortalLayout
title="SDK Documentation"
description="TypeScript SDK für React und Next.js Integration"
>
<h2>Übersicht</h2>
<p>
Das AI Compliance SDK ist ein TypeScript-Paket für die Integration des
Compliance-Workflows in React und Next.js Anwendungen. Es bietet:
</p>
<ul>
<li>React Context Provider für State Management</li>
<li>Hooks für einfachen Zugriff auf Compliance-Daten</li>
<li>Automatische Synchronisation mit dem Backend</li>
<li>Offline-Support mit localStorage Fallback</li>
<li>Export-Funktionen (PDF, JSON, ZIP)</li>
</ul>
<h2>Kernkomponenten</h2>
<h3>SDKProvider</h3>
<p>
Der Provider wrappet Ihre App und stellt den SDK-Kontext bereit:
</p>
<CodeBlock language="typescript" filename="app/layout.tsx">
{`import { SDKProvider } from '@breakpilot/compliance-sdk'
export default function Layout({ children }) {
return (
<SDKProvider
tenantId="your-tenant"
enableBackendSync={true}
>
{children}
</SDKProvider>
)
}`}
</CodeBlock>
<h3>useSDK Hook</h3>
<p>
Der Haupt-Hook für den Zugriff auf alle SDK-Funktionen:
</p>
<CodeBlock language="typescript" filename="component.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function MyComponent() {
const {
// State
state,
dispatch,
// Navigation
currentStep,
goToStep,
goToNextStep,
goToPreviousStep,
canGoNext,
canGoPrevious,
// Progress
completionPercentage,
phase1Completion,
phase2Completion,
// Checkpoints
validateCheckpoint,
overrideCheckpoint,
getCheckpointStatus,
// Data Updates
updateUseCase,
addRisk,
updateControl,
// Persistence
saveState,
loadState,
// Demo Data
seedDemoData,
clearDemoData,
isDemoDataLoaded,
// Sync
syncState,
forceSyncToServer,
isOnline,
// Export
exportState,
// Command Bar
isCommandBarOpen,
setCommandBarOpen,
} = useSDK()
return (
<div>
<h1>Progress: {completionPercentage}%</h1>
<button onClick={() => goToStep('risks')}>
Zur Risikoanalyse
</button>
</div>
)
}`}
</CodeBlock>
<h2>Types</h2>
<p>
Das SDK exportiert alle TypeScript-Types für volle Typsicherheit:
</p>
<CodeBlock language="typescript" filename="types.ts">
{`import type {
// Core Types
SDKState,
SDKAction,
SDKStep,
SDKPhase,
// Use Cases
UseCaseAssessment,
AssessmentResult,
// Risk Management
Risk,
RiskSeverity,
RiskMitigation,
// Controls & Evidence
Control,
Evidence,
Requirement,
// Checkpoints
Checkpoint,
CheckpointStatus,
ValidationError,
// DSFA
DSFA,
DSFASection,
DSFAApproval,
// TOMs & VVT
TOM,
ProcessingActivity,
RetentionPolicy,
// AI Act
AIActResult,
AIActRiskCategory,
} from '@breakpilot/compliance-sdk'`}
</CodeBlock>
<h2>Utility Functions</h2>
<p>
Hilfreiche Funktionen für die Arbeit mit dem SDK:
</p>
<CodeBlock language="typescript" filename="utils.ts">
{`import {
// Step Navigation
getStepById,
getStepByUrl,
getNextStep,
getPreviousStep,
getStepsForPhase,
// Risk Calculation
calculateRiskScore,
getRiskSeverityFromScore,
calculateResidualRisk,
// Progress
getCompletionPercentage,
getPhaseCompletionPercentage,
} from '@breakpilot/compliance-sdk'
// Beispiel: Risk Score berechnen
const inherentRisk = calculateRiskScore(4, 5) // likelihood * impact = 20
const severity = getRiskSeverityFromScore(20) // 'CRITICAL'`}
</CodeBlock>
<h2>API Client</h2>
<p>
Für direkten API-Zugriff ohne React Context:
</p>
<CodeBlock language="typescript" filename="api.ts">
{`import {
getSDKApiClient,
SDKApiClient,
} from '@breakpilot/compliance-sdk'
const client = getSDKApiClient('your-tenant-id')
// State laden
const state = await client.getState()
// State speichern
await client.saveState(updatedState)
// Checkpoint validieren
const result = await client.validateCheckpoint('CP-UC', state)
// Export
const blob = await client.exportState('pdf')`}
</CodeBlock>
<h2>RAG & LLM Client</h2>
<p>
Zugriff auf die RAG-Suche und Dokumentengenerierung:
</p>
<CodeBlock language="typescript" filename="rag.ts">
{`import {
getSDKBackendClient,
isLegalQuery,
} from '@breakpilot/compliance-sdk'
const client = getSDKBackendClient()
// RAG-Suche
const results = await client.search('DSGVO Art. 5', 5)
console.log(results) // SearchResult[]
// Dokumentengenerierung
const dsfa = await client.generateDSFA(context)
const toms = await client.generateTOM(context)
const vvt = await client.generateVVT(context)
// Prüfen ob eine Query rechtliche Inhalte betrifft
if (isLegalQuery('Einwilligung DSGVO')) {
// RAG-Suche durchführen
}`}
</CodeBlock>
<h2>Export</h2>
<p>
Exportieren Sie Compliance-Daten in verschiedenen Formaten:
</p>
<CodeBlock language="typescript" filename="export.ts">
{`import { exportToPDF, exportToZIP, downloadExport } from '@breakpilot/compliance-sdk'
// PDF Export
const pdfBlob = await exportToPDF(state)
downloadExport(pdfBlob, 'compliance-report.pdf')
// ZIP Export (alle Dokumente)
const zipBlob = await exportToZIP(state)
downloadExport(zipBlob, 'compliance-export.zip')
// Über den Hook
const { exportState } = useSDK()
const blob = await exportState('pdf') // 'json' | 'pdf' | 'zip'`}
</CodeBlock>
<InfoBox type="success" title="Weitere Dokumentation">
<ul className="list-disc list-inside space-y-1">
<li>
<Link href="/developers/sdk/installation" className="text-blue-600 hover:underline">
Installation Guide
</Link>
</li>
<li>
<Link href="/developers/sdk/configuration" className="text-blue-600 hover:underline">
Konfigurationsoptionen
</Link>
</li>
<li>
<Link href="/developers/guides/phase1" className="text-blue-600 hover:underline">
Phase 1 Workflow Guide
</Link>
</li>
</ul>
</InfoBox>
</DevPortalLayout>
)
}