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

@@ -4,28 +4,28 @@ declare(strict_types=1);
namespace App\Framework\Filesystem;
use App\Framework\Core\PathProvider;
use App\Framework\Filesystem\ValueObjects\FilePermissions;
/**
* Helper-Klasse für Filesystem-Permissions-Checks
*/
final readonly class PermissionChecker
{
public function __construct(
private Storage $storage
private PathProvider $pathProvider
) {
}
private function resolvePath(string $path): string
{
// Use reflection to access resolvePath from FileStorage
// or implement basic path resolution logic
if (method_exists($this->storage, 'resolvePath')) {
$reflection = new \ReflectionMethod($this->storage, 'resolvePath');
return $reflection->invoke($this->storage, $path);
// Absolute paths bleiben unverändert
if (str_starts_with($path, '/')) {
return $path;
}
// Fallback: return path as-is if storage doesn't have resolvePath
return $path;
// Relative paths über PathProvider auflösen (mit Caching)
return $this->pathProvider->resolvePath($path);
}
public function isDirectoryWritable(string $path): bool
@@ -156,7 +156,55 @@ final readonly class PermissionChecker
'owner' => file_exists($resolvedPath) ? posix_getpwuid(fileowner($resolvedPath))['name'] ?? 'unknown' : null,
'group' => file_exists($resolvedPath) ? posix_getgrgid(filegroup($resolvedPath))['name'] ?? 'unknown' : null,
'parent_dir' => dirname($resolvedPath),
'parent_writable' => is_dir(dirname($resolvedPath)) ? is_writable(dirname($resolvedPath)) : false,
'parent_writable' => is_dir(dirname($resolvedPath)) && is_writable(dirname($resolvedPath)),
];
}
/**
* Get current file permissions as FilePermissions value object
*/
public function getPermissions(string $path): ?FilePermissions
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return null;
}
$perms = fileperms($resolvedPath);
// Extract only permission bits (last 9 bits)
$mode = $perms & 0777;
return new FilePermissions($mode);
}
/**
* Set file permissions using FilePermissions value object
*/
public function setPermissions(string $path, FilePermissions $permissions): bool
{
$resolvedPath = $this->resolvePath($path);
if (! file_exists($resolvedPath)) {
return false;
}
return @chmod($resolvedPath, $permissions->mode);
}
/**
* Ensure file has specific permissions, set them if different
*/
public function ensurePermissions(string $path, FilePermissions $permissions): bool
{
$current = $this->getPermissions($path);
if ($current === null) {
return false; // File doesn't exist
}
if ($current->equals($permissions)) {
return true; // Already has correct permissions
}
return $this->setPermissions($path, $permissions);
}
}