feat(Production): Complete production deployment infrastructure

- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
This commit is contained in:
2025-10-25 19:18:37 +02:00
parent caa85db796
commit fc3d7e6357
83016 changed files with 378904 additions and 20919 deletions

View File

@@ -9,7 +9,7 @@ use App\Framework\Console\Progress\ProgressMiddleware;
use App\Framework\DI\Container;
use App\Framework\Discovery\Results\DiscoveryRegistry;
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\Core\ConsoleErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\Logging\Logger;
use App\Framework\Logging\ValueObjects\LogContext;
@@ -53,7 +53,7 @@ final readonly class CommandRegistry
{
if (! isset($this->discoveredAttributes[$commandName])) {
throw FrameworkException::create(
ErrorCode::CON_COMMAND_NOT_FOUND,
ConsoleErrorCode::COMMAND_NOT_FOUND,
"No discovered attribute found for command '{$commandName}'"
)->withData(['command_name' => $commandName]);
}
@@ -100,7 +100,7 @@ final readonly class CommandRegistry
// Validate command structure
if (! is_object($instance) || ! method_exists($instance, $methodName)) {
throw FrameworkException::create(
ErrorCode::CON_INVALID_COMMAND_STRUCTURE,
ConsoleErrorCode::INVALID_COMMAND_STRUCTURE,
"Invalid command configuration for '{$commandName}'"
)->withData([
'command_name' => $commandName,
@@ -128,7 +128,7 @@ final readonly class CommandRegistry
} catch (Throwable $e) {
throw FrameworkException::create(
ErrorCode::CON_COMMAND_EXECUTION_FAILED,
ConsoleErrorCode::EXECUTION_FAILED,
"Failed to execute command '{$commandName}': {$e->getMessage()}"
)->withData([
'command_name' => $commandName,
@@ -259,23 +259,25 @@ final readonly class CommandRegistry
try {
// Create the actual command execution callback
$commandExecutor = function (ConsoleInput $input, ConsoleOutputInterface $progressAwareOutput) use ($instance, $method, $arguments) {
// Check if method uses the new reflection-based parameter style
if ($this->usesReflectionParameters($method)) {
// Performance tracking: Parameter resolution
$parameterStart = microtime(true);
$resolvedParams = $this->parameterResolver->resolveParameters($method, $arguments);
$parameterDuration = (microtime(true) - $parameterStart) * 1000;
// Performance tracking: Parameter resolution
$parameterStart = microtime(true);
if ($this->performanceCollector) {
$this->performanceCollector->recordParameterResolutionTime($method->getDeclaringClass()->getName(), $parameterDuration);
}
// Resolve parameters with framework injection support
$resolvedParams = $this->parameterResolver->resolveParameters(
$method,
$arguments,
$input, // Inject ConsoleInput
$progressAwareOutput // Inject ConsoleOutput
);
$result = $method->invokeArgs($instance, $resolvedParams);
} else {
// For legacy style, use the progress-aware output
$result = $method->invoke($instance, $input, $progressAwareOutput);
$parameterDuration = (microtime(true) - $parameterStart) * 1000;
if ($this->performanceCollector) {
$this->performanceCollector->recordParameterResolutionTime($method->getDeclaringClass()->getName(), $parameterDuration);
}
$result = $method->invokeArgs($instance, $resolvedParams);
return $this->normalizeCommandResult($result);
};
@@ -295,43 +297,6 @@ final readonly class CommandRegistry
}
}
/**
* Determine if method uses reflection-based parameters
*/
private function usesReflectionParameters(ReflectionMethod $method): bool
{
$parameters = $method->getParameters();
// If no parameters, use simple invocation (no ConsoleInput/Output needed)
if (empty($parameters)) {
return true;
}
// If first parameter is ConsoleInput, it's legacy style
$firstParam = $parameters[0];
$firstParamType = $firstParam->getType();
if ($firstParamType instanceof \ReflectionNamedType) {
$typeName = $firstParamType->getName();
if ($typeName === ConsoleInput::class || $typeName === ConsoleInputInterface::class) {
return false; // Legacy style
}
}
// If method has ConsoleInput or ConsoleOutput in parameters, it's legacy
foreach ($parameters as $param) {
$type = $param->getType();
if ($type instanceof \ReflectionNamedType) {
$typeName = $type->getName();
if (in_array($typeName, [ConsoleInput::class, ConsoleInputInterface::class, ConsoleOutputInterface::class], true)) {
return false;
}
}
}
// All other cases are considered reflection-based
return true;
}
/**
* Generate help for a specific command
@@ -345,14 +310,7 @@ final readonly class CommandRegistry
try {
$reflectionMethod = new ReflectionMethod($className, $methodName);
if ($this->usesReflectionParameters($reflectionMethod)) {
return $this->parameterResolver->generateMethodHelp($reflectionMethod, $commandName);
} else {
// Generate basic help for legacy commands
$command = $this->commandList->get($commandName);
return "Command: {$commandName}\nDescription: {$command->description}\n\nThis command uses legacy parameter style.";
}
return $this->parameterResolver->generateMethodHelp($reflectionMethod, $commandName);
} catch (ReflectionException $e) {
return "Command: {$commandName}\nError generating help: {$e->getMessage()}";