{
"tool_response": {
"type": "update",
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ContentController.php",
"content": "<?php\n\nnamespace Controller;\n\nuse Application\\ContentCollectionService;\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Persistence\\CollectionRepository;\nuse Infrastructure\\Persistence\\ContentRepository;\nuse Infrastructure\\Validation\\CollectionValidator;\nuse UseCases\\Command\\CreateContentOrderCommand;\nuse UseCases\\Command\\GenerateContentCommand;\nuse UseCases\\Content\\GenerateContentUseCase;\n\nclass ContentController extends Controller\n{\n private ContentRepository $repository;\n private ContentCollectionService $collectionService;\n private GenerateContentUseCase $generateUseCase;\n\n public function __construct()\n {\n $this->repository = new ContentRepository();\n $collectionRepo = new CollectionRepository();\n $this->collectionService = new ContentCollectionService(\n $collectionRepo,\n new CollectionValidator($collectionRepo)\n );\n $this->generateUseCase = new GenerateContentUseCase();\n }\n\n \/**\n * GET \/content - List all content orders\n *\/\n public function index(): void\n {\n $status = $this->getString('status');\n\n $this->view('content.index', [\n 'title' => 'Content Studio',\n 'orders' => $this->repository->findAllOrders($status !== '' ? ['status' => $status] : []),\n 'stats' => $this->repository->getStatistics(),\n 'currentStatus' => $status,\n ]);\n }\n\n \/**\n * GET \/content\/new - Show create form\n *\/\n public function contentNew(): void\n {\n $lastSettings = $this->repository->getLastOrderSettings();\n\n $this->view('content.new', [\n 'title' => 'Neuer Content-Auftrag',\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n 'models' => ModelConfig::getAll(),\n 'collections' => $this->collectionService->getAvailable(),\n 'defaultModel' => $lastSettings['model'],\n 'defaultCollections' => $lastSettings['collections'],\n 'defaultContextLimit' => $lastSettings['context_limit'],\n 'defaultProfileId' => $lastSettings['author_profile_id'],\n 'defaultContractId' => $lastSettings['contract_id'],\n 'defaultStructureId' => $lastSettings['structure_id'],\n ]);\n }\n\n \/**\n * POST \/content - Store new order\n *\/\n public function store(): void\n {\n $this->requireCsrf();\n\n $command = CreateContentOrderCommand::fromRequest($_POST);\n $errors = $command->validate();\n\n if ($errors !== []) {\n $_SESSION['error'] = implode(' ', $errors);\n $this->redirect('\/content\/new');\n }\n\n \/\/ Validate collections\n $result = $this->collectionService->validateWithCompatibility($command->collections);\n if (!$result['valid']) {\n $_SESSION['error'] = 'Collection-Fehler: ' . $result['error'];\n $this->redirect('\/content\/new');\n }\n\n $orderId = $this->repository->createOrder([\n 'title' => $command->title,\n 'briefing' => $command->briefing,\n 'author_profile_id' => $command->authorProfileId,\n 'contract_id' => $command->contractId ?? $this->getFirstContractId(),\n 'structure_id' => $command->structureId,\n 'model' => ModelConfig::validate($command->model),\n 'collections' => json_encode($result['collections']),\n 'context_limit' => $command->contextLimit,\n ]);\n\n if ($command->shouldGenerate()) {\n $genResult = $this->generateUseCase->generate(\n $orderId,\n ModelConfig::validate($command->model),\n $result['collections'][0] ?? 'documents',\n $command->contextLimit\n );\n $_SESSION[$genResult->hasError() ? 'error' : 'success'] =\n $genResult->hasError() ? 'Generierung fehlgeschlagen: ' . $genResult->getError() : 'Content wurde generiert.';\n }\n\n $this->redirect('\/content\/' . $orderId);\n }\n\n \/**\n * GET \/content\/{id} - Show order details\n *\/\n public function show(int $id): void\n {\n $order = $this->repository->findOrder($id);\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $versions = $this->repository->findVersionsByOrder($id);\n $latestVersion = $versions[0] ?? null;\n\n $this->view('content.show', [\n 'title' => $order['title'],\n 'order' => $order,\n 'versions' => $versions,\n 'latestVersion' => $latestVersion,\n 'critiques' => $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [],\n 'sources' => $this->repository->findSourcesByOrder($id),\n 'models' => ModelConfig::getAll(),\n 'availableCollections' => $this->collectionService->getAvailable(),\n ]);\n }\n\n \/**\n * GET \/content\/{id}\/edit - Show edit form\n *\/\n public function edit(int $id): void\n {\n $order = $this->repository->findOrder($id);\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $this->view('content.edit', [\n 'title' => 'Auftrag bearbeiten',\n 'order' => $order,\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n ]);\n }\n\n \/**\n * POST \/content\/{id}\/generate - Generate content (HTMX)\n *\/\n public function generate(int $id): void\n {\n $this->requireCsrf();\n\n $command = GenerateContentCommand::fromRequest($id, $_POST);\n if (($errors = $command->validate()) !== []) {\n $this->htmxError(implode(' ', $errors));\n return;\n }\n\n $result = $this->collectionService->validateWithCompatibility([$command->collection]);\n if (!$result['valid']) {\n $this->htmxError($result['error'] ?? 'Collection-Fehler');\n return;\n }\n\n $genResult = $this->generateUseCase->generate($id, $command->model, $result['collections'][0], $command->contextLimit);\n if ($genResult->hasError()) {\n $this->htmxError('Fehler: ' . $genResult->getError());\n return;\n }\n\n $this->renderVersionPartial($genResult->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/critique - Run critique round (HTMX)\n *\/\n public function critique(int $id): void\n {\n $this->requireCsrf();\n\n $version = $this->repository->findLatestVersion($id);\n if ($version === null) {\n $this->htmxError('Keine Version vorhanden.');\n return;\n }\n\n $result = $this->generateUseCase->critique($version['id'], $_POST['model'] ?? 'claude-opus-4-5-20251101');\n if ($result->hasError()) {\n $this->htmxError('Fehler: ' . $result->getError());\n return;\n }\n\n $this->renderCritiquePartial($result->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/revise - Create revision (HTMX)\n *\/\n public function revise(int $id): void\n {\n $this->requireCsrf();\n\n $version = $this->repository->findLatestVersion($id);\n if ($version === null) {\n $this->htmxError('Keine Version vorhanden.');\n return;\n }\n\n $result = $this->generateUseCase->revise($version['id'], $_POST['model'] ?? 'claude-opus-4-5-20251101');\n if ($result->hasError()) {\n $this->htmxError('Fehler: ' . $result->getError());\n return;\n }\n\n $this->renderVersionPartial($result->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/approve - Approve content\n *\/\n public function approve(int $id): void\n {\n $this->requireCsrf();\n $this->repository->updateOrderStatus($id, 'approve');\n $this->htmxSuccess('Content genehmigt!');\n echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n }\n\n \/**\n * POST \/content\/{id}\/decline - Decline content\n *\/\n public function decline(int $id): void\n {\n $this->requireCsrf();\n $this->repository->updateOrderStatus($id, 'draft');\n $this->htmxAlert('warning', 'Content abgelehnt. Zurück zu Entwurf.');\n echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n }\n\n private function getFirstContractId(): ?int\n {\n $contracts = $this->repository->findAllContracts();\n return $contracts !== [] ? (int) $contracts[0]['id'] : null;\n }\n\n private function renderVersionPartial(array $result): void\n {\n $this->view('content.partials.version', [\n 'content' => $result['content'] ?? '',\n 'sources' => $result['sources'] ?? [],\n 'versionNumber' => $result['version_number'] ?? '?',\n ]);\n }\n\n private function renderCritiquePartial(array $result): void\n {\n $this->view('content.partials.critique', [\n 'critiques' => $result['critiques'] ?? [],\n 'allPassed' => $result['all_passed'] ?? false,\n 'round' => $result['round'] ?? '?',\n ]);\n }\n}\n",
"structuredPatch": [
{
"oldStart": 2,
"oldLines": 6,
"newStart": 2,
"newLines": 7,
"lines": [
" ",
" namespace Controller;",
" ",
"+use Application\\ContentCollectionService;",
" use Framework\\Controller;",
" use Infrastructure\\AI\\ModelConfig;",
" use Infrastructure\\Persistence\\CollectionRepository;"
]
},
{
"oldStart": 14,
"oldLines": 48,
"newStart": 15,
"newLines": 40,
"lines": [
" class ContentController extends Controller",
" {",
" private ContentRepository $repository;",
"- private CollectionRepository $collectionRepository;",
"- private CollectionValidator $collectionValidator;",
"+ private ContentCollectionService $collectionService;",
" private GenerateContentUseCase $generateUseCase;",
" ",
" public function __construct()",
" {",
" $this->repository = new ContentRepository();",
"- $this->collectionRepository = new CollectionRepository();",
"- $this->collectionValidator = new CollectionValidator($this->collectionRepository);",
"+ $collectionRepo = new CollectionRepository();",
"+ $this->collectionService = new ContentCollectionService(",
"+ $collectionRepo,",
"+ new CollectionValidator($collectionRepo)",
"+ );",
" $this->generateUseCase = new GenerateContentUseCase();",
" }",
" ",
" \/**",
"- * GET \/content",
"- * List all content orders",
"+ * GET \/content - List all content orders",
" *\/",
" public function index(): void",
" {",
"- $filters = [];",
" $status = $this->getString('status');",
"- if ($status !== '') {",
"- $filters['status'] = $status;",
"- }",
" ",
"- $orders = $this->repository->findAllOrders($filters);",
"- $stats = $this->repository->getStatistics();",
"-",
" $this->view('content.index', [",
" 'title' => 'Content Studio',",
"- 'orders' => $orders,",
"- 'stats' => $stats,",
"+ 'orders' => $this->repository->findAllOrders($status !== '' ? ['status' => $status] : []),",
"+ 'stats' => $this->repository->getStatistics(),",
" 'currentStatus' => $status,",
" ]);",
" }",
" ",
" \/**",
"- * GET \/content\/new",
"- * Show create form",
"+ * GET \/content\/new - Show create form",
" *\/",
" public function contentNew(): void",
" {",
"- $collections = $this->getAvailableCollections();",
" $lastSettings = $this->repository->getLastOrderSettings();",
" ",
" $this->view('content.new', ["
]
},
{
"oldStart": 64,
"oldLines": 8,
"newStart": 57,
"newLines": 7,
"lines": [
" 'contracts' => $this->repository->findAllContracts(),",
" 'structures' => $this->repository->findAllStructures(),",
" 'models' => ModelConfig::getAll(),",
"- 'collections' => $collections,",
"- \/\/ Defaults from last order",
"+ 'collections' => $this->collectionService->getAvailable(),",
" 'defaultModel' => $lastSettings['model'],",
" 'defaultCollections' => $lastSettings['collections'],",
" 'defaultContextLimit' => $lastSettings['context_limit'],"
]
},
{
"oldStart": 76,
"oldLines": 8,
"newStart": 68,
"newLines": 7,
"lines": [
" }",
" ",
" \/**",
"- * POST \/content",
"- * Store new order",
"+ * POST \/content - Store new order",
" *\/",
" public function store(): void",
" {"
]
},
{
"oldStart": 91,
"oldLines": 91,
"newStart": 82,
"newLines": 69,
"lines": [
" $this->redirect('\/content\/new');",
" }",
" ",
"- \/\/ Auto-apply first active contract if none selected",
"- $contractId = $command->contractId;",
"- if ($contractId === null) {",
"- $contracts = $this->repository->findAllContracts();",
"- if ($contracts !== []) {",
"- $contractId = (int) $contracts[0]['id'];",
"- }",
"- }",
"-",
"- \/\/ Validate collection compatibility",
"- $collections = $this->validateCollections($command->collections);",
"- $compatibility = $this->validateCollectionCompatibility($collections);",
"- if (!$compatibility['valid']) {",
"- $_SESSION['error'] = 'Collection-Fehler: ' . $compatibility['error'];",
"+ \/\/ Validate collections",
"+ $result = $this->collectionService->validateWithCompatibility($command->collections);",
"+ if (!$result['valid']) {",
"+ $_SESSION['error'] = 'Collection-Fehler: ' . $result['error'];",
" $this->redirect('\/content\/new');",
" }",
" ",
"- $model = ModelConfig::validate($command->model);",
"-",
" $orderId = $this->repository->createOrder([",
" 'title' => $command->title,",
" 'briefing' => $command->briefing,",
" 'author_profile_id' => $command->authorProfileId,",
"- 'contract_id' => $contractId,",
"+ 'contract_id' => $command->contractId ?? $this->getFirstContractId(),",
" 'structure_id' => $command->structureId,",
"- 'model' => $model,",
"- 'collections' => json_encode($collections),",
"+ 'model' => ModelConfig::validate($command->model),",
"+ 'collections' => json_encode($result['collections']),",
" 'context_limit' => $command->contextLimit,",
" ]);",
" ",
"- \/\/ If \"generate\" action: generate content immediately",
" if ($command->shouldGenerate()) {",
"- $collection = $collections[0] ?? 'documents';",
"- $result = $this->generateUseCase->generate($orderId, $model, $collection, $command->contextLimit);",
"-",
"- if ($result->hasError()) {",
"- $_SESSION['error'] = 'Generierung fehlgeschlagen: ' . $result->getError();",
"- } else {",
"- $_SESSION['success'] = 'Content wurde generiert.';",
"- }",
"+ $genResult = $this->generateUseCase->generate(",
"+ $orderId,",
"+ ModelConfig::validate($command->model),",
"+ $result['collections'][0] ?? 'documents',",
"+ $command->contextLimit",
"+ );",
"+ $_SESSION[$genResult->hasError() ? 'error' : 'success'] =",
"+ $genResult->hasError() ? 'Generierung fehlgeschlagen: ' . $genResult->getError() : 'Content wurde generiert.';",
" }",
" ",
" $this->redirect('\/content\/' . $orderId);",
" }",
" ",
" \/**",
"- * GET \/content\/{id}",
"- * Show order details",
"+ * GET \/content\/{id} - Show order details",
" *\/",
" public function show(int $id): void",
" {",
" $order = $this->repository->findOrder($id);",
"-",
" if ($order === null) {",
" $this->notFound('Auftrag nicht gefunden');",
" }",
" ",
" $versions = $this->repository->findVersionsByOrder($id);",
" $latestVersion = $versions[0] ?? null;",
"- $critiques = $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [];",
"- $sources = $this->repository->findSourcesByOrder($id);",
" ",
"- \/\/ Get available collections for the dropdown",
"- $availableCollections = $this->getAvailableCollections();",
"-",
" $this->view('content.show', [",
" 'title' => $order['title'],",
" 'order' => $order,",
" 'versions' => $versions,",
" 'latestVersion' => $latestVersion,",
"- 'critiques' => $critiques,",
"- 'sources' => $sources,",
"+ 'critiques' => $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [],",
"+ 'sources' => $this->repository->findSourcesByOrder($id),",
" 'models' => ModelConfig::getAll(),",
"- 'availableCollections' => $availableCollections,",
"+ 'availableCollections' => $this->collectionService->getAvailable(),",
" ]);",
" }",
" ",
" \/**",
"- * GET \/content\/{id}\/edit",
"- * Show edit form",
"+ * GET \/content\/{id}\/edit - Show edit form",
" *\/",
" public function edit(int $id): void",
" {",
" $order = $this->repository->findOrder($id);",
"-",
" if ($order === null) {",
" $this->notFound('Auftrag nicht gefunden');",
" }"
]
},
{
"oldStart": 190,
"oldLines": 103,
"newStart": 159,
"newLines": 71,
"lines": [
" }",
" ",
" \/**",
"- * POST \/content\/{id}\/generate",
"- * Generate content (HTMX)",
"+ * POST \/content\/{id}\/generate - Generate content (HTMX)",
" *\/",
" public function generate(int $id): void",
" {",
" $this->requireCsrf();",
" ",
" $command = GenerateContentCommand::fromRequest($id, $_POST);",
"- $errors = $command->validate();",
"-",
"- if ($errors !== []) {",
"+ if (($errors = $command->validate()) !== []) {",
" $this->htmxError(implode(' ', $errors));",
"-",
" return;",
" }",
" ",
"- \/\/ Validate collection",
"- $collections = $this->validateCollections([$command->collection]);",
"- if (empty($collections)) {",
"- $this->htmxError('Ungültige Collection: ' . $command->collection);",
"-",
"+ $result = $this->collectionService->validateWithCompatibility([$command->collection]);",
"+ if (!$result['valid']) {",
"+ $this->htmxError($result['error'] ?? 'Collection-Fehler');",
" return;",
" }",
"- $collection = $collections[0];",
" ",
"- \/\/ Validate compatibility (single collection always valid, but check exists)",
"- $compatibility = $this->validateCollectionCompatibility($collections);",
"- if (!$compatibility['valid']) {",
"- $this->htmxError($compatibility['error'] ?? 'Collection-Fehler');",
"-",
"+ $genResult = $this->generateUseCase->generate($id, $command->model, $result['collections'][0], $command->contextLimit);",
"+ if ($genResult->hasError()) {",
"+ $this->htmxError('Fehler: ' . $genResult->getError());",
" return;",
" }",
" ",
"- $result = $this->generateUseCase->generate($id, $command->model, $collection, $command->contextLimit);",
"-",
"- if ($result->hasError()) {",
"- $this->htmxError('Fehler: ' . $result->getError());",
"-",
"- return;",
"- }",
"-",
"- \/\/ Return updated content section",
"- $this->renderVersionPartial($result->toArray());",
"+ $this->renderVersionPartial($genResult->toArray());",
" }",
" ",
" \/**",
"- * POST \/content\/{id}\/critique",
"- * Run critique round (HTMX)",
"+ * POST \/content\/{id}\/critique - Run critique round (HTMX)",
" *\/",
" public function critique(int $id): void",
" {",
" $this->requireCsrf();",
" ",
"- \/\/ Get latest version",
" $version = $this->repository->findLatestVersion($id);",
"-",
" if ($version === null) {",
" $this->htmxError('Keine Version vorhanden.');",
"-",
" return;",
" }",
" ",
"- $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';",
"- $result = $this->generateUseCase->critique($version['id'], $model);",
"-",
"+ $result = $this->generateUseCase->critique($version['id'], $_POST['model'] ?? 'claude-opus-4-5-20251101');",
" if ($result->hasError()) {",
" $this->htmxError('Fehler: ' . $result->getError());",
"-",
" return;",
" }",
" ",
"- \/\/ Return critique results",
" $this->renderCritiquePartial($result->toArray());",
" }",
" ",
" \/**",
"- * POST \/content\/{id}\/revise",
"- * Create revision (HTMX)",
"+ * POST \/content\/{id}\/revise - Create revision (HTMX)",
" *\/",
" public function revise(int $id): void",
" {",
" $this->requireCsrf();",
" ",
" $version = $this->repository->findLatestVersion($id);",
"-",
" if ($version === null) {",
" $this->htmxError('Keine Version vorhanden.');",
"-",
" return;",
" }",
" ",
"- $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';",
"- $result = $this->generateUseCase->revise($version['id'], $model);",
"-",
"+ $result = $this->generateUseCase->revise($version['id'], $_POST['model'] ?? 'claude-opus-4-5-20251101');",
" if ($result->hasError()) {",
" $this->htmxError('Fehler: ' . $result->getError());",
"-",
" return;",
" }",
" "
]
},
{
"oldStart": 294,
"oldLines": 34,
"newStart": 231,
"newLines": 33,
"lines": [
" }",
" ",
" \/**",
"- * POST \/content\/{id}\/approve",
"- * Approve content",
"+ * POST \/content\/{id}\/approve - Approve content",
" *\/",
" public function approve(int $id): void",
" {",
" $this->requireCsrf();",
"-",
" $this->repository->updateOrderStatus($id, 'approve');",
" $this->htmxSuccess('Content genehmigt!');",
" echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';",
" }",
" ",
" \/**",
"- * POST \/content\/{id}\/decline",
"- * Decline content",
"+ * POST \/content\/{id}\/decline - Decline content",
" *\/",
" public function decline(int $id): void",
" {",
" $this->requireCsrf();",
"-",
" $this->repository->updateOrderStatus($id, 'draft');",
" $this->htmxAlert('warning', 'Content abgelehnt. Zurück zu Entwurf.');",
" echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';",
" }",
" ",
"- \/**",
"- * Render version partial",
"- *\/",
"+ private function getFirstContractId(): ?int",
"+ {",
"+ $contracts = $this->repository->findAllContracts();",
"+ return $contracts !== [] ? (int) $contracts[0]['id'] : null;",
"+ }",
"+",
" private function renderVersionPartial(array $result): void",
" {",
" $this->view('content.partials.version', ["
]
},
{
"oldStart": 331,
"oldLines": 9,
"newStart": 267,
"newLines": 6,
"lines": [
" ]);",
" }",
" ",
"- \/**",
"- * Render critique partial",
"- *\/",
" private function renderCritiquePartial(array $result): void",
" {",
" $this->view('content.partials.critique', ["
]
},
{
"oldStart": 342,
"oldLines": 56,
"newStart": 275,
"newLines": 4,
"lines": [
" 'round' => $result['round'] ?? '?',",
" ]);",
" }",
"-",
"- \/**",
"- * Get available collections from database",
"- *",
"- * @return array<int, array<string,mixed>>",
"- *\/",
"- private function getAvailableCollections(): array",
"- {",
"- $collections = $this->collectionRepository->getSearchable();",
"-",
"- if ($collections === []) {",
"- return [",
"- ['collection_id' => 'documents', 'display_name' => 'Dokumente', 'points_count' => 0, 'vector_size' => 1024],",
"- ];",
"- }",
"-",
"- return $collections;",
"- }",
"-",
"- \/**",
"- * Validate collections against available ones",
"- *",
"- * @param array<string> $collections",
"- * @return array<string>",
"- *\/",
"- private function validateCollections(array $collections): array",
"- {",
"- $availableIds = array_column($this->getAvailableCollections(), 'collection_id');",
"- $valid = array_filter($collections, fn ($c) => in_array($c, $availableIds, true));",
"-",
"- return array_values($valid);",
"- }",
"-",
"- \/**",
"- * Validate collection compatibility (vector dimensions)",
"- *",
"- * @param array<string> $collectionIds",
"- * @return array{valid: bool, error: string|null}",
"- *\/",
"- private function validateCollectionCompatibility(array $collectionIds): array",
"- {",
"- if (empty($collectionIds)) {",
"- return ['valid' => true, 'error' => null];",
"- }",
"-",
"- $result = $this->collectionValidator->validateSelection($collectionIds);",
"-",
"- return [",
"- 'valid' => $result->isValid(),",
"- 'error' => $result->getError(),",
"- ];",
"- }",
" }"
]
}
],
"originalFile": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Persistence\\CollectionRepository;\nuse Infrastructure\\Persistence\\ContentRepository;\nuse Infrastructure\\Validation\\CollectionValidator;\nuse UseCases\\Command\\CreateContentOrderCommand;\nuse UseCases\\Command\\GenerateContentCommand;\nuse UseCases\\Content\\GenerateContentUseCase;\n\nclass ContentController extends Controller\n{\n private ContentRepository $repository;\n private CollectionRepository $collectionRepository;\n private CollectionValidator $collectionValidator;\n private GenerateContentUseCase $generateUseCase;\n\n public function __construct()\n {\n $this->repository = new ContentRepository();\n $this->collectionRepository = new CollectionRepository();\n $this->collectionValidator = new CollectionValidator($this->collectionRepository);\n $this->generateUseCase = new GenerateContentUseCase();\n }\n\n \/**\n * GET \/content\n * List all content orders\n *\/\n public function index(): void\n {\n $filters = [];\n $status = $this->getString('status');\n if ($status !== '') {\n $filters['status'] = $status;\n }\n\n $orders = $this->repository->findAllOrders($filters);\n $stats = $this->repository->getStatistics();\n\n $this->view('content.index', [\n 'title' => 'Content Studio',\n 'orders' => $orders,\n 'stats' => $stats,\n 'currentStatus' => $status,\n ]);\n }\n\n \/**\n * GET \/content\/new\n * Show create form\n *\/\n public function contentNew(): void\n {\n $collections = $this->getAvailableCollections();\n $lastSettings = $this->repository->getLastOrderSettings();\n\n $this->view('content.new', [\n 'title' => 'Neuer Content-Auftrag',\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n 'models' => ModelConfig::getAll(),\n 'collections' => $collections,\n \/\/ Defaults from last order\n 'defaultModel' => $lastSettings['model'],\n 'defaultCollections' => $lastSettings['collections'],\n 'defaultContextLimit' => $lastSettings['context_limit'],\n 'defaultProfileId' => $lastSettings['author_profile_id'],\n 'defaultContractId' => $lastSettings['contract_id'],\n 'defaultStructureId' => $lastSettings['structure_id'],\n ]);\n }\n\n \/**\n * POST \/content\n * Store new order\n *\/\n public function store(): void\n {\n $this->requireCsrf();\n\n $command = CreateContentOrderCommand::fromRequest($_POST);\n $errors = $command->validate();\n\n if ($errors !== []) {\n $_SESSION['error'] = implode(' ', $errors);\n $this->redirect('\/content\/new');\n }\n\n \/\/ Auto-apply first active contract if none selected\n $contractId = $command->contractId;\n if ($contractId === null) {\n $contracts = $this->repository->findAllContracts();\n if ($contracts !== []) {\n $contractId = (int) $contracts[0]['id'];\n }\n }\n\n \/\/ Validate collection compatibility\n $collections = $this->validateCollections($command->collections);\n $compatibility = $this->validateCollectionCompatibility($collections);\n if (!$compatibility['valid']) {\n $_SESSION['error'] = 'Collection-Fehler: ' . $compatibility['error'];\n $this->redirect('\/content\/new');\n }\n\n $model = ModelConfig::validate($command->model);\n\n $orderId = $this->repository->createOrder([\n 'title' => $command->title,\n 'briefing' => $command->briefing,\n 'author_profile_id' => $command->authorProfileId,\n 'contract_id' => $contractId,\n 'structure_id' => $command->structureId,\n 'model' => $model,\n 'collections' => json_encode($collections),\n 'context_limit' => $command->contextLimit,\n ]);\n\n \/\/ If \"generate\" action: generate content immediately\n if ($command->shouldGenerate()) {\n $collection = $collections[0] ?? 'documents';\n $result = $this->generateUseCase->generate($orderId, $model, $collection, $command->contextLimit);\n\n if ($result->hasError()) {\n $_SESSION['error'] = 'Generierung fehlgeschlagen: ' . $result->getError();\n } else {\n $_SESSION['success'] = 'Content wurde generiert.';\n }\n }\n\n $this->redirect('\/content\/' . $orderId);\n }\n\n \/**\n * GET \/content\/{id}\n * Show order details\n *\/\n public function show(int $id): void\n {\n $order = $this->repository->findOrder($id);\n\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $versions = $this->repository->findVersionsByOrder($id);\n $latestVersion = $versions[0] ?? null;\n $critiques = $latestVersion ? $this->repository->findCritiquesByVersion($latestVersion['id']) : [];\n $sources = $this->repository->findSourcesByOrder($id);\n\n \/\/ Get available collections for the dropdown\n $availableCollections = $this->getAvailableCollections();\n\n $this->view('content.show', [\n 'title' => $order['title'],\n 'order' => $order,\n 'versions' => $versions,\n 'latestVersion' => $latestVersion,\n 'critiques' => $critiques,\n 'sources' => $sources,\n 'models' => ModelConfig::getAll(),\n 'availableCollections' => $availableCollections,\n ]);\n }\n\n \/**\n * GET \/content\/{id}\/edit\n * Show edit form\n *\/\n public function edit(int $id): void\n {\n $order = $this->repository->findOrder($id);\n\n if ($order === null) {\n $this->notFound('Auftrag nicht gefunden');\n }\n\n $this->view('content.edit', [\n 'title' => 'Auftrag bearbeiten',\n 'order' => $order,\n 'profiles' => $this->repository->findAllProfiles(),\n 'contracts' => $this->repository->findAllContracts(),\n 'structures' => $this->repository->findAllStructures(),\n ]);\n }\n\n \/**\n * POST \/content\/{id}\/generate\n * Generate content (HTMX)\n *\/\n public function generate(int $id): void\n {\n $this->requireCsrf();\n\n $command = GenerateContentCommand::fromRequest($id, $_POST);\n $errors = $command->validate();\n\n if ($errors !== []) {\n $this->htmxError(implode(' ', $errors));\n\n return;\n }\n\n \/\/ Validate collection\n $collections = $this->validateCollections([$command->collection]);\n if (empty($collections)) {\n $this->htmxError('Ungültige Collection: ' . $command->collection);\n\n return;\n }\n $collection = $collections[0];\n\n \/\/ Validate compatibility (single collection always valid, but check exists)\n $compatibility = $this->validateCollectionCompatibility($collections);\n if (!$compatibility['valid']) {\n $this->htmxError($compatibility['error'] ?? 'Collection-Fehler');\n\n return;\n }\n\n $result = $this->generateUseCase->generate($id, $command->model, $collection, $command->contextLimit);\n\n if ($result->hasError()) {\n $this->htmxError('Fehler: ' . $result->getError());\n\n return;\n }\n\n \/\/ Return updated content section\n $this->renderVersionPartial($result->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/critique\n * Run critique round (HTMX)\n *\/\n public function critique(int $id): void\n {\n $this->requireCsrf();\n\n \/\/ Get latest version\n $version = $this->repository->findLatestVersion($id);\n\n if ($version === null) {\n $this->htmxError('Keine Version vorhanden.');\n\n return;\n }\n\n $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n $result = $this->generateUseCase->critique($version['id'], $model);\n\n if ($result->hasError()) {\n $this->htmxError('Fehler: ' . $result->getError());\n\n return;\n }\n\n \/\/ Return critique results\n $this->renderCritiquePartial($result->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/revise\n * Create revision (HTMX)\n *\/\n public function revise(int $id): void\n {\n $this->requireCsrf();\n\n $version = $this->repository->findLatestVersion($id);\n\n if ($version === null) {\n $this->htmxError('Keine Version vorhanden.');\n\n return;\n }\n\n $model = $_POST['model'] ?? 'claude-opus-4-5-20251101';\n $result = $this->generateUseCase->revise($version['id'], $model);\n\n if ($result->hasError()) {\n $this->htmxError('Fehler: ' . $result->getError());\n\n return;\n }\n\n $this->renderVersionPartial($result->toArray());\n }\n\n \/**\n * POST \/content\/{id}\/approve\n * Approve content\n *\/\n public function approve(int $id): void\n {\n $this->requireCsrf();\n\n $this->repository->updateOrderStatus($id, 'approve');\n $this->htmxSuccess('Content genehmigt!');\n echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n }\n\n \/**\n * POST \/content\/{id}\/decline\n * Decline content\n *\/\n public function decline(int $id): void\n {\n $this->requireCsrf();\n\n $this->repository->updateOrderStatus($id, 'draft');\n $this->htmxAlert('warning', 'Content abgelehnt. Zurück zu Entwurf.');\n echo '<script>setTimeout(() => window.location.reload(), 1000);<\/script>';\n }\n\n \/**\n * Render version partial\n *\/\n private function renderVersionP... [TRUNCATED-5278a8668f7433bb]"
}
}