[split-required] Split 58 monoliths across Python, Go, TypeScript (Phases 1-3)

Phase 1 — Python (klausur-service): 5 monoliths → 36 files
- dsfa_corpus_ingestion.py (1,828 LOC → 5 files)
- cv_ocr_engines.py (2,102 LOC → 7 files)
- cv_layout.py (3,653 LOC → 10 files)
- vocab_worksheet_api.py (2,783 LOC → 8 files)
- grid_build_core.py (1,958 LOC → 6 files)

Phase 2 — Go (edu-search-service, school-service): 8 monoliths → 19 files
- staff_crawler.go (1,402 → 4), policy/store.go (1,168 → 3)
- policy_handlers.go (700 → 2), repository.go (684 → 2)
- search.go (592 → 2), ai_extraction_handlers.go (554 → 2)
- seed_data.go (591 → 2), grade_service.go (646 → 2)

Phase 3 — TypeScript (admin-lehrer): 45 monoliths → 220+ files
- sdk/types.ts (2,108 → 16 domain files)
- ai/rag/page.tsx (2,686 → 14 files)
- 22 page.tsx files split into _components/ + _hooks/
- 11 component files split into sub-components
- 10 SDK data catalogs added to loc-exceptions
- Deleted dead backup index_original.ts (4,899 LOC)

All original public APIs preserved via re-export facades.
Zero new errors: Python imports verified, Go builds clean,
TypeScript tsc --noEmit shows only pre-existing errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-24 17:28:57 +02:00
parent 9ba420fa91
commit b681ddb131
251 changed files with 30016 additions and 25037 deletions

View File

@@ -0,0 +1,225 @@
'use client'
import { useState, useEffect, useCallback } from 'react'
import type { TabId, Tenant, Namespace, Role, UserRole, LLMPolicy } from './types'
import { SDK_BASE_URL } from './types'
export interface RbacStats {
tenants: number
namespaces: number
roles: number
systemRoles: number
policies: number
activeUsers: number
}
export function useRbacData() {
const [activeTab, setActiveTab] = useState<TabId>('tenants')
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
// Data states
const [tenants, setTenants] = useState<Tenant[]>([])
const [namespaces, setNamespaces] = useState<Namespace[]>([])
const [roles, setRoles] = useState<Role[]>([])
const [userRoles, setUserRoles] = useState<UserRole[]>([])
const [policies, setPolicies] = useState<LLMPolicy[]>([])
// Filter states
const [selectedTenantId, setSelectedTenantId] = useState<string>('')
const [searchTerm, setSearchTerm] = useState('')
// Modal states
const [showCreateModal, setShowCreateModal] = useState(false)
const [editItem, setEditItem] = useState<any>(null)
// Load data based on active tab
const loadData = useCallback(async () => {
setLoading(true)
setError(null)
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
}
if (selectedTenantId) {
headers['X-Tenant-ID'] = selectedTenantId
}
switch (activeTab) {
case 'tenants': {
const res = await fetch(`${SDK_BASE_URL}/sdk/v1/tenants`, { headers })
if (res.ok) {
const data = await res.json()
setTenants(data.tenants || [])
}
break
}
case 'namespaces': {
if (!selectedTenantId) {
setNamespaces([])
break
}
const res = await fetch(`${SDK_BASE_URL}/sdk/v1/tenants/${selectedTenantId}/namespaces`, { headers })
if (res.ok) {
const data = await res.json()
setNamespaces(data.namespaces || [])
}
break
}
case 'roles': {
const res = await fetch(`${SDK_BASE_URL}/sdk/v1/roles`, { headers })
if (res.ok) {
const data = await res.json()
setRoles(data.roles || [])
}
break
}
case 'users': {
// This would need a user ID - for now show empty
setUserRoles([])
break
}
case 'policies': {
const res = await fetch(`${SDK_BASE_URL}/sdk/v1/llm/policies`, { headers })
if (res.ok) {
const data = await res.json()
setPolicies(data.policies || [])
}
break
}
}
} catch (err) {
console.error('Failed to load data:', err)
setError('Verbindung zum AI Compliance SDK fehlgeschlagen. Stellen Sie sicher, dass der SDK-Service laeuft.')
} finally {
setLoading(false)
}
}, [activeTab, selectedTenantId])
useEffect(() => {
loadData()
}, [loadData])
// Load tenants on mount for the filter
useEffect(() => {
const loadTenants = async () => {
try {
const res = await fetch(`${SDK_BASE_URL}/sdk/v1/tenants`)
if (res.ok) {
const data = await res.json()
setTenants(data.tenants || [])
if (data.tenants?.length > 0 && !selectedTenantId) {
setSelectedTenantId(data.tenants[0].id)
}
}
} catch (err) {
console.error('Failed to load tenants:', err)
}
}
loadTenants()
}, [])
const handleCreate = async (data: any) => {
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
}
if (selectedTenantId) {
headers['X-Tenant-ID'] = selectedTenantId
}
let endpoint = ''
switch (activeTab) {
case 'tenants':
endpoint = `${SDK_BASE_URL}/sdk/v1/tenants`
break
case 'namespaces':
endpoint = `${SDK_BASE_URL}/sdk/v1/tenants/${selectedTenantId}/namespaces`
break
case 'roles':
endpoint = `${SDK_BASE_URL}/sdk/v1/roles`
break
case 'policies':
endpoint = `${SDK_BASE_URL}/sdk/v1/llm/policies`
break
}
const res = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(data),
})
if (res.ok) {
setShowCreateModal(false)
loadData()
} else {
const errData = await res.json()
alert(`Fehler: ${errData.error || 'Unbekannter Fehler'}`)
}
} catch (err) {
console.error('Create failed:', err)
alert('Erstellen fehlgeschlagen')
}
}
const filteredData = () => {
const term = searchTerm.toLowerCase()
switch (activeTab) {
case 'tenants':
return tenants.filter(t =>
t.name.toLowerCase().includes(term) ||
t.slug.toLowerCase().includes(term)
)
case 'namespaces':
return namespaces.filter(n =>
n.name.toLowerCase().includes(term) ||
n.slug.toLowerCase().includes(term)
)
case 'roles':
return roles.filter(r =>
r.name.toLowerCase().includes(term) ||
r.description?.toLowerCase().includes(term)
)
case 'policies':
return policies.filter(p =>
p.name.toLowerCase().includes(term)
)
default:
return []
}
}
const stats: RbacStats = {
tenants: tenants.length,
namespaces: namespaces.length,
roles: roles.length,
systemRoles: roles.filter(r => r.is_system_role).length,
policies: policies.length,
activeUsers: userRoles.length,
}
return {
activeTab,
setActiveTab,
loading,
error,
tenants,
userRoles,
selectedTenantId,
setSelectedTenantId,
searchTerm,
setSearchTerm,
showCreateModal,
setShowCreateModal,
editItem,
setEditItem,
handleCreate,
filteredData,
stats,
}
}