fix: Restore all files lost during destructive rebase

A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-02-09 09:51:32 +01:00
parent f7487ee240
commit bfdaf63ba9
2009 changed files with 749983 additions and 1731 deletions

View File

@@ -3,14 +3,7 @@
import React from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import {
useSDK,
SDK_STEPS,
SDK_PACKAGES,
getStepsForPackage,
type SDKPackageId,
type SDKStep,
} from '@/lib/sdk'
import { useSDK, SDK_STEPS, getStepsForPhase, SDKPhase } from '@/lib/sdk'
// =============================================================================
// ICONS
@@ -51,6 +44,80 @@ const CollapseIcon = ({ collapsed }: { collapsed: boolean }) => (
</svg>
)
// =============================================================================
// PHASE INDICATOR
// =============================================================================
interface PhaseIndicatorProps {
phase: SDKPhase
title: string
completion: number
isActive: boolean
isExpanded: boolean
onToggle: () => void
collapsed: boolean
}
function PhaseIndicator({ phase, title, completion, isActive, isExpanded, onToggle, collapsed }: PhaseIndicatorProps) {
if (collapsed) {
return (
<button
onClick={onToggle}
className={`w-full flex items-center justify-center py-3 transition-colors ${
isActive
? 'bg-purple-50 border-l-4 border-purple-600'
: 'hover:bg-gray-50 border-l-4 border-transparent'
}`}
title={`${title} (${completion}%)`}
>
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold ${
isActive
? 'bg-purple-600 text-white'
: completion === 100
? 'bg-green-500 text-white'
: 'bg-gray-200 text-gray-600'
}`}
>
{completion === 100 ? <CheckIcon /> : phase}
</div>
</button>
)
}
return (
<button
onClick={onToggle}
className={`w-full flex items-center justify-between px-4 py-3 text-left transition-colors ${
isActive
? 'bg-purple-50 border-l-4 border-purple-600'
: 'hover:bg-gray-50 border-l-4 border-transparent'
}`}
>
<div className="flex items-center gap-3">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold ${
isActive
? 'bg-purple-600 text-white'
: completion === 100
? 'bg-green-500 text-white'
: 'bg-gray-200 text-gray-600'
}`}
>
{completion === 100 ? <CheckIcon /> : phase}
</div>
<div>
<div className={`font-medium ${isActive ? 'text-purple-900' : 'text-gray-700'}`}>
{title}
</div>
<div className="text-xs text-gray-500">{completion}% abgeschlossen</div>
</div>
</div>
<ChevronDownIcon className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`} />
</button>
)
}
// =============================================================================
// PROGRESS BAR
// =============================================================================
@@ -71,108 +138,12 @@ function ProgressBar({ value, className = '' }: ProgressBarProps) {
)
}
// =============================================================================
// PACKAGE INDICATOR
// =============================================================================
interface PackageIndicatorProps {
packageId: SDKPackageId
order: number
name: string
icon: string
completion: number
isActive: boolean
isExpanded: boolean
isLocked: boolean
onToggle: () => void
collapsed: boolean
}
function PackageIndicator({
order,
name,
icon,
completion,
isActive,
isExpanded,
isLocked,
onToggle,
collapsed,
}: PackageIndicatorProps) {
if (collapsed) {
return (
<button
onClick={onToggle}
className={`w-full flex items-center justify-center py-3 transition-colors ${
isActive
? 'bg-purple-50 border-l-4 border-purple-600'
: isLocked
? 'border-l-4 border-transparent opacity-50'
: 'hover:bg-gray-50 border-l-4 border-transparent'
}`}
title={`${order}. ${name} (${completion}%)`}
>
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-lg ${
isLocked
? 'bg-gray-200 text-gray-400'
: isActive
? 'bg-purple-600 text-white'
: completion === 100
? 'bg-green-500 text-white'
: 'bg-gray-200 text-gray-600'
}`}
>
{isLocked ? <LockIcon /> : completion === 100 ? <CheckIcon /> : icon}
</div>
</button>
)
}
return (
<button
onClick={onToggle}
disabled={isLocked}
className={`w-full flex items-center justify-between px-4 py-3 text-left transition-colors ${
isLocked
? 'opacity-50 cursor-not-allowed'
: isActive
? 'bg-purple-50 border-l-4 border-purple-600'
: 'hover:bg-gray-50 border-l-4 border-transparent'
}`}
>
<div className="flex items-center gap-3">
<div
className={`w-8 h-8 rounded-full flex items-center justify-center text-lg ${
isLocked
? 'bg-gray-200 text-gray-400'
: isActive
? 'bg-purple-600 text-white'
: completion === 100
? 'bg-green-500 text-white'
: 'bg-gray-200 text-gray-600'
}`}
>
{isLocked ? <LockIcon /> : completion === 100 ? <CheckIcon /> : icon}
</div>
<div>
<div className={`font-medium text-sm ${isActive ? 'text-purple-900' : isLocked ? 'text-gray-400' : 'text-gray-700'}`}>
{order}. {name}
</div>
<div className="text-xs text-gray-500">{completion}%</div>
</div>
</div>
{!isLocked && <ChevronDownIcon className={`transition-transform ${isExpanded ? 'rotate-180' : ''}`} />}
</button>
)
}
// =============================================================================
// STEP ITEM
// =============================================================================
interface StepItemProps {
step: SDKStep
step: (typeof SDK_STEPS)[number]
isActive: boolean
isCompleted: boolean
isLocked: boolean
@@ -290,48 +261,25 @@ interface SDKSidebarProps {
export function SDKSidebar({ collapsed = false, onCollapsedChange }: SDKSidebarProps) {
const pathname = usePathname()
const { state, packageCompletion, completionPercentage, getCheckpointStatus } = useSDK()
const [expandedPackages, setExpandedPackages] = React.useState<Record<SDKPackageId, boolean>>({
'vorbereitung': true,
'analyse': false,
'dokumentation': false,
'rechtliche-texte': false,
'betrieb': false,
const { state, phase1Completion, phase2Completion, getCheckpointStatus } = useSDK()
const [expandedPhases, setExpandedPhases] = React.useState<Record<number, boolean>>({
1: true,
2: true,
})
// Auto-expand current package
React.useEffect(() => {
const currentStep = SDK_STEPS.find(s => s.url === pathname)
if (currentStep) {
setExpandedPackages(prev => ({
...prev,
[currentStep.package]: true,
}))
}
}, [pathname])
const togglePackage = (packageId: SDKPackageId) => {
setExpandedPackages(prev => ({ ...prev, [packageId]: !prev[packageId] }))
const togglePhase = (phase: number) => {
setExpandedPhases(prev => ({ ...prev, [phase]: !prev[phase] }))
}
const isStepLocked = (step: SDKStep): boolean => {
const phase1Steps = getStepsForPhase(1)
const phase2Steps = getStepsForPhase(2)
const isStepLocked = (step: (typeof SDK_STEPS)[number]): boolean => {
if (state.preferences?.allowParallelWork) return false
return step.prerequisiteSteps.some(prereq => !state.completedSteps.includes(prereq))
}
const isPackageLocked = (packageId: SDKPackageId): boolean => {
if (state.preferences?.allowParallelWork) return false
const pkg = SDK_PACKAGES.find(p => p.id === packageId)
if (!pkg || pkg.order === 1) return false
// Check if previous package is complete
const prevPkg = SDK_PACKAGES.find(p => p.order === pkg.order - 1)
if (!prevPkg) return false
return packageCompletion[prevPkg.id] < 100
}
const getStepCheckpointStatus = (step: SDKStep): 'passed' | 'failed' | 'warning' | 'pending' => {
const getStepCheckpointStatus = (step: (typeof SDK_STEPS)[number]): 'passed' | 'failed' | 'warning' | 'pending' => {
const status = getCheckpointStatus(step.checkpointId)
if (!status) return 'pending'
if (status.passed) return 'passed'
@@ -340,25 +288,6 @@ export function SDKSidebar({ collapsed = false, onCollapsedChange }: SDKSidebarP
return 'pending'
}
const isStepActive = (stepUrl: string) => pathname === stepUrl
const isPackageActive = (packageId: SDKPackageId) => {
const steps = getStepsForPackage(packageId)
return steps.some(s => s.url === pathname)
}
// Filter steps based on customer type
const getVisibleSteps = (packageId: SDKPackageId): SDKStep[] => {
const steps = getStepsForPackage(packageId)
return steps.filter(step => {
// Hide import step for new customers
if (step.id === 'import' && state.customerType === 'new') {
return false
}
return true
})
}
return (
<aside className={`fixed left-0 top-0 h-screen ${collapsed ? 'w-16' : 'w-64'} bg-white border-r border-gray-200 flex flex-col z-40 transition-all duration-300`}>
{/* Header */}
@@ -388,51 +317,71 @@ export function SDKSidebar({ collapsed = false, onCollapsedChange }: SDKSidebarP
<div className="px-4 py-3 border-b border-gray-100">
<div className="flex items-center justify-between text-sm mb-2">
<span className="text-gray-600">Gesamtfortschritt</span>
<span className="font-medium text-purple-600">{completionPercentage}%</span>
<span className="font-medium text-purple-600">
{Math.round((phase1Completion + phase2Completion) / 2)}%
</span>
</div>
<ProgressBar value={completionPercentage} />
<ProgressBar value={(phase1Completion + phase2Completion) / 2} />
</div>
)}
{/* Navigation - 5 Packages */}
{/* Navigation */}
<nav className="flex-1 overflow-y-auto">
{SDK_PACKAGES.map(pkg => {
const steps = getVisibleSteps(pkg.id)
const isLocked = isPackageLocked(pkg.id)
const isActive = isPackageActive(pkg.id)
return (
<div key={pkg.id} className={pkg.order > 1 ? 'border-t border-gray-100' : ''}>
<PackageIndicator
packageId={pkg.id}
order={pkg.order}
name={pkg.name}
icon={pkg.icon}
completion={packageCompletion[pkg.id]}
isActive={isActive}
isExpanded={expandedPackages[pkg.id]}
isLocked={isLocked}
onToggle={() => togglePackage(pkg.id)}
collapsed={collapsed}
/>
{expandedPackages[pkg.id] && !isLocked && (
<div className="py-1">
{steps.map(step => (
<StepItem
key={step.id}
step={step}
isActive={isStepActive(step.url)}
isCompleted={state.completedSteps.includes(step.id)}
isLocked={isStepLocked(step)}
checkpointStatus={getStepCheckpointStatus(step)}
collapsed={collapsed}
/>
))}
</div>
)}
{/* Phase 1 */}
<div>
<PhaseIndicator
phase={1}
title="Compliance Assessment"
completion={phase1Completion}
isActive={state.currentPhase === 1}
isExpanded={expandedPhases[1]}
onToggle={() => togglePhase(1)}
collapsed={collapsed}
/>
{expandedPhases[1] && (
<div className="py-1">
{phase1Steps.map(step => (
<StepItem
key={step.id}
step={step}
isActive={pathname === step.url}
isCompleted={state.completedSteps.includes(step.id)}
isLocked={isStepLocked(step)}
checkpointStatus={getStepCheckpointStatus(step)}
collapsed={collapsed}
/>
))}
</div>
)
})}
)}
</div>
{/* Phase 2 */}
<div className="border-t border-gray-100">
<PhaseIndicator
phase={2}
title="Dokumentengenerierung"
completion={phase2Completion}
isActive={state.currentPhase === 2}
isExpanded={expandedPhases[2]}
onToggle={() => togglePhase(2)}
collapsed={collapsed}
/>
{expandedPhases[2] && (
<div className="py-1">
{phase2Steps.map(step => (
<StepItem
key={step.id}
step={step}
isActive={pathname === step.url}
isCompleted={state.completedSteps.includes(step.id)}
isLocked={isStepLocked(step)}
checkpointStatus={getStepCheckpointStatus(step)}
collapsed={collapsed}
/>
))}
</div>
)}
</div>
{/* Additional Modules */}
<div className="border-t border-gray-100 py-2">