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

@@ -0,0 +1,202 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheIdentifier;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheItem;
use App\Framework\Cache\CacheResult;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\DateTime\SystemClock;
use App\Framework\ErrorAggregation\ErrorAggregator;
use App\Framework\ErrorAggregation\Storage\InMemoryErrorStorage;
use App\Framework\ErrorHandling\ErrorHandler;
use App\Framework\ErrorReporting\ErrorReporter;
use App\Framework\ErrorReporting\Storage\InMemoryErrorReportStorage;
use App\Framework\Exception\Core\DatabaseErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\Http\RequestIdGenerator;
use App\Framework\Http\ResponseEmitter;
use App\Framework\DI\DefaultContainer;
use App\Framework\Queue\InMemoryQueue;
// Create all dependencies
$container = new DefaultContainer();
$emitter = new ResponseEmitter();
$requestIdGenerator = new RequestIdGenerator();
// Error Aggregation setup
$errorStorage = new InMemoryErrorStorage();
$cache = new class implements Cache {
private array $data = [];
public function get(CacheIdentifier ...$identifiers): CacheResult
{
$items = [];
foreach ($identifiers as $identifier) {
$keyStr = $identifier->toString();
if (isset($this->data[$keyStr])) {
$items[] = $this->data[$identifier->toString()];
} else {
$items[] = CacheItem::miss($identifier instanceof CacheKey ? $identifier : CacheKey::fromString($identifier->toString()));
}
}
return count($items) === 1
? CacheResult::single($items[0])
: CacheResult::multiple($items);
}
public function set(CacheItem ...$items): bool
{
foreach ($items as $item) {
$this->data[$item->key->toString()] = $item;
}
return true;
}
public function has(CacheIdentifier ...$identifiers): array
{
$result = [];
foreach ($identifiers as $identifier) {
$result[] = isset($this->data[$identifier->toString()]);
}
return $result;
}
public function forget(CacheIdentifier ...$identifiers): bool
{
foreach ($identifiers as $identifier) {
unset($this->data[$identifier->toString()]);
}
return true;
}
public function clear(): bool
{
$this->data = [];
return true;
}
public function remember(CacheKey $key, callable $callback, ?Duration $ttl = null): CacheItem
{
$keyStr = $key->toString();
if (isset($this->data[$keyStr])) {
return $this->data[$keyStr];
}
$value = $callback();
$item = $ttl ? CacheItem::forSetting($key, $value, $ttl) : CacheItem::miss($key);
$this->data[$keyStr] = $item;
return $item;
}
};
$clock = new SystemClock();
$alertQueue = new InMemoryQueue();
$errorAggregator = new ErrorAggregator(
storage: $errorStorage,
cache: $cache,
clock: $clock,
alertQueue: $alertQueue,
logger: null,
batchSize: 100,
maxRetentionDays: 90
);
// Error Reporting setup
$errorReportStorage = new InMemoryErrorReportStorage();
$reportQueue = new InMemoryQueue();
$errorReporter = new ErrorReporter(
storage: $errorReportStorage,
clock: $clock,
logger: null,
queue: $reportQueue,
asyncProcessing: false,
processors: [],
filters: []
);
// Create ErrorHandler
$errorHandler = new ErrorHandler(
emitter: $emitter,
container: $container,
requestIdGenerator: $requestIdGenerator,
errorAggregator: $errorAggregator,
errorReporter: $errorReporter,
logger: null,
isDebugMode: true,
securityHandler: null
);
echo "=== Testing Error Pipeline ===\n\n";
// Create test exception
$exception = FrameworkException::create(
DatabaseErrorCode::QUERY_FAILED,
'Test database error'
);
echo "1. Creating ErrorHandlerContext manually...\n";
$errorHandlerContext = (new \ReflectionClass($errorHandler))->getMethod('createErrorHandlerContext')->invoke($errorHandler, $exception, null);
echo " Context created successfully\n";
echo " ExceptionContext: operation={$errorHandlerContext->exception->operation}, component={$errorHandlerContext->exception->component}\n";
echo "\n2. Testing ErrorEvent::fromErrorHandlerContext...\n";
try {
$errorEvent = \App\Framework\ErrorAggregation\ErrorEvent::fromErrorHandlerContext($errorHandlerContext, $clock);
echo " ErrorEvent created successfully\n";
echo " Event ID: {$errorEvent->id}\n";
echo " Event message: {$errorEvent->errorMessage}\n";
} catch (\Throwable $e) {
echo " EXCEPTION in fromErrorHandlerContext: " . $e->getMessage() . "\n";
echo " AT: " . $e->getFile() . ":" . $e->getLine() . "\n";
echo " TRACE:\n";
foreach ($e->getTrace() as $frame) {
$file = $frame['file'] ?? 'unknown';
$line = $frame['line'] ?? 0;
$function = $frame['function'] ?? 'unknown';
echo " $file:$line - $function()\n";
}
exit(1);
}
echo "\n3. Testing ErrorAggregator.processError directly...\n";
try {
$errorAggregator->processError($errorHandlerContext);
echo " processError completed successfully\n";
} catch (\Throwable $e) {
echo " EXCEPTION in processError: " . $e->getMessage() . "\n";
echo " AT: " . $e->getFile() . ":" . $e->getLine() . "\n";
throw $e;
}
echo "\n3. Creating HTTP response from exception...\n";
$response = $errorHandler->createHttpResponse($exception);
echo "\n4. Checking ErrorAggregator storage...\n";
$events = $errorStorage->getRecentEvents(10);
echo " Events stored: " . count($events) . "\n";
if (count($events) > 0) {
echo " First event message: " . $events[0]->message . "\n";
echo " First event severity: " . $events[0]->severity->value . "\n";
} else {
echo " No events stored!\n";
}
echo "\n3. Checking ErrorReporter storage...\n";
$reports = $errorReportStorage->findRecent(10);
echo " Reports stored: " . count($reports) . "\n";
if (count($reports) > 0) {
echo " First report message: " . $reports[0]->message . "\n";
echo " First report exception: " . $reports[0]->exception . "\n";
echo " First report level: " . $reports[0]->level . "\n";
} else {
echo " No reports stored!\n";
}
echo "\n=== Test Complete ===\n";