fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit restores all missing components: - Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education, infrastructure, communication, development, onboarding, rbac - SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen, vendor-compliance, tom-generator, dsr, and more - Developer portal (25 pages): API docs, SDK guides, frameworks - All components, lib files, hooks, and types - Updated package.json with all dependencies The issue was caused by incomplete initial repository state - the full admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2 but was never fully synced to the main admin-v2 directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
107
admin-v2/app/api/sdk/v1/tom-generator/controls/evaluate/route.ts
Normal file
107
admin-v2/app/api/sdk/v1/tom-generator/controls/evaluate/route.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { TOMRulesEngine } from '@/lib/sdk/tom-generator/rules-engine'
|
||||
import { TOMGeneratorState } from '@/lib/sdk/tom-generator/types'
|
||||
|
||||
/**
|
||||
* TOM Generator Controls Evaluation API
|
||||
*
|
||||
* POST /api/sdk/v1/tom-generator/controls/evaluate - Evaluate controls for given state
|
||||
*
|
||||
* Request body:
|
||||
* {
|
||||
* state: TOMGeneratorState
|
||||
* }
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* evaluations: RulesEngineResult[]
|
||||
* derivedTOMs: DerivedTOM[]
|
||||
* summary: {
|
||||
* total: number
|
||||
* required: number
|
||||
* recommended: number
|
||||
* optional: number
|
||||
* notApplicable: number
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { state } = body
|
||||
|
||||
if (!state) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'state is required in request body' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Parse dates in state
|
||||
const parsedState: TOMGeneratorState = {
|
||||
...state,
|
||||
createdAt: new Date(state.createdAt),
|
||||
updatedAt: new Date(state.updatedAt),
|
||||
steps: state.steps?.map((step: { id: string; completed: boolean; data: unknown; validatedAt: string | null }) => ({
|
||||
...step,
|
||||
validatedAt: step.validatedAt ? new Date(step.validatedAt) : null,
|
||||
})) || [],
|
||||
documents: [],
|
||||
derivedTOMs: [],
|
||||
gapAnalysis: null,
|
||||
exports: [],
|
||||
}
|
||||
|
||||
// Initialize rules engine and evaluate
|
||||
const engine = new TOMRulesEngine()
|
||||
const evaluations = engine.evaluateControls(parsedState)
|
||||
const derivedTOMs = engine.deriveAllTOMs(parsedState)
|
||||
|
||||
// Calculate summary
|
||||
const summary = {
|
||||
total: evaluations.length,
|
||||
required: evaluations.filter((e) => e.applicability === 'REQUIRED').length,
|
||||
recommended: evaluations.filter((e) => e.applicability === 'RECOMMENDED').length,
|
||||
optional: evaluations.filter((e) => e.applicability === 'OPTIONAL').length,
|
||||
notApplicable: evaluations.filter((e) => e.applicability === 'NOT_APPLICABLE').length,
|
||||
}
|
||||
|
||||
// Group by category
|
||||
const byCategory: Record<string, typeof evaluations> = {}
|
||||
evaluations.forEach((e) => {
|
||||
const category = e.controlId.split('-')[1] // Extract category from ID like TOM-AC-01
|
||||
if (!byCategory[category]) {
|
||||
byCategory[category] = []
|
||||
}
|
||||
byCategory[category].push(e)
|
||||
})
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
evaluations,
|
||||
derivedTOMs,
|
||||
summary,
|
||||
byCategory,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to evaluate controls:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Failed to evaluate controls' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function OPTIONS() {
|
||||
return NextResponse.json(
|
||||
{ status: 'ok' },
|
||||
{
|
||||
headers: {
|
||||
Allow: 'POST, OPTIONS',
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
128
admin-v2/app/api/sdk/v1/tom-generator/controls/route.ts
Normal file
128
admin-v2/app/api/sdk/v1/tom-generator/controls/route.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import {
|
||||
getAllControls,
|
||||
getControlById,
|
||||
getControlsByCategory,
|
||||
searchControls,
|
||||
getCategories,
|
||||
} from '@/lib/sdk/tom-generator/controls/loader'
|
||||
import { ControlCategory } from '@/lib/sdk/tom-generator/types'
|
||||
|
||||
/**
|
||||
* TOM Generator Controls API
|
||||
*
|
||||
* GET /api/sdk/v1/tom-generator/controls - List all controls
|
||||
* GET /api/sdk/v1/tom-generator/controls?id=xxx - Get single control
|
||||
* GET /api/sdk/v1/tom-generator/controls?category=xxx - Filter by category
|
||||
* GET /api/sdk/v1/tom-generator/controls?search=xxx - Search controls
|
||||
* GET /api/sdk/v1/tom-generator/controls?categories=true - Get categories list
|
||||
*/
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const id = searchParams.get('id')
|
||||
const category = searchParams.get('category')
|
||||
const search = searchParams.get('search')
|
||||
const categoriesOnly = searchParams.get('categories')
|
||||
const language = (searchParams.get('language') || 'de') as 'de' | 'en'
|
||||
|
||||
// Get categories list
|
||||
if (categoriesOnly === 'true') {
|
||||
const categories = getCategories()
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: categories,
|
||||
})
|
||||
}
|
||||
|
||||
// Get single control by ID
|
||||
if (id) {
|
||||
const control = getControlById(id)
|
||||
if (!control) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: `Control not found: ${id}` },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
...control,
|
||||
// Return localized name and description
|
||||
localizedName: control.name[language],
|
||||
localizedDescription: control.description[language],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Filter by category
|
||||
if (category) {
|
||||
const controls = getControlsByCategory(category as ControlCategory)
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: controls.map((c) => ({
|
||||
...c,
|
||||
localizedName: c.name[language],
|
||||
localizedDescription: c.description[language],
|
||||
})),
|
||||
meta: {
|
||||
category,
|
||||
count: controls.length,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Search controls
|
||||
if (search) {
|
||||
const controls = searchControls(search, language)
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: controls.map((c) => ({
|
||||
...c,
|
||||
localizedName: c.name[language],
|
||||
localizedDescription: c.description[language],
|
||||
})),
|
||||
meta: {
|
||||
query: search,
|
||||
count: controls.length,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Return all controls
|
||||
const controls = getAllControls()
|
||||
const categories = getCategories()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: controls.map((c) => ({
|
||||
...c,
|
||||
localizedName: c.name[language],
|
||||
localizedDescription: c.description[language],
|
||||
})),
|
||||
meta: {
|
||||
totalControls: controls.length,
|
||||
categories: categories.length,
|
||||
language,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch controls:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Failed to fetch controls' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function OPTIONS() {
|
||||
return NextResponse.json(
|
||||
{ status: 'ok' },
|
||||
{
|
||||
headers: {
|
||||
Allow: 'GET, OPTIONS',
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user