feat: Extract Developer Portal as standalone Next.js app on port 3006

SDK customers can now access the documentation publicly without login.
The portal runs independently from admin-v2 on https://macmini:3006/.

- New developer-portal/ app with 26 pages, 2 components
- Docker service + nginx SSL reverse proxy on port 3006
- All /developers/* routes remapped to /* in the new app
- admin-v2 developer pages remain unchanged

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-09 17:15:54 +01:00
parent bba975be28
commit 09dd1487b4
39 changed files with 7646 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
node_modules
.next
.git
.gitignore
README.md
*.log
.env.local
.env.*.local

View File

@@ -0,0 +1,45 @@
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
# Install dependencies
RUN npm install
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM node:20-alpine AS runner
WORKDIR /app
# Set to production
ENV NODE_ENV=production
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy built assets
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
# Set hostname
ENV HOSTNAME="0.0.0.0"
# Start the application
CMD ["node", "server.js"]

View File

@@ -0,0 +1,271 @@
import { DevPortalLayout, ApiEndpoint, CodeBlock, ParameterTable, InfoBox } from '@/components/DevPortalLayout'
export default function ExportApiPage() {
return (
<DevPortalLayout
title="Export API"
description="Exportieren Sie Compliance-Daten in verschiedenen Formaten"
>
<h2>Uebersicht</h2>
<p>
Die Export API ermoeglicht den Download aller Compliance-Daten in
verschiedenen Formaten fuer Audits, Dokumentation und Archivierung.
</p>
<h2>Unterstuetzte Formate</h2>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Format</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Use Case</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3 font-mono">json</td>
<td className="px-4 py-3 text-gray-600">Kompletter State als JSON</td>
<td className="px-4 py-3 text-gray-600">Backup, Migration, API-Integration</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono">pdf</td>
<td className="px-4 py-3 text-gray-600">Formatierter PDF-Report</td>
<td className="px-4 py-3 text-gray-600">Audits, Management-Reports</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono">zip</td>
<td className="px-4 py-3 text-gray-600">Alle Dokumente als ZIP-Archiv</td>
<td className="px-4 py-3 text-gray-600">Vollstaendige Dokumentation</td>
</tr>
</tbody>
</table>
</div>
<h2>GET /export</h2>
<p>Exportiert den aktuellen State im gewuenschten Format.</p>
<h3>Query-Parameter</h3>
<ParameterTable
parameters={[
{
name: 'format',
type: 'string',
required: true,
description: 'Export-Format: json, pdf, zip',
},
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Tenant-ID',
},
{
name: 'sections',
type: 'string',
required: false,
description: 'Kommaseparierte Liste: useCases,risks,controls,dsfa,toms,vvt (default: alle)',
},
{
name: 'phase',
type: 'number',
required: false,
description: 'Nur bestimmte Phase exportieren: 1 oder 2',
},
{
name: 'language',
type: 'string',
required: false,
description: 'Sprache fuer PDF: de, en (default: de)',
},
]}
/>
<h2>JSON Export</h2>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/export?format=json&tenantId=your-tenant-id" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-o compliance-export.json`}
</CodeBlock>
<h3>Response</h3>
<CodeBlock language="json" filename="compliance-export.json">
{`{
"exportedAt": "2026-02-04T12:00:00Z",
"version": "1.0.0",
"tenantId": "your-tenant-id",
"state": {
"currentPhase": 2,
"currentStep": "dsfa",
"completedSteps": [...],
"useCases": [...],
"risks": [...],
"controls": [...],
"dsfa": {...},
"toms": [...],
"vvt": [...]
},
"meta": {
"completionPercentage": 75,
"lastModified": "2026-02-04T11:55:00Z"
}
}`}
</CodeBlock>
<h2>PDF Export</h2>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/export?format=pdf&tenantId=your-tenant-id&sections=dsfa,toms" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-o compliance-report.pdf`}
</CodeBlock>
<h3>PDF Inhalt</h3>
<p>Das generierte PDF enthaelt:</p>
<ul>
<li>Deckblatt mit Tenant-Info und Exportdatum</li>
<li>Inhaltsverzeichnis</li>
<li>Executive Summary mit Fortschritt</li>
<li>Use Case Uebersicht</li>
<li>Risikoanalyse mit Matrix-Visualisierung</li>
<li>DSFA (falls generiert)</li>
<li>TOM-Katalog</li>
<li>VVT-Auszug</li>
<li>Checkpoint-Status</li>
</ul>
<InfoBox type="info" title="PDF Styling">
Das PDF folgt einem professionellen Audit-Layout mit Corporate Design.
Enterprise-Kunden koennen ein Custom-Logo und Farbschema konfigurieren.
</InfoBox>
<h2>ZIP Export</h2>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/export?format=zip&tenantId=your-tenant-id" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-o compliance-export.zip`}
</CodeBlock>
<h3>ZIP Struktur</h3>
<CodeBlock language="text" filename="compliance-export.zip">
{`compliance-export/
├── README.md
├── state.json # Kompletter State
├── summary.pdf # Executive Summary
├── use-cases/
│ ├── uc-1-ki-analyse.json
│ └── uc-2-chatbot.json
├── risks/
│ ├── risk-matrix.pdf
│ └── risks.json
├── documents/
│ ├── dsfa.pdf
│ ├── dsfa.json
│ ├── toms.pdf
│ ├── toms.json
│ ├── vvt.pdf
│ └── vvt.json
├── checkpoints/
│ └── checkpoint-status.json
└── audit-trail/
└── changes.json`}
</CodeBlock>
<h2>SDK Integration</h2>
<CodeBlock language="typescript" filename="export-examples.ts">
{`import { useSDK, exportToPDF, exportToZIP, downloadExport } from '@breakpilot/compliance-sdk'
// Option 1: Ueber den Hook
function ExportButton() {
const { exportState } = useSDK()
const handlePDFExport = async () => {
const blob = await exportState('pdf')
downloadExport(blob, 'compliance-report.pdf')
}
const handleZIPExport = async () => {
const blob = await exportState('zip')
downloadExport(blob, 'compliance-export.zip')
}
const handleJSONExport = async () => {
const blob = await exportState('json')
downloadExport(blob, 'compliance-state.json')
}
return (
<div className="flex gap-2">
<button onClick={handlePDFExport}>PDF Export</button>
<button onClick={handleZIPExport}>ZIP Export</button>
<button onClick={handleJSONExport}>JSON Export</button>
</div>
)
}
// Option 2: Direkte Funktionen
async function exportManually(state: SDKState) {
// PDF generieren
const pdfBlob = await exportToPDF(state)
downloadExport(pdfBlob, \`compliance-\${Date.now()}.pdf\`)
// ZIP generieren
const zipBlob = await exportToZIP(state)
downloadExport(zipBlob, \`compliance-\${Date.now()}.zip\`)
}`}
</CodeBlock>
<h2>Command Bar Integration</h2>
<p>
Exporte sind auch ueber die Command Bar verfuegbar:
</p>
<CodeBlock language="text" filename="Command Bar">
{`Cmd+K → "pdf" → "Als PDF exportieren"
Cmd+K → "zip" → "Als ZIP exportieren"
Cmd+K → "json" → "Als JSON exportieren"`}
</CodeBlock>
<h2>Automatisierte Exports</h2>
<p>
Fuer regelmaessige Backups oder CI/CD-Integration:
</p>
<CodeBlock language="bash" filename="Cron Job">
{`# Taeglicher Backup-Export um 02:00 Uhr
0 2 * * * curl -X GET "https://api.breakpilot.io/sdk/v1/export?format=zip&tenantId=my-tenant" \\
-H "Authorization: Bearer $API_KEY" \\
-o "/backups/compliance-$(date +%Y%m%d).zip"`}
</CodeBlock>
<InfoBox type="warning" title="Dateigröße">
ZIP-Exporte koennen bei umfangreichen States mehrere MB gross werden.
Die API hat ein Timeout von 60 Sekunden. Bei sehr grossen States
verwenden Sie den asynchronen Export-Endpoint (Enterprise).
</InfoBox>
<h2>Fehlerbehandlung</h2>
<CodeBlock language="typescript" filename="error-handling.ts">
{`import { exportState } from '@breakpilot/compliance-sdk'
try {
const blob = await exportState('pdf')
downloadExport(blob, 'report.pdf')
} catch (error) {
if (error.code === 'EMPTY_STATE') {
console.error('Keine Daten zum Exportieren vorhanden')
} else if (error.code === 'GENERATION_FAILED') {
console.error('PDF-Generierung fehlgeschlagen:', error.message)
} else if (error.code === 'TIMEOUT') {
console.error('Export-Timeout - versuchen Sie ZIP fuer grosse States')
} else {
console.error('Unbekannter Fehler:', error)
}
}`}
</CodeBlock>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,381 @@
import { DevPortalLayout, ApiEndpoint, CodeBlock, ParameterTable, InfoBox } from '@/components/DevPortalLayout'
export default function GenerateApiPage() {
return (
<DevPortalLayout
title="Generation API"
description="Automatische Generierung von Compliance-Dokumenten"
>
<h2>Uebersicht</h2>
<p>
Die Generation API nutzt LLM-Technologie (Claude) zur automatischen Erstellung
von Compliance-Dokumenten basierend auf Ihrem SDK-State:
</p>
<ul>
<li><strong>DSFA</strong> - Datenschutz-Folgenabschaetzung</li>
<li><strong>TOM</strong> - Technische und Organisatorische Massnahmen</li>
<li><strong>VVT</strong> - Verarbeitungsverzeichnis nach Art. 30 DSGVO</li>
</ul>
<InfoBox type="info" title="LLM-Model">
Die Generierung verwendet Claude 3.5 Sonnet fuer optimale Qualitaet
bei deutschen Rechtstexten. RAG-Context wird automatisch einbezogen.
</InfoBox>
<h2>POST /generate/dsfa</h2>
<p>Generiert eine Datenschutz-Folgenabschaetzung basierend auf dem aktuellen State.</p>
<h3>Request Body</h3>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Tenant-ID fuer State-Zugriff',
},
{
name: 'useCaseId',
type: 'string',
required: false,
description: 'Optional: Nur fuer bestimmten Use Case generieren',
},
{
name: 'includeRisks',
type: 'boolean',
required: false,
description: 'Risiken aus Risk Matrix einbeziehen (default: true)',
},
{
name: 'includeControls',
type: 'boolean',
required: false,
description: 'Bestehende Controls referenzieren (default: true)',
},
{
name: 'language',
type: 'string',
required: false,
description: 'Sprache: de, en (default: de)',
},
]}
/>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X POST "https://api.breakpilot.io/sdk/v1/generate/dsfa" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"tenantId": "your-tenant-id",
"useCaseId": "uc-ki-kundenanalyse",
"includeRisks": true,
"includeControls": true,
"language": "de"
}'`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"dsfa": {
"id": "dsfa-2026-02-04-abc123",
"version": "1.0",
"status": "DRAFT",
"createdAt": "2026-02-04T12:00:00Z",
"useCase": {
"id": "uc-ki-kundenanalyse",
"name": "KI-gestuetzte Kundenanalyse",
"description": "Analyse von Kundenverhalten mittels ML..."
},
"sections": {
"systematicDescription": {
"title": "1. Systematische Beschreibung",
"content": "Die geplante Verarbeitungstaetigkeit umfasst..."
},
"necessityAssessment": {
"title": "2. Bewertung der Notwendigkeit",
"content": "Die Verarbeitung ist notwendig fuer..."
},
"riskAssessment": {
"title": "3. Risikobewertung",
"risks": [
{
"id": "risk-1",
"title": "Unbefugter Datenzugriff",
"severity": "HIGH",
"likelihood": 3,
"impact": 4,
"description": "...",
"mitigations": ["Verschluesselung", "Zugriffskontrolle"]
}
]
},
"mitigationMeasures": {
"title": "4. Abhilfemassnahmen",
"controls": [...]
},
"stakeholderConsultation": {
"title": "5. Einbeziehung Betroffener",
"content": "..."
},
"dpoOpinion": {
"title": "6. Stellungnahme des DSB",
"content": "Ausstehend - Freigabe erforderlich"
}
},
"conclusion": {
"overallRisk": "MEDIUM",
"recommendation": "PROCEED_WITH_CONDITIONS",
"conditions": [
"Implementierung der TOM-Empfehlungen",
"Regelmaessige Ueberpruefung"
]
}
},
"generationMeta": {
"model": "claude-3.5-sonnet",
"ragContextUsed": true,
"tokensUsed": 4250,
"durationMs": 8500
}
}
}`}
</CodeBlock>
<h2>POST /generate/tom</h2>
<p>Generiert technische und organisatorische Massnahmen.</p>
<h3>Request Body</h3>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Tenant-ID',
},
{
name: 'categories',
type: 'string[]',
required: false,
description: 'TOM-Kategorien: access_control, encryption, pseudonymization, etc.',
},
{
name: 'basedOnRisks',
type: 'boolean',
required: false,
description: 'TOMs basierend auf Risk Matrix generieren (default: true)',
},
]}
/>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X POST "https://api.breakpilot.io/sdk/v1/generate/tom" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"tenantId": "your-tenant-id",
"categories": ["access_control", "encryption", "backup"],
"basedOnRisks": true
}'`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"toms": [
{
"id": "tom-1",
"category": "access_control",
"categoryLabel": "Zugangskontrolle",
"title": "Multi-Faktor-Authentifizierung",
"description": "Implementierung von MFA fuer alle Systemzugaenge",
"technicalMeasures": [
"TOTP-basierte 2FA",
"Hardware Security Keys (FIDO2)"
],
"organizationalMeasures": [
"Schulung der Mitarbeiter",
"Dokumentation der Zugaenge"
],
"article32Reference": "Art. 32 Abs. 1 lit. b DSGVO",
"priority": "HIGH",
"implementationStatus": "PLANNED"
},
{
"id": "tom-2",
"category": "encryption",
"categoryLabel": "Verschluesselung",
"title": "Transportverschluesselung",
"description": "TLS 1.3 fuer alle Datenuebert\\\\ragungen",
"technicalMeasures": [
"TLS 1.3 mit PFS",
"HSTS Header"
],
"organizationalMeasures": [
"Zertifikatsmanagement",
"Regelmaessige Audits"
],
"article32Reference": "Art. 32 Abs. 1 lit. a DSGVO",
"priority": "CRITICAL",
"implementationStatus": "IMPLEMENTED"
}
],
"summary": {
"totalMeasures": 20,
"byCategory": {
"access_control": 5,
"encryption": 4,
"backup": 3,
"monitoring": 4,
"incident_response": 4
},
"implementationProgress": {
"implemented": 12,
"in_progress": 5,
"planned": 3
}
}
}
}`}
</CodeBlock>
<h2>POST /generate/vvt</h2>
<p>Generiert ein Verarbeitungsverzeichnis nach Art. 30 DSGVO.</p>
<h3>Request Body</h3>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Tenant-ID',
},
{
name: 'organizationInfo',
type: 'object',
required: false,
description: 'Organisationsdaten (Name, Anschrift, DSB-Kontakt)',
},
{
name: 'includeRetentionPolicies',
type: 'boolean',
required: false,
description: 'Loeschfristen einbeziehen (default: true)',
},
]}
/>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X POST "https://api.breakpilot.io/sdk/v1/generate/vvt" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"tenantId": "your-tenant-id",
"organizationInfo": {
"name": "Beispiel GmbH",
"address": "Musterstrasse 1, 10115 Berlin",
"dpoContact": "datenschutz@beispiel.de"
},
"includeRetentionPolicies": true
}'`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"vvt": {
"id": "vvt-2026-02-04",
"version": "1.0",
"organization": {
"name": "Beispiel GmbH",
"address": "Musterstrasse 1, 10115 Berlin",
"dpoContact": "datenschutz@beispiel.de"
},
"processingActivities": [
{
"id": "pa-1",
"name": "Kundendatenverarbeitung",
"purpose": "Vertragserfuellung und Kundenservice",
"legalBasis": "Art. 6 Abs. 1 lit. b DSGVO",
"dataCategories": ["Kontaktdaten", "Vertragsdaten", "Zahlungsdaten"],
"dataSubjects": ["Kunden", "Interessenten"],
"recipients": ["Zahlungsdienstleister", "Versanddienstleister"],
"thirdCountryTransfers": {
"exists": false,
"countries": [],
"safeguards": null
},
"retentionPeriod": "10 Jahre nach Vertragsende (HGB)",
"technicalMeasures": ["Verschluesselung", "Zugriffskontrolle"]
}
],
"lastUpdated": "2026-02-04T12:00:00Z"
}
}
}`}
</CodeBlock>
<h2>SDK Integration</h2>
<CodeBlock language="typescript" filename="document-generation.ts">
{`import { getSDKBackendClient } from '@breakpilot/compliance-sdk'
const client = getSDKBackendClient()
// DSFA generieren
async function generateDSFA(useCaseId: string) {
const dsfa = await client.generateDSFA({
useCaseId,
includeRisks: true,
includeControls: true,
})
console.log('DSFA generiert:', dsfa.id)
console.log('Gesamtrisiko:', dsfa.conclusion.overallRisk)
return dsfa
}
// TOMs generieren
async function generateTOMs() {
const toms = await client.generateTOM({
categories: ['access_control', 'encryption'],
basedOnRisks: true,
})
console.log(\`\${toms.length} TOMs generiert\`)
return toms
}
// VVT generieren
async function generateVVT() {
const vvt = await client.generateVVT({
organizationInfo: {
name: 'Beispiel GmbH',
address: 'Musterstrasse 1',
dpoContact: 'dpo@beispiel.de',
},
})
console.log(\`VVT mit \${vvt.processingActivities.length} Verarbeitungen\`)
return vvt
}`}
</CodeBlock>
<InfoBox type="warning" title="Kosten">
Die Dokumentengenerierung verbraucht LLM-Tokens. Durchschnittliche Kosten:
DSFA ~5.000 Tokens, TOMs ~3.000 Tokens, VVT ~4.000 Tokens.
Enterprise-Kunden haben unbegrenzte Generierungen.
</InfoBox>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,239 @@
import Link from 'next/link'
import { DevPortalLayout, ApiEndpoint, InfoBox } from '@/components/DevPortalLayout'
export default function ApiReferencePage() {
return (
<DevPortalLayout
title="API Reference"
description="Vollständige REST API Dokumentation"
>
<h2>Base URL</h2>
<p>
Alle API-Endpunkte sind unter folgender Basis-URL erreichbar:
</p>
<div className="bg-gray-100 p-4 rounded-lg font-mono text-sm my-4">
https://api.breakpilot.io/sdk/v1
</div>
<p>
Für Self-Hosted-Installationen verwenden Sie Ihre eigene Domain.
</p>
<h2>Authentifizierung</h2>
<p>
Alle API-Anfragen erfordern einen gültigen API Key im Header:
</p>
<div className="bg-gray-100 p-4 rounded-lg font-mono text-sm my-4">
Authorization: Bearer YOUR_API_KEY
</div>
<InfoBox type="info" title="Tenant-ID">
Die Tenant-ID wird aus dem API Key abgeleitet oder kann explizit
als Query-Parameter oder im Request-Body mitgegeben werden.
</InfoBox>
<h2>API Endpoints</h2>
<h3>State Management</h3>
<p>
Verwalten Sie den SDK-State für Ihren Tenant.
</p>
<ApiEndpoint
method="GET"
path="/state/{tenantId}"
description="Lädt den aktuellen SDK-State für einen Tenant"
/>
<ApiEndpoint
method="POST"
path="/state"
description="Speichert den SDK-State (mit Versionierung)"
/>
<ApiEndpoint
method="DELETE"
path="/state/{tenantId}"
description="Löscht den State für einen Tenant"
/>
<p>
<Link href="/api/state" className="text-blue-600 hover:underline">
Vollständige State API Dokumentation
</Link>
</p>
<h3>RAG Search</h3>
<p>
Durchsuchen Sie den Compliance-Korpus (DSGVO, AI Act, NIS2).
</p>
<ApiEndpoint
method="GET"
path="/rag/search"
description="Semantische Suche im Legal Corpus"
/>
<ApiEndpoint
method="GET"
path="/rag/status"
description="Status des RAG-Systems und Corpus-Informationen"
/>
<p>
<Link href="/api/rag" className="text-blue-600 hover:underline">
Vollständige RAG API Dokumentation
</Link>
</p>
<h3>Document Generation</h3>
<p>
Generieren Sie Compliance-Dokumente automatisch.
</p>
<ApiEndpoint
method="POST"
path="/generate/dsfa"
description="Generiert eine Datenschutz-Folgenabschätzung"
/>
<ApiEndpoint
method="POST"
path="/generate/tom"
description="Generiert technische und organisatorische Maßnahmen"
/>
<ApiEndpoint
method="POST"
path="/generate/vvt"
description="Generiert ein Verarbeitungsverzeichnis"
/>
<p>
<Link href="/api/generate" className="text-blue-600 hover:underline">
Vollständige Generation API Dokumentation
</Link>
</p>
<h3>Export</h3>
<p>
Exportieren Sie den Compliance-Stand in verschiedenen Formaten.
</p>
<ApiEndpoint
method="GET"
path="/export"
description="Exportiert den State (JSON, PDF, ZIP)"
/>
<p>
<Link href="/api/export" className="text-blue-600 hover:underline">
Vollständige Export API Dokumentation
</Link>
</p>
<h2>Response Format</h2>
<p>
Alle Responses folgen einem einheitlichen Format:
</p>
<h3>Erfolgreiche Response</h3>
<div className="bg-gray-900 text-gray-100 p-4 rounded-lg font-mono text-sm my-4">
{`{
"success": true,
"data": { ... },
"meta": {
"version": 1,
"timestamp": "2026-02-04T12:00:00Z"
}
}`}
</div>
<h3>Fehler Response</h3>
<div className="bg-gray-900 text-gray-100 p-4 rounded-lg font-mono text-sm my-4">
{`{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Tenant ID is required",
"details": { ... }
}
}`}
</div>
<h2>Error Codes</h2>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">HTTP Status</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Code</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3">400</td>
<td className="px-4 py-3 font-mono text-red-600">VALIDATION_ERROR</td>
<td className="px-4 py-3 text-gray-600">Ungültige Request-Daten</td>
</tr>
<tr>
<td className="px-4 py-3">401</td>
<td className="px-4 py-3 font-mono text-red-600">UNAUTHORIZED</td>
<td className="px-4 py-3 text-gray-600">Fehlender oder ungültiger API Key</td>
</tr>
<tr>
<td className="px-4 py-3">403</td>
<td className="px-4 py-3 font-mono text-red-600">FORBIDDEN</td>
<td className="px-4 py-3 text-gray-600">Keine Berechtigung für diese Ressource</td>
</tr>
<tr>
<td className="px-4 py-3">404</td>
<td className="px-4 py-3 font-mono text-red-600">NOT_FOUND</td>
<td className="px-4 py-3 text-gray-600">Ressource nicht gefunden</td>
</tr>
<tr>
<td className="px-4 py-3">409</td>
<td className="px-4 py-3 font-mono text-red-600">CONFLICT</td>
<td className="px-4 py-3 text-gray-600">Versions-Konflikt (Optimistic Locking)</td>
</tr>
<tr>
<td className="px-4 py-3">429</td>
<td className="px-4 py-3 font-mono text-red-600">RATE_LIMITED</td>
<td className="px-4 py-3 text-gray-600">Zu viele Anfragen</td>
</tr>
<tr>
<td className="px-4 py-3">500</td>
<td className="px-4 py-3 font-mono text-red-600">INTERNAL_ERROR</td>
<td className="px-4 py-3 text-gray-600">Interner Server-Fehler</td>
</tr>
</tbody>
</table>
</div>
<h2>Rate Limits</h2>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Plan</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Requests/Minute</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Requests/Tag</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3">Starter</td>
<td className="px-4 py-3">60</td>
<td className="px-4 py-3">10.000</td>
</tr>
<tr>
<td className="px-4 py-3">Professional</td>
<td className="px-4 py-3">300</td>
<td className="px-4 py-3">100.000</td>
</tr>
<tr>
<td className="px-4 py-3">Enterprise</td>
<td className="px-4 py-3">Unbegrenzt</td>
<td className="px-4 py-3">Unbegrenzt</td>
</tr>
</tbody>
</table>
</div>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,248 @@
import { DevPortalLayout, ApiEndpoint, CodeBlock, ParameterTable, InfoBox } from '@/components/DevPortalLayout'
export default function RAGApiPage() {
return (
<DevPortalLayout
title="RAG API"
description="Semantische Suche im Legal Corpus (DSGVO, AI Act, NIS2)"
>
<h2>Uebersicht</h2>
<p>
Die RAG (Retrieval-Augmented Generation) API ermoeglicht semantische Suche
im Compliance-Korpus. Der Korpus enthaelt:
</p>
<ul>
<li>DSGVO (Datenschutz-Grundverordnung)</li>
<li>AI Act (EU KI-Verordnung)</li>
<li>NIS2 (Netzwerk- und Informationssicherheit)</li>
<li>ePrivacy-Verordnung</li>
<li>Bundesdatenschutzgesetz (BDSG)</li>
</ul>
<InfoBox type="info" title="Embedding-Modell">
Die Suche verwendet BGE-M3 Embeddings fuer praezise semantische Aehnlichkeit.
Die Vektoren werden in Qdrant gespeichert.
</InfoBox>
<h2>GET /rag/search</h2>
<p>Durchsucht den Legal Corpus semantisch.</p>
<h3>Query-Parameter</h3>
<ParameterTable
parameters={[
{
name: 'q',
type: 'string',
required: true,
description: 'Die Suchanfrage (z.B. "Einwilligung personenbezogene Daten")',
},
{
name: 'top_k',
type: 'number',
required: false,
description: 'Anzahl der Ergebnisse (default: 5, max: 20)',
},
{
name: 'corpus',
type: 'string',
required: false,
description: 'Einschraenkung auf bestimmten Corpus: dsgvo, ai_act, nis2, all (default: all)',
},
{
name: 'min_score',
type: 'number',
required: false,
description: 'Minimaler Relevanz-Score 0-1 (default: 0.5)',
},
]}
/>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/rag/search?q=Einwilligung%20DSGVO&top_k=5" \\
-H "Authorization: Bearer YOUR_API_KEY"`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"query": "Einwilligung DSGVO",
"results": [
{
"id": "dsgvo-art-7",
"title": "Art. 7 DSGVO - Bedingungen fuer die Einwilligung",
"content": "Beruht die Verarbeitung auf einer Einwilligung, muss der Verantwortliche nachweisen koennen, dass die betroffene Person in die Verarbeitung ihrer personenbezogenen Daten eingewilligt hat...",
"corpus": "dsgvo",
"article": "Art. 7",
"score": 0.92,
"metadata": {
"chapter": "II",
"section": "Einwilligung",
"url": "https://dsgvo-gesetz.de/art-7-dsgvo/"
}
},
{
"id": "dsgvo-art-6-1-a",
"title": "Art. 6 Abs. 1 lit. a DSGVO - Einwilligung als Rechtsgrundlage",
"content": "Die Verarbeitung ist nur rechtmaessig, wenn mindestens eine der nachstehenden Bedingungen erfuellt ist: a) Die betroffene Person hat ihre Einwilligung...",
"corpus": "dsgvo",
"article": "Art. 6",
"score": 0.88,
"metadata": {
"chapter": "II",
"section": "Rechtmaessigkeit",
"url": "https://dsgvo-gesetz.de/art-6-dsgvo/"
}
}
],
"total_results": 2,
"search_time_ms": 45
},
"meta": {
"corpus_version": "2026-01",
"embedding_model": "bge-m3"
}
}`}
</CodeBlock>
<h2>GET /rag/status</h2>
<p>Gibt Status-Informationen ueber das RAG-System zurueck.</p>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/rag/status" \\
-H "Authorization: Bearer YOUR_API_KEY"`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"status": "healthy",
"corpus": {
"dsgvo": {
"documents": 99,
"chunks": 1250,
"last_updated": "2026-01-15T00:00:00Z"
},
"ai_act": {
"documents": 89,
"chunks": 980,
"last_updated": "2026-01-20T00:00:00Z"
},
"nis2": {
"documents": 46,
"chunks": 520,
"last_updated": "2026-01-10T00:00:00Z"
}
},
"embedding_service": {
"status": "online",
"model": "bge-m3",
"dimension": 1024
},
"vector_db": {
"type": "qdrant",
"collections": 3,
"total_vectors": 2750
}
}
}`}
</CodeBlock>
<h2>SDK Integration</h2>
<p>
Verwenden Sie den SDK-Client fuer einfache RAG-Suche:
</p>
<CodeBlock language="typescript" filename="rag-search.ts">
{`import { getSDKBackendClient, isLegalQuery } from '@breakpilot/compliance-sdk'
const client = getSDKBackendClient()
// Pruefen ob die Query rechtliche Inhalte betrifft
if (isLegalQuery('Was ist eine Einwilligung?')) {
// RAG-Suche durchfuehren
const results = await client.search('Einwilligung DSGVO', 5)
results.forEach(result => {
console.log(\`[\${result.corpus}] \${result.title}\`)
console.log(\`Score: \${result.score}\`)
console.log(\`URL: \${result.metadata.url}\`)
console.log('---')
})
}`}
</CodeBlock>
<h2>Keyword-Erkennung</h2>
<p>
Die Funktion <code>isLegalQuery</code> erkennt automatisch rechtliche Anfragen:
</p>
<CodeBlock language="typescript" filename="keyword-detection.ts">
{`import { isLegalQuery } from '@breakpilot/compliance-sdk'
// Gibt true zurueck fuer:
isLegalQuery('DSGVO Art. 5') // true - Artikel-Referenz
isLegalQuery('Einwilligung') // true - DSGVO-Begriff
isLegalQuery('AI Act Hochrisiko') // true - AI Act Begriff
isLegalQuery('NIS2 Richtlinie') // true - NIS2 Referenz
isLegalQuery('personenbezogene Daten') // true - Datenschutz-Begriff
// Gibt false zurueck fuer:
isLegalQuery('Wie ist das Wetter?') // false - Keine rechtliche Anfrage
isLegalQuery('Programmiere mir X') // false - Technische Anfrage`}
</CodeBlock>
<h2>Beispiel: Command Bar Integration</h2>
<CodeBlock language="typescript" filename="command-bar-rag.tsx">
{`import { useState } from 'react'
import { getSDKBackendClient, isLegalQuery } from '@breakpilot/compliance-sdk'
function CommandBarSearch({ query }: { query: string }) {
const [results, setResults] = useState([])
const [loading, setLoading] = useState(false)
useEffect(() => {
if (query.length > 3 && isLegalQuery(query)) {
setLoading(true)
const client = getSDKBackendClient()
client.search(query, 3).then(data => {
setResults(data)
setLoading(false)
})
}
}, [query])
if (!isLegalQuery(query)) return null
return (
<div className="rag-results">
{loading ? (
<p>Suche im Legal Corpus...</p>
) : (
results.map(result => (
<div key={result.id} className="result-card">
<h4>{result.title}</h4>
<p>{result.content.slice(0, 200)}...</p>
<a href={result.metadata.url} target="_blank">
Volltext lesen
</a>
</div>
))
)}
</div>
)
}`}
</CodeBlock>
<InfoBox type="warning" title="Rate Limits">
Die RAG-Suche ist auf 100 Anfragen/Minute (Professional) bzw.
unbegrenzt (Enterprise) limitiert. Implementieren Sie Client-Side
Debouncing fuer Echtzeit-Suche.
</InfoBox>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,266 @@
import { DevPortalLayout, ApiEndpoint, CodeBlock, ParameterTable, InfoBox } from '@/components/DevPortalLayout'
export default function StateApiPage() {
return (
<DevPortalLayout
title="State API"
description="Verwalten Sie den SDK-State für Ihren Tenant"
>
<h2>Übersicht</h2>
<p>
Die State API ermöglicht das Speichern und Abrufen des kompletten SDK-States.
Der State enthält alle Compliance-Daten: Use Cases, Risiken, Controls,
Checkpoints und mehr.
</p>
<InfoBox type="info" title="Versionierung">
Der State wird mit optimistischem Locking gespeichert. Bei jedem Speichern
wird die Version erhöht. Bei Konflikten erhalten Sie einen 409-Fehler.
</InfoBox>
<h2>GET /state/{'{tenantId}'}</h2>
<p>Lädt den aktuellen SDK-State für einen Tenant.</p>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X GET "https://api.breakpilot.io/sdk/v1/state/your-tenant-id" \\
-H "Authorization: Bearer YOUR_API_KEY"`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"version": "1.0.0",
"lastModified": "2026-02-04T12:00:00Z",
"tenantId": "your-tenant-id",
"userId": "user-123",
"subscription": "PROFESSIONAL",
"currentPhase": 1,
"currentStep": "use-case-workshop",
"completedSteps": ["use-case-workshop", "screening"],
"checkpoints": {
"CP-UC": {
"checkpointId": "CP-UC",
"passed": true,
"validatedAt": "2026-02-01T10:00:00Z",
"validatedBy": "user-123",
"errors": [],
"warnings": []
}
},
"useCases": [
{
"id": "uc-1",
"name": "KI-Kundenanalyse",
"description": "...",
"category": "Marketing",
"stepsCompleted": 5,
"assessmentResult": {
"riskLevel": "HIGH",
"dsfaRequired": true,
"aiActClassification": "LIMITED"
}
}
],
"risks": [...],
"controls": [...],
"dsfa": {...},
"toms": [...],
"vvt": [...]
},
"meta": {
"version": 5,
"etag": "W/\\"abc123\\""
}
}`}
</CodeBlock>
<h3>Response (404 Not Found)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "No state found for tenant your-tenant-id"
}
}`}
</CodeBlock>
<h2>POST /state</h2>
<p>Speichert den SDK-State. Unterstützt Versionierung und optimistisches Locking.</p>
<h3>Request Body</h3>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Eindeutige Tenant-ID',
},
{
name: 'userId',
type: 'string',
required: false,
description: 'User-ID für Audit-Trail',
},
{
name: 'state',
type: 'SDKState',
required: true,
description: 'Der komplette SDK-State',
},
{
name: 'expectedVersion',
type: 'number',
required: false,
description: 'Erwartete Version für optimistisches Locking',
},
]}
/>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X POST "https://api.breakpilot.io/sdk/v1/state" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-H "If-Match: W/\\"abc123\\"" \\
-d '{
"tenantId": "your-tenant-id",
"userId": "user-123",
"state": {
"currentPhase": 1,
"currentStep": "risks",
"useCases": [...],
"risks": [...]
}
}'`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"tenantId": "your-tenant-id",
"version": 6,
"updatedAt": "2026-02-04T12:05:00Z"
},
"meta": {
"etag": "W/\\"def456\\""
}
}`}
</CodeBlock>
<h3>Response (409 Conflict)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": false,
"error": {
"code": "CONFLICT",
"message": "Version conflict: expected 5, but current is 6",
"details": {
"expectedVersion": 5,
"currentVersion": 6
}
}
}`}
</CodeBlock>
<InfoBox type="warning" title="Konfliktbehandlung">
Bei einem 409-Fehler sollten Sie den State erneut laden, Ihre Änderungen
mergen und erneut speichern.
</InfoBox>
<h2>DELETE /state/{'{tenantId}'}</h2>
<p>Löscht den kompletten State für einen Tenant.</p>
<h3>Request</h3>
<CodeBlock language="bash" filename="cURL">
{`curl -X DELETE "https://api.breakpilot.io/sdk/v1/state/your-tenant-id" \\
-H "Authorization: Bearer YOUR_API_KEY"`}
</CodeBlock>
<h3>Response (200 OK)</h3>
<CodeBlock language="json" filename="Response">
{`{
"success": true,
"data": {
"tenantId": "your-tenant-id",
"deleted": true
}
}`}
</CodeBlock>
<h2>State-Struktur</h2>
<p>Der SDKState enthält alle Compliance-Daten:</p>
<CodeBlock language="typescript" filename="types.ts">
{`interface SDKState {
// Metadata
version: string
lastModified: Date
// Tenant & User
tenantId: string
userId: string
subscription: 'FREE' | 'STARTER' | 'PROFESSIONAL' | 'ENTERPRISE'
// Progress
currentPhase: 1 | 2
currentStep: string
completedSteps: string[]
checkpoints: Record<string, CheckpointStatus>
// Phase 1 Data
useCases: UseCaseAssessment[]
activeUseCase: string | null
screening: ScreeningResult | null
modules: ServiceModule[]
requirements: Requirement[]
controls: Control[]
evidence: Evidence[]
checklist: ChecklistItem[]
risks: Risk[]
// Phase 2 Data
aiActClassification: AIActResult | null
obligations: Obligation[]
dsfa: DSFA | null
toms: TOM[]
retentionPolicies: RetentionPolicy[]
vvt: ProcessingActivity[]
documents: LegalDocument[]
cookieBanner: CookieBannerConfig | null
consents: ConsentRecord[]
dsrConfig: DSRConfig | null
escalationWorkflows: EscalationWorkflow[]
// UI State
preferences: UserPreferences
}`}
</CodeBlock>
<h2>Beispiel: SDK Integration</h2>
<CodeBlock language="typescript" filename="sdk-client.ts">
{`import { getSDKApiClient } from '@breakpilot/compliance-sdk'
const client = getSDKApiClient('your-tenant-id')
// State laden
const state = await client.getState()
console.log('Current step:', state.currentStep)
console.log('Use cases:', state.useCases.length)
// State speichern
await client.saveState({
...state,
currentStep: 'risks',
risks: [...state.risks, newRisk],
})`}
</CodeBlock>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,164 @@
import { DevPortalLayout, InfoBox } from '@/components/DevPortalLayout'
export default function ChangelogPage() {
return (
<DevPortalLayout
title="Changelog"
description="Versionshistorie und Aenderungen des AI Compliance SDK"
>
<h2>Versionierung</h2>
<p>
Das SDK folgt Semantic Versioning (SemVer):
<code className="mx-1">MAJOR.MINOR.PATCH</code>
</p>
<ul>
<li><strong>MAJOR:</strong> Breaking Changes</li>
<li><strong>MINOR:</strong> Neue Features, abwaertskompatibel</li>
<li><strong>PATCH:</strong> Bugfixes</li>
</ul>
{/* Version 1.2.0 */}
<div className="mt-8 border-l-4 border-green-500 pl-4">
<div className="flex items-center gap-3 mb-2">
<span className="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm font-medium">
v1.2.0
</span>
<span className="text-slate-500 text-sm">2026-02-04</span>
<span className="px-2 py-0.5 bg-green-500 text-white rounded text-xs">Latest</span>
</div>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Neue Features</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1 mb-4">
<li>Demo-Daten Seeding ueber API (nicht mehr hardcodiert)</li>
<li>Playwright E2E Tests fuer alle 19 SDK-Schritte</li>
<li>Command Bar RAG-Integration mit Live-Suche</li>
<li>Developer Portal mit API-Dokumentation</li>
<li>TOM-Katalog mit 20 vorkonfigurierten Massnahmen</li>
<li>VVT-Templates fuer gaengige Verarbeitungstaetigkeiten</li>
</ul>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Verbesserungen</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1 mb-4">
<li>Performance-Optimierung beim State-Loading</li>
<li>Bessere TypeScript-Typen fuer alle Exports</li>
<li>Verbesserte Fehlerbehandlung bei API-Calls</li>
</ul>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Bugfixes</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1">
<li>Fix: Checkpoint-Validierung bei leeren Arrays</li>
<li>Fix: Multi-Tab-Sync bei Safari</li>
<li>Fix: Export-Dateiname mit Sonderzeichen</li>
</ul>
</div>
{/* Version 1.1.0 */}
<div className="mt-8 border-l-4 border-blue-500 pl-4">
<div className="flex items-center gap-3 mb-2">
<span className="px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium">
v1.1.0
</span>
<span className="text-slate-500 text-sm">2026-01-20</span>
</div>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Neue Features</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1 mb-4">
<li>Backend-Sync mit PostgreSQL-Persistierung</li>
<li>SDK Backend (Go) mit RAG + LLM-Integration</li>
<li>Automatische DSFA-Generierung via Claude API</li>
<li>Export nach PDF, ZIP, JSON</li>
</ul>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Verbesserungen</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1 mb-4">
<li>Offline-Support mit localStorage Fallback</li>
<li>Optimistic Locking fuer Konfliktbehandlung</li>
<li>BroadcastChannel fuer Multi-Tab-Sync</li>
</ul>
</div>
{/* Version 1.0.0 */}
<div className="mt-8 border-l-4 border-slate-400 pl-4">
<div className="flex items-center gap-3 mb-2">
<span className="px-3 py-1 bg-slate-100 text-slate-800 rounded-full text-sm font-medium">
v1.0.0
</span>
<span className="text-slate-500 text-sm">2026-01-01</span>
</div>
<h3 className="text-lg font-semibold text-slate-900 mb-2">Initial Release</h3>
<ul className="list-disc list-inside text-slate-700 space-y-1 mb-4">
<li>SDKProvider mit React Context</li>
<li>useSDK Hook mit vollstaendigem State-Zugriff</li>
<li>19-Schritte Compliance-Workflow (Phase 1 + 2)</li>
<li>Checkpoint-Validierung</li>
<li>Risk Matrix mit Score-Berechnung</li>
<li>TypeScript-Support mit allen Types</li>
<li>Utility Functions fuer Navigation und Berechnung</li>
</ul>
</div>
{/* Breaking Changes Notice */}
<InfoBox type="warning" title="Upgrade-Hinweise">
<p className="mb-2">
Bei Major-Version-Updates (z.B. 1.x 2.x) koennen Breaking Changes auftreten.
Pruefen Sie die Migration Guides vor dem Upgrade.
</p>
<p>
Das SDK speichert die State-Version im localStorage. Bei inkompatiblen
Aenderungen wird automatisch eine Migration durchgefuehrt.
</p>
</InfoBox>
<h2>Geplante Features</h2>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Feature</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Version</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Status</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3">Multi-Tenant-Support</td>
<td className="px-4 py-3 font-mono">v1.3.0</td>
<td className="px-4 py-3"><span className="px-2 py-1 bg-yellow-100 text-yellow-800 rounded text-xs">In Entwicklung</span></td>
</tr>
<tr>
<td className="px-4 py-3">Workflow-Customization</td>
<td className="px-4 py-3 font-mono">v1.3.0</td>
<td className="px-4 py-3"><span className="px-2 py-1 bg-blue-100 text-blue-800 rounded text-xs">Geplant</span></td>
</tr>
<tr>
<td className="px-4 py-3">Audit-Trail Export</td>
<td className="px-4 py-3 font-mono">v1.4.0</td>
<td className="px-4 py-3"><span className="px-2 py-1 bg-blue-100 text-blue-800 rounded text-xs">Geplant</span></td>
</tr>
<tr>
<td className="px-4 py-3">White-Label Branding</td>
<td className="px-4 py-3 font-mono">v2.0.0</td>
<td className="px-4 py-3"><span className="px-2 py-1 bg-slate-100 text-slate-800 rounded text-xs">Roadmap</span></td>
</tr>
</tbody>
</table>
</div>
<h2>Feedback & Issues</h2>
<p>
Fuer Bug-Reports und Feature-Requests nutzen Sie bitte:
</p>
<ul>
<li>
<strong>GitHub Issues:</strong>{' '}
<code>github.com/breakpilot/compliance-sdk/issues</code>
</li>
<li>
<strong>Support:</strong>{' '}
<code>support@breakpilot.io</code>
</li>
</ul>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,203 @@
import Link from 'next/link'
import { DevPortalLayout, CodeBlock, InfoBox, ParameterTable } from '@/components/DevPortalLayout'
export default function GettingStartedPage() {
return (
<DevPortalLayout
title="Quick Start"
description="Starten Sie in 5 Minuten mit dem AI Compliance SDK"
>
<h2>1. Installation</h2>
<p>
Installieren Sie das SDK über Ihren bevorzugten Paketmanager:
</p>
<CodeBlock language="bash" filename="Terminal">
{`npm install @breakpilot/compliance-sdk
# oder
yarn add @breakpilot/compliance-sdk
# oder
pnpm add @breakpilot/compliance-sdk`}
</CodeBlock>
<h2>2. API Key erhalten</h2>
<p>
Nach dem Abo-Abschluss erhalten Sie Ihren API Key im{' '}
<Link href="/settings" className="text-blue-600 hover:underline">
Einstellungsbereich
</Link>.
</p>
<InfoBox type="warning" title="Sicherheitshinweis">
Speichern Sie den API Key niemals im Frontend-Code. Verwenden Sie
Umgebungsvariablen auf dem Server.
</InfoBox>
<h2>3. Provider einrichten</h2>
<p>
Wrappen Sie Ihre App mit dem SDKProvider:
</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.TENANT_ID}
apiKey={process.env.BREAKPILOT_API_KEY}
enableBackendSync={true}
>
{children}
</SDKProvider>
</body>
</html>
)
}`}
</CodeBlock>
<h3>Provider Props</h3>
<ParameterTable
parameters={[
{
name: 'tenantId',
type: 'string',
required: true,
description: 'Ihre eindeutige Tenant-ID',
},
{
name: 'apiKey',
type: 'string',
required: false,
description: 'API Key für Backend-Sync (serverseitig)',
},
{
name: 'userId',
type: 'string',
required: false,
description: 'Optional: Benutzer-ID für Audit-Trail',
},
{
name: 'enableBackendSync',
type: 'boolean',
required: false,
description: 'Aktiviert Synchronisation mit dem Backend (default: false)',
},
]}
/>
<h2>4. SDK verwenden</h2>
<p>
Nutzen Sie den useSDK Hook in Ihren Komponenten:
</p>
<CodeBlock language="typescript" filename="components/Dashboard.tsx">
{`'use client'
import { useSDK } from '@breakpilot/compliance-sdk'
export function ComplianceDashboard() {
const {
state,
completionPercentage,
goToStep,
currentStep,
} = useSDK()
return (
<div className="p-6">
<h1 className="text-2xl font-bold">
Compliance Fortschritt: {completionPercentage}%
</h1>
<div className="mt-4">
<p>Aktueller Schritt: {currentStep?.name}</p>
<p>Phase: {state.currentPhase}</p>
<p>Use Cases: {state.useCases.length}</p>
</div>
<div className="mt-6 flex gap-4">
<button
onClick={() => goToStep('use-case-workshop')}
className="px-4 py-2 bg-blue-600 text-white rounded"
>
Use Case Workshop
</button>
<button
onClick={() => goToStep('risks')}
className="px-4 py-2 bg-blue-600 text-white rounded"
>
Risikoanalyse
</button>
</div>
</div>
)
}`}
</CodeBlock>
<h2>5. Erste Schritte im Workflow</h2>
<p>
Das SDK führt Sie durch einen 19-Schritte-Workflow in 2 Phasen:
</p>
<div className="my-6 not-prose">
<div className="grid grid-cols-2 gap-4">
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-semibold mb-2">Phase 1: Assessment</h4>
<ol className="text-sm text-gray-600 space-y-1 list-decimal list-inside">
<li>Use Case Workshop</li>
<li>System Screening</li>
<li>Compliance Modules</li>
<li>Requirements</li>
<li>Controls</li>
<li>Evidence</li>
<li>Audit Checklist</li>
<li>Risk Matrix</li>
</ol>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-semibold mb-2">Phase 2: Dokumentation</h4>
<ol className="text-sm text-gray-600 space-y-1 list-decimal list-inside">
<li>AI Act Klassifizierung</li>
<li>Pflichtenübersicht</li>
<li>DSFA</li>
<li>TOMs</li>
<li>Löschfristen</li>
<li>VVT</li>
<li>Rechtliche Vorlagen</li>
<li>Cookie Banner</li>
<li>Einwilligungen</li>
<li>DSR Portal</li>
<li>Escalations</li>
</ol>
</div>
</div>
</div>
<h2>6. Nächste Schritte</h2>
<ul>
<li>
<Link href="/sdk/configuration" className="text-blue-600 hover:underline">
SDK Konfiguration
</Link>
{' '}- Alle Konfigurationsoptionen
</li>
<li>
<Link href="/api/state" className="text-blue-600 hover:underline">
State API
</Link>
{' '}- Verstehen Sie das State Management
</li>
<li>
<Link href="/guides/phase1" className="text-blue-600 hover:underline">
Phase 1 Guide
</Link>
{' '}- Kompletter Workflow für das Assessment
</li>
</ul>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,35 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f5f9;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* Smooth transitions */
* {
transition-property: background-color, border-color, color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
/* Focus styles */
*:focus-visible {
outline: 2px solid #0ea5e9;
outline-offset: 2px;
}

View File

@@ -0,0 +1,227 @@
import Link from 'next/link'
import { DevPortalLayout, InfoBox } from '@/components/DevPortalLayout'
export default function GuidesPage() {
return (
<DevPortalLayout
title="Entwickler-Guides"
description="Schritt-fuer-Schritt Anleitungen fuer die SDK-Integration"
>
<h2>Workflow-Guides</h2>
<p>
Das AI Compliance SDK fuehrt durch einen strukturierten 19-Schritte-Workflow
in zwei Phasen. Diese Guides erklaeren jeden Schritt im Detail.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 my-8">
<Link
href="/guides/phase1"
className="block p-6 bg-blue-50 border border-blue-200 rounded-xl hover:border-blue-400 transition-colors"
>
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 bg-blue-600 text-white rounded-xl flex items-center justify-center text-xl font-bold">
1
</div>
<div>
<h3 className="text-lg font-semibold text-blue-900">Phase 1: Assessment</h3>
<p className="text-sm text-blue-600">8 Schritte</p>
</div>
</div>
<p className="text-blue-800 text-sm">
Use Case Workshop, System Screening, Module-Auswahl, Requirements,
Controls, Evidence, Checkliste, Risk Matrix.
</p>
</Link>
<Link
href="/guides/phase2"
className="block p-6 bg-green-50 border border-green-200 rounded-xl hover:border-green-400 transition-colors"
>
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 bg-green-600 text-white rounded-xl flex items-center justify-center text-xl font-bold">
2
</div>
<div>
<h3 className="text-lg font-semibold text-green-900">Phase 2: Dokumentation</h3>
<p className="text-sm text-green-600">11 Schritte</p>
</div>
</div>
<p className="text-green-800 text-sm">
AI Act Klassifizierung, Pflichten, DSFA, TOMs, Loeschfristen,
VVT, Rechtliche Vorlagen, Cookie Banner, DSR Portal.
</p>
</Link>
</div>
<h2>Workflow-Uebersicht</h2>
<div className="my-6 not-prose">
<div className="bg-slate-50 rounded-xl p-6 border border-slate-200">
<h4 className="font-semibold mb-4 text-slate-900">Phase 1: Assessment (8 Schritte)</h4>
<ol className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">01</span>
<p className="font-medium">Use Case Workshop</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">02</span>
<p className="font-medium">System Screening</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">03</span>
<p className="font-medium">Compliance Modules</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">04</span>
<p className="font-medium">Requirements</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">05</span>
<p className="font-medium">Controls</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">06</span>
<p className="font-medium">Evidence</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">07</span>
<p className="font-medium">Audit Checklist</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-blue-600 font-mono">08</span>
<p className="font-medium">Risk Matrix</p>
</li>
</ol>
</div>
<div className="bg-slate-50 rounded-xl p-6 border border-slate-200 mt-4">
<h4 className="font-semibold mb-4 text-slate-900">Phase 2: Dokumentation (11 Schritte)</h4>
<ol className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">09</span>
<p className="font-medium">AI Act Klassifizierung</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">10</span>
<p className="font-medium">Pflichtenuebersicht</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">11</span>
<p className="font-medium">DSFA</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">12</span>
<p className="font-medium">TOMs</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">13</span>
<p className="font-medium">Loeschfristen</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">14</span>
<p className="font-medium">VVT</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">15</span>
<p className="font-medium">Rechtliche Vorlagen</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">16</span>
<p className="font-medium">Cookie Banner</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">17</span>
<p className="font-medium">Einwilligungen</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">18</span>
<p className="font-medium">DSR Portal</p>
</li>
<li className="p-3 bg-white rounded-lg border border-slate-200">
<span className="text-green-600 font-mono">19</span>
<p className="font-medium">Escalations</p>
</li>
</ol>
</div>
</div>
<h2>Checkpoints</h2>
<p>
Das SDK validiert den Fortschritt an definierten Checkpoints:
</p>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Checkpoint</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Nach Schritt</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Validierung</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3 font-mono text-blue-600">CP-UC</td>
<td className="px-4 py-3">Use Case Workshop</td>
<td className="px-4 py-3 text-gray-600">Mind. 1 Use Case angelegt</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-blue-600">CP-SCREEN</td>
<td className="px-4 py-3">System Screening</td>
<td className="px-4 py-3 text-gray-600">Screening abgeschlossen</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-blue-600">CP-CTRL</td>
<td className="px-4 py-3">Controls</td>
<td className="px-4 py-3 text-gray-600">Alle Requirements haben Controls</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-blue-600">CP-RISK</td>
<td className="px-4 py-3">Risk Matrix</td>
<td className="px-4 py-3 text-gray-600">Alle Risiken bewertet</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-green-600">CP-DSFA</td>
<td className="px-4 py-3">DSFA</td>
<td className="px-4 py-3 text-gray-600">DSFA generiert (falls erforderlich)</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-green-600">CP-TOM</td>
<td className="px-4 py-3">TOMs</td>
<td className="px-4 py-3 text-gray-600">Mind. 10 TOMs definiert</td>
</tr>
<tr>
<td className="px-4 py-3 font-mono text-green-600">CP-VVT</td>
<td className="px-4 py-3">VVT</td>
<td className="px-4 py-3 text-gray-600">VVT vollstaendig</td>
</tr>
</tbody>
</table>
</div>
<InfoBox type="info" title="Checkpoint-Navigation">
Nicht bestandene Checkpoints blockieren den Fortschritt zu spaetere Schritte.
Verwenden Sie <code>validateCheckpoint()</code> um den Status zu pruefen.
</InfoBox>
<h2>Best Practices</h2>
<ul>
<li>
<strong>Speichern Sie regelmaessig:</strong> Der State wird automatisch
im localStorage gespeichert, aber aktivieren Sie Backend-Sync fuer
persistente Speicherung.
</li>
<li>
<strong>Nutzen Sie die Command Bar:</strong> Cmd+K oeffnet schnelle
Navigation, Export und RAG-Suche.
</li>
<li>
<strong>Arbeiten Sie Use-Case-zentriert:</strong> Bearbeiten Sie
einen Use Case vollstaendig, bevor Sie zum naechsten wechseln.
</li>
<li>
<strong>Validieren Sie Checkpoints:</strong> Pruefen Sie vor dem
Phasenwechsel, ob alle Checkpoints bestanden sind.
</li>
</ul>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,391 @@
import { DevPortalLayout, CodeBlock, InfoBox } from '@/components/DevPortalLayout'
export default function Phase1GuidePage() {
return (
<DevPortalLayout
title="Phase 1: Assessment Guide"
description="Schritt-fuer-Schritt durch die Assessment-Phase"
>
<h2>Uebersicht Phase 1</h2>
<p>
Phase 1 umfasst die Erfassung und Bewertung Ihrer KI-Anwendungsfaelle.
Am Ende haben Sie eine vollstaendige Risikoanalyse und wissen, welche
Compliance-Dokumente Sie benoetigen.
</p>
<div className="my-6 p-4 bg-blue-50 border border-blue-200 rounded-xl">
<h3 className="text-lg font-semibold text-blue-900 mb-2">Phase 1 Schritte</h3>
<ol className="list-decimal list-inside text-blue-800 space-y-1">
<li>Use Case Workshop</li>
<li>System Screening</li>
<li>Compliance Modules</li>
<li>Requirements</li>
<li>Controls</li>
<li>Evidence</li>
<li>Audit Checklist</li>
<li>Risk Matrix</li>
</ol>
</div>
<h2>Schritt 1: Use Case Workshop</h2>
<p>
Erfassen Sie alle KI-Anwendungsfaelle in Ihrem Unternehmen.
</p>
<h3>Code-Beispiel</h3>
<CodeBlock language="typescript" filename="use-case-workshop.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function UseCaseForm() {
const { updateUseCase, state } = useSDK()
const handleCreateUseCase = async () => {
await updateUseCase({
id: \`uc-\${Date.now()}\`,
name: 'KI-gestuetzte Kundenanalyse',
description: 'Analyse von Kundenverhalten mittels ML',
category: 'Marketing',
department: 'Marketing & Sales',
dataTypes: ['Kundendaten', 'Verhaltensdaten', 'Transaktionen'],
aiCapabilities: ['Profiling', 'Vorhersage'],
stepsCompleted: 0,
})
}
return (
<div>
<h2>Use Cases: {state.useCases.length}</h2>
<button onClick={handleCreateUseCase}>
Use Case hinzufuegen
</button>
{state.useCases.map(uc => (
<div key={uc.id}>
<h3>{uc.name}</h3>
<p>{uc.description}</p>
</div>
))}
</div>
)
}`}
</CodeBlock>
<InfoBox type="info" title="Checkpoint CP-UC">
Nach dem Use Case Workshop muss mindestens ein Use Case angelegt sein,
um zum naechsten Schritt zu gelangen.
</InfoBox>
<h2>Schritt 2: System Screening</h2>
<p>
Das Screening bewertet jeden Use Case hinsichtlich Datenschutz und AI Act.
</p>
<h3>Code-Beispiel</h3>
<CodeBlock language="typescript" filename="screening.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function ScreeningView() {
const { state, dispatch } = useSDK()
const completeScreening = (useCaseId: string, result: ScreeningResult) => {
dispatch({
type: 'UPDATE_USE_CASE',
payload: {
id: useCaseId,
screeningResult: result,
// Ergebnis bestimmt weitere Pflichten
assessmentResult: {
riskLevel: result.aiActRisk,
dsfaRequired: result.dsfaRequired,
aiActClassification: result.aiActClassification,
},
},
})
}
// Screening-Fragen beantworten
const screeningQuestions = [
'Werden personenbezogene Daten verarbeitet?',
'Erfolgt automatisierte Entscheidungsfindung?',
'Werden besondere Datenkategorien verarbeitet?',
'Erfolgt Profiling?',
'Werden Daten in Drittlaender uebermittelt?',
]
return (
<div>
{screeningQuestions.map((question, i) => (
<label key={i} className="block">
<input type="checkbox" />
{question}
</label>
))}
</div>
)
}`}
</CodeBlock>
<h2>Schritt 3: Compliance Modules</h2>
<p>
Basierend auf dem Screening werden relevante Compliance-Module aktiviert.
</p>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Modul</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Aktiviert wenn</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3 font-medium">DSGVO Basis</td>
<td className="px-4 py-3 text-gray-600">Immer (personenbezogene Daten)</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium">DSFA</td>
<td className="px-4 py-3 text-gray-600">Hohes Risiko, Profiling, Art. 9 Daten</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium">AI Act</td>
<td className="px-4 py-3 text-gray-600">KI-basierte Entscheidungen</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium">NIS2</td>
<td className="px-4 py-3 text-gray-600">Kritische Infrastruktur</td>
</tr>
</tbody>
</table>
</div>
<h2>Schritt 4: Requirements</h2>
<p>
Fuer jedes aktivierte Modul werden spezifische Anforderungen generiert.
</p>
<CodeBlock language="typescript" filename="requirements.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function RequirementsView() {
const { state } = useSDK()
// Requirements nach Modul gruppieren
const byModule = state.requirements.reduce((acc, req) => {
const module = req.module || 'general'
if (!acc[module]) acc[module] = []
acc[module].push(req)
return acc
}, {})
return (
<div>
{Object.entries(byModule).map(([module, reqs]) => (
<div key={module}>
<h3>{module}</h3>
<ul>
{reqs.map(req => (
<li key={req.id}>
<strong>{req.title}</strong>
<p>{req.description}</p>
<span>Status: {req.status}</span>
</li>
))}
</ul>
</div>
))}
</div>
)
}`}
</CodeBlock>
<h2>Schritt 5: Controls</h2>
<p>
Definieren Sie Kontrollen fuer jede Anforderung.
</p>
<CodeBlock language="typescript" filename="controls.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function ControlsView() {
const { updateControl, state } = useSDK()
const addControl = (requirementId: string) => {
updateControl({
id: \`ctrl-\${Date.now()}\`,
requirementId,
title: 'Zugriffskontrolle implementieren',
description: 'Role-based access control fuer alle Datenzugaenge',
type: 'TECHNICAL',
status: 'PLANNED',
implementationDate: null,
owner: 'IT-Abteilung',
})
}
return (
<div>
<h2>Controls: {state.controls.length}</h2>
{state.requirements.map(req => (
<div key={req.id}>
<h3>{req.title}</h3>
<p>Controls: {state.controls.filter(c => c.requirementId === req.id).length}</p>
<button onClick={() => addControl(req.id)}>
Control hinzufuegen
</button>
</div>
))}
</div>
)
}`}
</CodeBlock>
<InfoBox type="warning" title="Checkpoint CP-CTRL">
Jede Requirement muss mindestens ein Control haben, bevor Sie
zur Evidence-Phase uebergehen koennen.
</InfoBox>
<h2>Schritt 6: Evidence</h2>
<p>
Dokumentieren Sie Nachweise fuer implementierte Controls.
</p>
<CodeBlock language="typescript" filename="evidence.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function EvidenceUpload({ controlId }: { controlId: string }) {
const { dispatch } = useSDK()
const addEvidence = (file: File) => {
dispatch({
type: 'ADD_EVIDENCE',
payload: {
id: \`ev-\${Date.now()}\`,
controlId,
title: file.name,
type: 'DOCUMENT',
uploadedAt: new Date().toISOString(),
fileType: file.type,
// In Produktion: Upload zu Storage
},
})
}
return (
<input
type="file"
onChange={(e) => e.target.files?.[0] && addEvidence(e.target.files[0])}
/>
)
}`}
</CodeBlock>
<h2>Schritt 7: Audit Checklist</h2>
<p>
Die Checkliste fasst alle Compliance-Punkte zusammen.
</p>
<h2>Schritt 8: Risk Matrix</h2>
<p>
Bewerten Sie alle identifizierten Risiken nach Likelihood und Impact.
</p>
<CodeBlock language="typescript" filename="risk-matrix.tsx">
{`import { useSDK, calculateRiskScore, getRiskSeverityFromScore } from '@breakpilot/compliance-sdk'
function RiskMatrix() {
const { addRisk, state } = useSDK()
const createRisk = () => {
const likelihood = 3 // 1-5
const impact = 4 // 1-5
const score = calculateRiskScore(likelihood, impact) // 12
const severity = getRiskSeverityFromScore(score) // 'HIGH'
addRisk({
id: \`risk-\${Date.now()}\`,
title: 'Unbefugter Datenzugriff',
description: 'Risiko durch unzureichende Zugriffskontrolle',
likelihood,
impact,
inherentScore: score,
severity,
category: 'Security',
mitigations: [],
residualScore: null,
})
}
return (
<div>
<h2>Risiken: {state.risks.length}</h2>
{/* 5x5 Matrix Visualisierung */}
<div className="grid grid-cols-5 gap-1">
{[5,4,3,2,1].map(likelihood => (
[1,2,3,4,5].map(impact => {
const score = likelihood * impact
const risksHere = state.risks.filter(
r => r.likelihood === likelihood && r.impact === impact
)
return (
<div
key={\`\${likelihood}-\${impact}\`}
className={\`p-2 \${score >= 15 ? 'bg-red-500' : score >= 8 ? 'bg-yellow-500' : 'bg-green-500'}\`}
>
{risksHere.length > 0 && (
<span className="text-white">{risksHere.length}</span>
)}
</div>
)
})
))}
</div>
<button onClick={createRisk}>Risiko hinzufuegen</button>
</div>
)
}`}
</CodeBlock>
<InfoBox type="success" title="Phase 1 abgeschlossen">
Nach erfolgreicher Bewertung aller Risiken koennen Sie zu Phase 2
uebergehen. Der Checkpoint CP-RISK validiert, dass alle Risiken
eine Severity-Bewertung haben.
</InfoBox>
<h2>Navigation nach Phase 2</h2>
<CodeBlock language="typescript" filename="phase-transition.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function PhaseTransition() {
const { validateCheckpoint, goToStep, phase1Completion } = useSDK()
const handleContinueToPhase2 = async () => {
// Alle Phase-1-Checkpoints pruefen
const cpRisk = await validateCheckpoint('CP-RISK')
if (cpRisk.passed) {
goToStep('ai-act-classification') // Erster Schritt Phase 2
} else {
console.error('Checkpoint nicht bestanden:', cpRisk.errors)
}
}
return (
<div>
<p>Phase 1 Fortschritt: {phase1Completion}%</p>
{phase1Completion === 100 && (
<button onClick={handleContinueToPhase2}>
Weiter zu Phase 2
</button>
)}
</div>
)
}`}
</CodeBlock>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,377 @@
import { DevPortalLayout, CodeBlock, InfoBox } from '@/components/DevPortalLayout'
export default function Phase2GuidePage() {
return (
<DevPortalLayout
title="Phase 2: Dokumentation Guide"
description="Schritt-fuer-Schritt durch die Dokumentations-Phase"
>
<h2>Uebersicht Phase 2</h2>
<p>
Phase 2 generiert alle erforderlichen Compliance-Dokumente basierend
auf dem Assessment aus Phase 1. Die Dokumente koennen exportiert und
fuer Audits verwendet werden.
</p>
<div className="my-6 p-4 bg-green-50 border border-green-200 rounded-xl">
<h3 className="text-lg font-semibold text-green-900 mb-2">Phase 2 Schritte</h3>
<ol className="list-decimal list-inside text-green-800 space-y-1">
<li>AI Act Klassifizierung</li>
<li>Pflichtenuebersicht</li>
<li>DSFA (Datenschutz-Folgenabschaetzung)</li>
<li>TOMs (Technische/Organisatorische Massnahmen)</li>
<li>Loeschfristen</li>
<li>VVT (Verarbeitungsverzeichnis)</li>
<li>Rechtliche Vorlagen</li>
<li>Cookie Banner</li>
<li>Einwilligungen</li>
<li>DSR Portal</li>
<li>Escalations</li>
</ol>
</div>
<h2>Schritt 9: AI Act Klassifizierung</h2>
<p>
Klassifizieren Sie jeden Use Case nach dem EU AI Act Risikosystem.
</p>
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Risikostufe</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Beschreibung</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Pflichten</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200 text-sm">
<tr>
<td className="px-4 py-3 font-medium text-red-600">Verboten</td>
<td className="px-4 py-3 text-gray-600">Social Scoring, Manipulative KI</td>
<td className="px-4 py-3 text-gray-600">Nicht zulaessig</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium text-orange-600">Hochrisiko</td>
<td className="px-4 py-3 text-gray-600">Biometrie, Medizin, kritische Infrastruktur</td>
<td className="px-4 py-3 text-gray-600">Umfangreiche Dokumentation, Konformitaetsbewertung</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium text-yellow-600">Begrenzt</td>
<td className="px-4 py-3 text-gray-600">Chatbots, Empfehlungssysteme</td>
<td className="px-4 py-3 text-gray-600">Transparenzpflichten</td>
</tr>
<tr>
<td className="px-4 py-3 font-medium text-green-600">Minimal</td>
<td className="px-4 py-3 text-gray-600">Spam-Filter, Spiele</td>
<td className="px-4 py-3 text-gray-600">Freiwillige Verhaltenskodizes</td>
</tr>
</tbody>
</table>
</div>
<CodeBlock language="typescript" filename="ai-act-classification.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
import type { AIActRiskCategory } from '@breakpilot/compliance-sdk'
function AIActClassification() {
const { state, dispatch } = useSDK()
const classifyUseCase = (useCaseId: string, classification: AIActRiskCategory) => {
dispatch({
type: 'UPDATE_USE_CASE',
payload: {
id: useCaseId,
assessmentResult: {
...state.useCases.find(uc => uc.id === useCaseId)?.assessmentResult,
aiActClassification: classification,
},
},
})
// Wenn Hochrisiko, zusaetzliche Pflichten aktivieren
if (classification === 'HIGH_RISK') {
dispatch({
type: 'SET_AI_ACT_RESULT',
payload: {
classification,
conformityRequired: true,
documentationRequired: true,
humanOversightRequired: true,
},
})
}
}
return (
<div>
{state.useCases.map(uc => (
<div key={uc.id}>
<h3>{uc.name}</h3>
<select
value={uc.assessmentResult?.aiActClassification || ''}
onChange={(e) => classifyUseCase(uc.id, e.target.value as AIActRiskCategory)}
>
<option value="">Bitte waehlen...</option>
<option value="PROHIBITED">Verboten</option>
<option value="HIGH_RISK">Hochrisiko</option>
<option value="LIMITED">Begrenzt</option>
<option value="MINIMAL">Minimal</option>
</select>
</div>
))}
</div>
)
}`}
</CodeBlock>
<h2>Schritt 10: Pflichtenuebersicht</h2>
<p>
Basierend auf der Klassifizierung werden alle anwendbaren Pflichten angezeigt.
</p>
<h2>Schritt 11: DSFA</h2>
<p>
Die Datenschutz-Folgenabschaetzung wird automatisch generiert.
</p>
<CodeBlock language="typescript" filename="dsfa.tsx">
{`import { useSDK, getSDKBackendClient } from '@breakpilot/compliance-sdk'
function DSFAGeneration() {
const { state, dispatch } = useSDK()
const [generating, setGenerating] = useState(false)
const generateDSFA = async () => {
setGenerating(true)
const client = getSDKBackendClient()
const dsfa = await client.generateDSFA({
useCases: state.useCases,
risks: state.risks,
controls: state.controls,
})
dispatch({
type: 'SET_DSFA',
payload: dsfa,
})
setGenerating(false)
}
// DSFA nur anzeigen wenn erforderlich
const dsfaRequired = state.useCases.some(
uc => uc.assessmentResult?.dsfaRequired
)
if (!dsfaRequired) {
return <p>Keine DSFA erforderlich fuer die aktuellen Use Cases.</p>
}
return (
<div>
{state.dsfa ? (
<div>
<h3>DSFA generiert</h3>
<p>Status: {state.dsfa.status}</p>
<p>Gesamtrisiko: {state.dsfa.conclusion?.overallRisk}</p>
{/* DSFA-Sektionen anzeigen */}
{Object.entries(state.dsfa.sections || {}).map(([key, section]) => (
<div key={key}>
<h4>{section.title}</h4>
<p>{section.content}</p>
</div>
))}
</div>
) : (
<button onClick={generateDSFA} disabled={generating}>
{generating ? 'Generiere DSFA...' : 'DSFA generieren'}
</button>
)}
</div>
)
}`}
</CodeBlock>
<InfoBox type="info" title="Checkpoint CP-DSFA">
Wenn eine DSFA erforderlich ist (basierend auf Screening), muss diese
generiert werden, bevor Sie fortfahren koennen.
</InfoBox>
<h2>Schritt 12: TOMs</h2>
<p>
Technische und Organisatorische Massnahmen nach Art. 32 DSGVO.
</p>
<CodeBlock language="typescript" filename="toms.tsx">
{`import { useSDK, getSDKBackendClient } from '@breakpilot/compliance-sdk'
function TOMsView() {
const { state, dispatch } = useSDK()
const generateTOMs = async () => {
const client = getSDKBackendClient()
const toms = await client.generateTOM({
risks: state.risks,
controls: state.controls,
})
dispatch({
type: 'SET_TOMS',
payload: toms,
})
}
const tomCategories = [
{ id: 'access_control', label: 'Zugangskontrolle' },
{ id: 'access_rights', label: 'Zugriffskontrolle' },
{ id: 'transfer_control', label: 'Weitergabekontrolle' },
{ id: 'input_control', label: 'Eingabekontrolle' },
{ id: 'availability', label: 'Verfuegbarkeitskontrolle' },
{ id: 'separation', label: 'Trennungsgebot' },
]
return (
<div>
<h2>TOMs: {state.toms.length}</h2>
{tomCategories.map(cat => {
const tomsInCategory = state.toms.filter(t => t.category === cat.id)
return (
<div key={cat.id}>
<h3>{cat.label} ({tomsInCategory.length})</h3>
<ul>
{tomsInCategory.map(tom => (
<li key={tom.id}>
<strong>{tom.title}</strong>
<p>{tom.description}</p>
<span>Status: {tom.implementationStatus}</span>
</li>
))}
</ul>
</div>
)
})}
<button onClick={generateTOMs}>TOMs generieren</button>
</div>
)
}`}
</CodeBlock>
<h2>Schritt 13: Loeschfristen</h2>
<p>
Definieren Sie Aufbewahrungsfristen fuer verschiedene Datenkategorien.
</p>
<h2>Schritt 14: VVT</h2>
<p>
Das Verarbeitungsverzeichnis nach Art. 30 DSGVO.
</p>
<CodeBlock language="typescript" filename="vvt.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function VVTView() {
const { state, dispatch } = useSDK()
const addProcessingActivity = () => {
dispatch({
type: 'ADD_PROCESSING_ACTIVITY',
payload: {
id: \`pa-\${Date.now()}\`,
name: 'Kundendatenverarbeitung',
purpose: 'Vertragserfuellung',
legalBasis: 'Art. 6 Abs. 1 lit. b DSGVO',
dataCategories: ['Kontaktdaten', 'Vertragsdaten'],
dataSubjects: ['Kunden'],
recipients: [],
retentionPeriod: '10 Jahre',
technicalMeasures: ['Verschluesselung', 'Zugriffskontrolle'],
},
})
}
return (
<div>
<h2>Verarbeitungstaetigkeiten: {state.vvt.length}</h2>
{state.vvt.map(activity => (
<div key={activity.id} className="border p-4 rounded mb-4">
<h3>{activity.name}</h3>
<p><strong>Zweck:</strong> {activity.purpose}</p>
<p><strong>Rechtsgrundlage:</strong> {activity.legalBasis}</p>
<p><strong>Datenkategorien:</strong> {activity.dataCategories.join(', ')}</p>
<p><strong>Betroffene:</strong> {activity.dataSubjects.join(', ')}</p>
<p><strong>Loeschfrist:</strong> {activity.retentionPeriod}</p>
</div>
))}
<button onClick={addProcessingActivity}>
Verarbeitungstaetigkeit hinzufuegen
</button>
</div>
)
}`}
</CodeBlock>
<h2>Schritt 15-19: Weitere Dokumentation</h2>
<p>
Die verbleibenden Schritte umfassen:
</p>
<ul>
<li><strong>Rechtliche Vorlagen:</strong> AGB, Datenschutzerklaerung, etc.</li>
<li><strong>Cookie Banner:</strong> Konfiguration fuer Cookie-Consent</li>
<li><strong>Einwilligungen:</strong> Consent-Management fuer Betroffene</li>
<li><strong>DSR Portal:</strong> Data Subject Request Handling</li>
<li><strong>Escalations:</strong> Eskalationspfade fuer Datenschutzvorfaelle</li>
</ul>
<h2>Export der Dokumentation</h2>
<CodeBlock language="typescript" filename="export-all.tsx">
{`import { useSDK } from '@breakpilot/compliance-sdk'
function ExportAll() {
const { exportState, completionPercentage } = useSDK()
const handleExport = async (format: 'pdf' | 'zip' | 'json') => {
const blob = await exportState(format)
// Download ausloesen
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = \`compliance-export.\${format === 'json' ? 'json' : format}\`
a.click()
URL.revokeObjectURL(url)
}
return (
<div>
<h2>Compliance Fortschritt: {completionPercentage}%</h2>
<div className="flex gap-4 mt-4">
<button onClick={() => handleExport('pdf')}>
PDF Export
</button>
<button onClick={() => handleExport('zip')}>
ZIP Export (alle Dokumente)
</button>
<button onClick={() => handleExport('json')}>
JSON Backup
</button>
</div>
</div>
)
}`}
</CodeBlock>
<InfoBox type="success" title="Workflow abgeschlossen">
Nach Abschluss aller 19 Schritte haben Sie eine vollstaendige
Compliance-Dokumentation, die Sie fuer Audits und regulatorische
Anforderungen verwenden koennen.
</InfoBox>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,22 @@
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'BreakPilot Developer Portal',
description: 'SDK-Dokumentation und API-Referenz fuer BreakPilot AI Compliance SDK',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="de">
<body className={inter.className}>{children}</body>
</html>
)
}

View File

@@ -0,0 +1,188 @@
import Link from 'next/link'
import { DevPortalLayout, CodeBlock, InfoBox } from '@/components/DevPortalLayout'
import { Zap, Code, Terminal, Book, ArrowRight } from 'lucide-react'
export default function DevelopersPage() {
return (
<DevPortalLayout
title="AI Compliance SDK"
description="Integrieren Sie Compliance-Automation in Ihre Anwendung"
>
{/* Quick Links */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-12 not-prose">
<Link
href="/getting-started"
className="group p-6 border border-gray-200 rounded-xl hover:border-blue-300 hover:shadow-lg transition-all"
>
<div className="flex items-center gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center text-blue-600">
<Zap className="w-5 h-5" />
</div>
<h3 className="font-semibold text-gray-900">Quick Start</h3>
</div>
<p className="text-sm text-gray-600 mb-3">
Starten Sie in 5 Minuten mit dem AI Compliance SDK
</p>
<span className="text-sm text-blue-600 group-hover:underline flex items-center gap-1">
Jetzt starten <ArrowRight className="w-4 h-4" />
</span>
</Link>
<Link
href="/api"
className="group p-6 border border-gray-200 rounded-xl hover:border-blue-300 hover:shadow-lg transition-all"
>
<div className="flex items-center gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center text-green-600">
<Terminal className="w-5 h-5" />
</div>
<h3 className="font-semibold text-gray-900">API Reference</h3>
</div>
<p className="text-sm text-gray-600 mb-3">
Vollständige API-Dokumentation aller Endpoints
</p>
<span className="text-sm text-blue-600 group-hover:underline flex items-center gap-1">
API erkunden <ArrowRight className="w-4 h-4" />
</span>
</Link>
<Link
href="/sdk"
className="group p-6 border border-gray-200 rounded-xl hover:border-blue-300 hover:shadow-lg transition-all"
>
<div className="flex items-center gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center text-purple-600">
<Code className="w-5 h-5" />
</div>
<h3 className="font-semibold text-gray-900">SDK Documentation</h3>
</div>
<p className="text-sm text-gray-600 mb-3">
TypeScript SDK für React und Next.js
</p>
<span className="text-sm text-blue-600 group-hover:underline flex items-center gap-1">
Dokumentation lesen <ArrowRight className="w-4 h-4" />
</span>
</Link>
<Link
href="/guides"
className="group p-6 border border-gray-200 rounded-xl hover:border-blue-300 hover:shadow-lg transition-all"
>
<div className="flex items-center gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-orange-100 flex items-center justify-center text-orange-600">
<Book className="w-5 h-5" />
</div>
<h3 className="font-semibold text-gray-900">Guides</h3>
</div>
<p className="text-sm text-gray-600 mb-3">
Schritt-für-Schritt-Anleitungen und Best Practices
</p>
<span className="text-sm text-blue-600 group-hover:underline flex items-center gap-1">
Guides ansehen <ArrowRight className="w-4 h-4" />
</span>
</Link>
</div>
{/* Installation */}
<h2>Installation</h2>
<CodeBlock language="bash" filename="Terminal">
{`npm install @breakpilot/compliance-sdk
# oder
yarn add @breakpilot/compliance-sdk
# oder
pnpm add @breakpilot/compliance-sdk`}
</CodeBlock>
{/* Quick Example */}
<h2>Schnellstart-Beispiel</h2>
<CodeBlock language="typescript" filename="app.tsx">
{`import { SDKProvider, useSDK } from '@breakpilot/compliance-sdk'
function App() {
return (
<SDKProvider
tenantId="your-tenant-id"
apiKey={process.env.BREAKPILOT_API_KEY}
>
<ComplianceDashboard />
</SDKProvider>
)
}
function ComplianceDashboard() {
const { state, goToStep, completionPercentage } = useSDK()
return (
<div>
<h1>Compliance Status: {completionPercentage}%</h1>
<p>Aktueller Schritt: {state.currentStep}</p>
<button onClick={() => goToStep('risks')}>
Zur Risikoanalyse
</button>
</div>
)
}`}
</CodeBlock>
<InfoBox type="info" title="Voraussetzungen">
<ul className="list-disc list-inside space-y-1">
<li>Node.js 18 oder höher</li>
<li>React 18 oder höher</li>
<li>Breakpilot API Key (erhältlich nach Abo-Abschluss)</li>
</ul>
</InfoBox>
{/* Features */}
<h2>Hauptfunktionen</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 not-prose">
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-medium text-gray-900 mb-2">19-Schritt-Workflow</h4>
<p className="text-sm text-gray-600">
Geführter Compliance-Prozess von Use Case bis DSR-Portal
</p>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-medium text-gray-900 mb-2">RAG-basierte Suche</h4>
<p className="text-sm text-gray-600">
Durchsuchen Sie DSGVO, AI Act, NIS2 mit semantischer Suche
</p>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-medium text-gray-900 mb-2">Dokumentengenerierung</h4>
<p className="text-sm text-gray-600">
Automatische Erstellung von DSFA, TOMs, VVT
</p>
</div>
<div className="p-4 border border-gray-200 rounded-lg">
<h4 className="font-medium text-gray-900 mb-2">Export</h4>
<p className="text-sm text-gray-600">
PDF, JSON, ZIP-Export für Audits und Dokumentation
</p>
</div>
</div>
{/* Next Steps */}
<h2>Nächste Schritte</h2>
<ol>
<li>
<Link href="/getting-started" className="text-blue-600 hover:underline">
Quick Start Guide
</Link>
{' '}- Erste Integration in 5 Minuten
</li>
<li>
<Link href="/api/state" className="text-blue-600 hover:underline">
State API
</Link>
{' '}- Verstehen Sie das State Management
</li>
<li>
<Link href="/guides/phase1" className="text-blue-600 hover:underline">
Phase 1 Workflow
</Link>
{' '}- Durchlaufen Sie den Compliance-Prozess
</li>
</ol>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,256 @@
import { DevPortalLayout, CodeBlock, InfoBox, ParameterTable } from '@/components/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/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/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/SDKDocsSidebar'
import { ChevronRight } from 'lucide-react'
const frameworks = [
{
name: 'React',
href: '/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: '/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: '/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="/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/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/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/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="/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="/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/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/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/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/SDKDocsSidebar'
import { ChevronRight, Apple, Smartphone } from 'lucide-react'
const platforms = [
{
name: 'iOS (Swift)',
href: '/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: '/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: '/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/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: '/sdk/consent/installation',
icon: Download,
color: 'bg-blue-500',
},
{
title: 'API Referenz',
description: 'Vollstaendige API-Dokumentation',
href: '/sdk/consent/api-reference',
icon: FileCode,
color: 'bg-purple-500',
},
{
title: 'Frameworks',
description: 'React, Vue, Angular Integration',
href: '/sdk/consent/frameworks',
icon: Layers,
color: 'bg-green-500',
},
{
title: 'Mobile SDKs',
description: 'iOS, Android, Flutter',
href: '/sdk/consent/mobile',
icon: Smartphone,
color: 'bg-orange-500',
},
{
title: 'Sicherheit',
description: 'Best Practices & Compliance',
href: '/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/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/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/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="/sdk/installation" className="text-blue-600 hover:underline">
Installation Guide
</Link>
</li>
<li>
<Link href="/sdk/configuration" className="text-blue-600 hover:underline">
Konfigurationsoptionen
</Link>
</li>
<li>
<Link href="/guides/phase1" className="text-blue-600 hover:underline">
Phase 1 Workflow Guide
</Link>
</li>
</ul>
</InfoBox>
</DevPortalLayout>
)
}

View File

@@ -0,0 +1,313 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { Book, Code, FileText, HelpCircle, Zap, Terminal, Database, Shield, ChevronRight, Clock } from 'lucide-react'
interface NavItem {
title: string
href: string
icon?: React.ReactNode
items?: NavItem[]
}
const navigation: NavItem[] = [
{
title: 'Getting Started',
href: '/getting-started',
icon: <Zap className="w-4 h-4" />,
items: [
{ title: 'Quick Start', href: '/getting-started' },
],
},
{
title: 'SDK Documentation',
href: '/sdk',
icon: <Code className="w-4 h-4" />,
items: [
{ title: 'Overview', href: '/sdk' },
{ title: 'Installation', href: '/sdk/installation' },
{ title: 'Configuration', href: '/sdk/configuration' },
],
},
{
title: 'Consent SDK',
href: '/sdk/consent',
icon: <Shield className="w-4 h-4" />,
items: [
{ title: 'Uebersicht', href: '/sdk/consent' },
{ title: 'Installation', href: '/sdk/consent/installation' },
{ title: 'API Referenz', href: '/sdk/consent/api-reference' },
{ title: 'Frameworks', href: '/sdk/consent/frameworks' },
{ title: 'Mobile SDKs', href: '/sdk/consent/mobile' },
{ title: 'Sicherheit', href: '/sdk/consent/security' },
],
},
{
title: 'API Reference',
href: '/api',
icon: <Terminal className="w-4 h-4" />,
items: [
{ title: 'Overview', href: '/api' },
{ title: 'State API', href: '/api/state' },
{ title: 'RAG Search API', href: '/api/rag' },
{ title: 'Generation API', href: '/api/generate' },
{ title: 'Export API', href: '/api/export' },
],
},
{
title: 'Guides',
href: '/guides',
icon: <Book className="w-4 h-4" />,
items: [
{ title: 'Overview', href: '/guides' },
{ title: 'Phase 1: Assessment', href: '/guides/phase1' },
{ title: 'Phase 2: Dokumentation', href: '/guides/phase2' },
],
},
{
title: 'Changelog',
href: '/changelog',
icon: <Clock className="w-4 h-4" />,
items: [
{ title: 'Versionshistorie', href: '/changelog' },
],
},
]
interface DevPortalLayoutProps {
children: React.ReactNode
title?: string
description?: string
}
export function DevPortalLayout({ children, title, description }: DevPortalLayoutProps) {
const pathname = usePathname()
return (
<div className="min-h-screen bg-white">
{/* Header */}
<header className="sticky top-0 z-50 border-b border-gray-200 bg-white/95 backdrop-blur">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<div className="flex items-center gap-4">
<Link href="/" className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-600 to-indigo-600 flex items-center justify-center">
<FileText className="w-5 h-5 text-white" />
</div>
<span className="font-semibold text-gray-900">Developer Portal</span>
</Link>
<span className="text-gray-300">|</span>
<span className="text-sm text-gray-500">AI Compliance SDK</span>
</div>
<div className="flex items-center gap-4">
<Link
href="https://macmini:3002/sdk"
className="text-sm text-gray-600 hover:text-gray-900 transition-colors"
>
SDK Dashboard
</Link>
<a
href="https://github.com/breakpilot/compliance-sdk"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-gray-600 hover:text-gray-900 transition-colors"
>
GitHub
</a>
</div>
</div>
</div>
</header>
<div className="max-w-7xl mx-auto flex">
{/* Sidebar */}
<aside className="w-64 shrink-0 border-r border-gray-200 h-[calc(100vh-64px)] sticky top-16 overflow-y-auto">
<nav className="p-4 space-y-6">
{navigation.map((section) => (
<div key={section.href}>
<div className="flex items-center gap-2 text-sm font-medium text-gray-900 mb-2">
{section.icon}
<span>{section.title}</span>
</div>
{section.items && (
<ul className="ml-6 space-y-1">
{section.items.map((item) => (
<li key={item.href}>
<Link
href={item.href}
className={`block py-1.5 text-sm transition-colors ${
pathname === item.href
? 'text-blue-600 font-medium'
: 'text-gray-600 hover:text-gray-900'
}`}
>
{item.title}
</Link>
</li>
))}
</ul>
)}
</div>
))}
</nav>
</aside>
{/* Main Content */}
<main className="flex-1 min-w-0">
<div className="max-w-3xl mx-auto px-8 py-12">
{(title || description) && (
<div className="mb-8">
{title && (
<h1 className="text-3xl font-bold text-gray-900 mb-2">{title}</h1>
)}
{description && (
<p className="text-lg text-gray-600">{description}</p>
)}
</div>
)}
<div className="prose prose-gray prose-blue max-w-none">
{children}
</div>
</div>
</main>
</div>
</div>
)
}
// Re-usable components for documentation
export function ApiEndpoint({
method,
path,
description,
}: {
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
path: string
description: string
}) {
const methodColors = {
GET: 'bg-green-100 text-green-800',
POST: 'bg-blue-100 text-blue-800',
PUT: 'bg-yellow-100 text-yellow-800',
DELETE: 'bg-red-100 text-red-800',
}
return (
<div className="border border-gray-200 rounded-lg p-4 my-4 not-prose">
<div className="flex items-center gap-3 mb-2">
<span className={`px-2 py-1 text-xs font-bold rounded ${methodColors[method]}`}>
{method}
</span>
<code className="text-sm font-mono text-gray-800">{path}</code>
</div>
<p className="text-sm text-gray-600">{description}</p>
</div>
)
}
export function CodeBlock({
language,
children,
filename,
}: {
language: string
children: string
filename?: string
}) {
return (
<div className="my-4 not-prose">
{filename && (
<div className="bg-gray-800 text-gray-300 text-xs px-4 py-2 rounded-t-lg border-b border-gray-700">
{filename}
</div>
)}
<pre className={`bg-gray-900 text-gray-100 p-4 overflow-x-auto text-sm ${filename ? 'rounded-b-lg' : 'rounded-lg'}`}>
<code className={`language-${language}`}>{children}</code>
</pre>
</div>
)
}
export function ParameterTable({
parameters,
}: {
parameters: Array<{
name: string
type: string
required?: boolean
description: string
}>
}) {
return (
<div className="my-4 overflow-x-auto not-prose">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Parameter</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Type</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Required</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Description</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{parameters.map((param) => (
<tr key={param.name}>
<td className="px-4 py-3">
<code className="text-sm text-blue-600">{param.name}</code>
</td>
<td className="px-4 py-3">
<code className="text-sm text-gray-600">{param.type}</code>
</td>
<td className="px-4 py-3">
{param.required ? (
<span className="text-red-600 text-sm">Yes</span>
) : (
<span className="text-gray-400 text-sm">No</span>
)}
</td>
<td className="px-4 py-3 text-sm text-gray-600">{param.description}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
export function InfoBox({
type = 'info',
title,
children,
}: {
type?: 'info' | 'warning' | 'success' | 'error'
title?: string
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',
success: 'bg-green-50 border-green-200 text-green-800',
error: 'bg-red-50 border-red-200 text-red-800',
}
const icons = {
info: <HelpCircle className="w-5 h-5" />,
warning: <Shield className="w-5 h-5" />,
success: <Zap className="w-5 h-5" />,
error: <Shield className="w-5 h-5" />,
}
return (
<div className={`my-4 p-4 border rounded-lg ${styles[type]} not-prose`}>
<div className="flex items-start gap-3">
<div className="shrink-0 mt-0.5">{icons[type]}</div>
<div>
{title && <p className="font-medium mb-1">{title}</p>}
<div className="text-sm">{children}</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,165 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import {
Shield, Download, FileCode, Layers, Smartphone, Lock,
ChevronDown, ChevronRight, Home, BookOpen,
Code2
} from 'lucide-react'
interface NavItem {
title: string
href: string
icon?: React.ReactNode
children?: NavItem[]
}
const navigation: NavItem[] = [
{
title: 'Uebersicht',
href: '/sdk/consent',
icon: <Home className="w-4 h-4" />,
},
{
title: 'Installation',
href: '/sdk/consent/installation',
icon: <Download className="w-4 h-4" />,
},
{
title: 'API Referenz',
href: '/sdk/consent/api-reference',
icon: <FileCode className="w-4 h-4" />,
},
{
title: 'Frameworks',
href: '/sdk/consent/frameworks',
icon: <Layers className="w-4 h-4" />,
children: [
{ title: 'React', href: '/sdk/consent/frameworks/react' },
{ title: 'Vue', href: '/sdk/consent/frameworks/vue' },
{ title: 'Angular', href: '/sdk/consent/frameworks/angular' },
],
},
{
title: 'Mobile SDKs',
href: '/sdk/consent/mobile',
icon: <Smartphone className="w-4 h-4" />,
children: [
{ title: 'iOS (Swift)', href: '/sdk/consent/mobile/ios' },
{ title: 'Android (Kotlin)', href: '/sdk/consent/mobile/android' },
{ title: 'Flutter', href: '/sdk/consent/mobile/flutter' },
],
},
{
title: 'Sicherheit',
href: '/sdk/consent/security',
icon: <Lock className="w-4 h-4" />,
},
]
function NavLink({ item, depth = 0 }: { item: NavItem; depth?: number }) {
const pathname = usePathname()
const isActive = pathname === item.href
const isParentActive = item.children?.some((child) => pathname === child.href)
const [isOpen, setIsOpen] = React.useState(isActive || isParentActive)
const hasChildren = item.children && item.children.length > 0
return (
<div>
<div className="flex items-center">
<Link
href={item.href}
className={`flex-1 flex items-center gap-2 px-3 py-2 text-sm rounded-lg transition-colors ${
isActive
? 'bg-violet-100 text-violet-900 font-medium'
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
}`}
style={{ paddingLeft: `${12 + depth * 12}px` }}
>
{item.icon && <span className="shrink-0">{item.icon}</span>}
<span>{item.title}</span>
</Link>
{hasChildren && (
<button
onClick={() => setIsOpen(!isOpen)}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
{isOpen ? (
<ChevronDown className="w-4 h-4 text-gray-400" />
) : (
<ChevronRight className="w-4 h-4 text-gray-400" />
)}
</button>
)}
</div>
{hasChildren && isOpen && (
<div className="mt-1 space-y-1">
{item.children?.map((child) => (
<NavLink key={child.href} item={child} depth={depth + 1} />
))}
</div>
)}
</div>
)
}
export function SDKDocsSidebar() {
return (
<aside className="w-64 h-[calc(100vh-64px)] fixed top-16 left-0 border-r border-gray-200 bg-white overflow-y-auto">
<div className="p-4">
{/* Header */}
<div className="mb-6">
<Link
href="/sdk/consent"
className="flex items-center gap-3 p-3 rounded-xl bg-gradient-to-r from-violet-50 to-purple-50 border border-violet-100"
>
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-violet-600 to-purple-600 flex items-center justify-center">
<Shield className="w-5 h-5 text-white" />
</div>
<div>
<div className="font-semibold text-gray-900">Consent SDK</div>
<div className="text-xs text-gray-500">v1.0.0</div>
</div>
</Link>
</div>
{/* Navigation */}
<nav className="space-y-1">
{navigation.map((item) => (
<NavLink key={item.href} item={item} />
))}
</nav>
{/* Resources */}
<div className="mt-8 pt-6 border-t border-gray-200">
<div className="text-xs font-medium text-gray-400 uppercase tracking-wider mb-3 px-3">
Ressourcen
</div>
<div className="space-y-1">
<a
href="https://github.com/breakpilot/consent-sdk"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 text-sm text-gray-600 hover:bg-gray-100 hover:text-gray-900 rounded-lg transition-colors"
>
<Code2 className="w-4 h-4" />
<span>GitHub</span>
</a>
<Link
href="/"
className="flex items-center gap-2 px-3 py-2 text-sm text-gray-600 hover:bg-gray-100 hover:text-gray-900 rounded-lg transition-colors"
>
<BookOpen className="w-4 h-4" />
<span>Developer Portal</span>
</Link>
</div>
</div>
</div>
</aside>
)
}
export default SDKDocsSidebar

View File

@@ -0,0 +1,10 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
reactStrictMode: true,
typescript: {
ignoreBuildErrors: true,
},
}
module.exports = nextConfig

View File

@@ -0,0 +1,25 @@
{
"name": "breakpilot-developer-portal",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3006",
"build": "next build",
"start": "next start -p 3006"
},
"dependencies": {
"lucide-react": "^0.468.0",
"next": "^15.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^22.10.2",
"@types/react": "^18.3.16",
"@types/react-dom": "^18.3.5",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,9 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
export default config

View File

@@ -0,0 +1,18 @@
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
},
},
plugins: [],
}
export default config

View File

@@ -0,0 +1,40 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}

View File

@@ -18,6 +18,7 @@ services:
- "8089:8089" # HTTPS Edu-Search proxy (edu-search runs on 8088)
- "8093:8093" # HTTPS AI Compliance SDK
- "8443:8443" # HTTPS Jitsi Meet (https://macmini:8443/)
- "3006:3006" # HTTPS Developer Portal (https://macmini:3006/)
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- vault_certs:/etc/nginx/certs:ro
@@ -40,6 +41,8 @@ services:
condition: service_started
jitsi-web:
condition: service_started
developer-portal:
condition: service_started
extra_hosts:
- "breakpilot-edu-search:host-gateway"
networks:
@@ -756,6 +759,24 @@ services:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Developer Portal - Oeffentliches SDK-Dokumentationsportal
# Access: https://macmini:3006/
# ============================================
developer-portal:
build:
context: ./developer-portal
dockerfile: Dockerfile
platform: linux/arm64
container_name: breakpilot-pwa-developer-portal
expose:
- "3000"
environment:
- NODE_ENV=production
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# AI Compliance SDK - Multi-Tenant RBAC & LLM Gateway
# Go auf Port 8090 (intern), 8093 (extern)

View File

@@ -317,6 +317,33 @@ server {
}
}
# HTTPS - Developer Portal on port 3006
# Oeffentliches SDK-Dokumentationsportal (kein Auth)
server {
listen 3006 ssl;
http2 on;
server_name macmini localhost;
ssl_certificate /etc/nginx/certs/macmini.crt;
ssl_certificate_key /etc/nginx/certs/macmini.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
location / {
set $upstream_devportal developer-portal:3000;
proxy_pass http://$upstream_devportal;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
# HTTPS - AI Compliance SDK on port 8093
# Multi-Tenant RBAC, LLM Gateway, Audit Trail
server {