feat: CI/CD pipeline setup complete - Ansible playbooks updated, secrets configured, workflow ready
This commit is contained in:
@@ -64,10 +64,14 @@ final readonly class AppBootstrapper
|
||||
// Register MemoryMonitor as singleton
|
||||
$this->container->singleton(MemoryMonitor::class, $this->memoryMonitor);
|
||||
|
||||
// Only log context in development - production doesn't need this noise
|
||||
$envType = EnvironmentType::fromEnvironment($env);
|
||||
|
||||
if ($envType->isDevelopment()) {
|
||||
|
||||
// Only log context in development - production doesn't need this noise
|
||||
//$envType = EnvironmentType::fromEnvironment($env);
|
||||
|
||||
//if ($envType->isDevelopment()) {
|
||||
|
||||
if($typedConfig->app->type->isDevelopment()) {
|
||||
// Fehleranzeige für die Entwicklung aktivieren
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
@@ -83,14 +87,6 @@ final readonly class AppBootstrapper
|
||||
|
||||
return false;
|
||||
}, true, true);
|
||||
|
||||
|
||||
register_shutdown_function(function () {
|
||||
$error = error_get_last();
|
||||
if ($error !== null) {
|
||||
echo 'SHUTDOWN ERROR: ' . print_r($error, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +119,9 @@ final readonly class AppBootstrapper
|
||||
$this->bootstrap();
|
||||
$this->registerCliErrorHandler();
|
||||
|
||||
$ed = $this->container->get(EventDispatcher::class);
|
||||
$this->container->instance(EventDispatcherInterface::class, $ed);
|
||||
|
||||
$consoleOutput = new ConsoleOutput();
|
||||
$this->container->instance(ConsoleOutput::class, $consoleOutput);
|
||||
|
||||
@@ -195,33 +194,19 @@ final readonly class AppBootstrapper
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize environment with encryption support
|
||||
* Initialize environment with smart priority handling
|
||||
*
|
||||
* Uses EnvironmentLoader which orchestrates:
|
||||
* - Docker ENV vars loading (via $_ENV, $_SERVER)
|
||||
* - .env file loading
|
||||
* - Smart priority (Production: Docker ENV > .env, Development: .env > Docker ENV)
|
||||
* - Automatic encryption support for .env.secrets
|
||||
*/
|
||||
private function initializeEnvironment(): Environment
|
||||
{
|
||||
// First, try to load basic environment to get encryption key
|
||||
$basicEnv = Environment::fromFile($this->basePath . '/.env');
|
||||
$encryptionKey = $basicEnv->get('ENCRYPTION_KEY');
|
||||
$loader = new EncryptedEnvLoader();
|
||||
|
||||
// If we have an encryption key, use the encrypted loader
|
||||
if ($encryptionKey !== null) {
|
||||
try {
|
||||
// These dependencies will be resolved later through the container
|
||||
$randomGenerator = $this->container->get(RandomGenerator::class);
|
||||
$encryptionFactory = new EncryptionFactory($randomGenerator);
|
||||
$encryptedLoader = new EncryptedEnvLoader($encryptionFactory, $randomGenerator);
|
||||
|
||||
return $encryptedLoader->loadEnvironment($this->basePath, $encryptionKey);
|
||||
} catch (\Throwable $e) {
|
||||
// Fallback to basic environment if encryption fails
|
||||
error_log("Failed to load encrypted environment: " . $e->getMessage());
|
||||
|
||||
return $basicEnv;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to basic environment loading
|
||||
return $basicEnv;
|
||||
return $loader->load($this->basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -213,9 +213,23 @@ final readonly class ContainerBootstrapper
|
||||
private function autowire(Container $container): void
|
||||
{
|
||||
// Discovery service bootstrapping
|
||||
error_log("🔧 CONTAINER BOOTSTRAP: autowire() starting Discovery");
|
||||
$clock = $container->get(Clock::class);
|
||||
$bootstrapper = new DiscoveryServiceBootstrapper($container, $clock);
|
||||
|
||||
// Create a simple logger for Discovery phase
|
||||
// In MCP mode, use NullHandler to suppress output
|
||||
$isMcpMode = getenv('MCP_SERVER_MODE') === '1';
|
||||
$handlers = $isMcpMode
|
||||
? [new \App\Framework\Logging\Handlers\NullHandler()]
|
||||
: [new \App\Framework\Logging\Handlers\ConsoleHandler()];
|
||||
|
||||
$logger = new \App\Framework\Logging\DefaultLogger(
|
||||
minLevel: \App\Framework\Logging\LogLevel::DEBUG,
|
||||
handlers: $handlers,
|
||||
processorManager: new \App\Framework\Logging\ProcessorManager(),
|
||||
contextManager: new \App\Framework\Logging\LogContextManager()
|
||||
);
|
||||
|
||||
$bootstrapper = new DiscoveryServiceBootstrapper($container, $clock, $logger);
|
||||
$results = $bootstrapper->bootstrap();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Core\Events;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Version;
|
||||
|
||||
final readonly class ApplicationBooted
|
||||
{
|
||||
public function __construct(
|
||||
public \DateTimeImmutable $bootTime,
|
||||
public string $environment,
|
||||
public string $version = 'dev',
|
||||
public Version $version,
|
||||
public \DateTimeImmutable $occurredAt = new \DateTimeImmutable()
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -3,7 +3,37 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Core\Helper;
|
||||
|
||||
final class Str
|
||||
{
|
||||
use Stringable;
|
||||
|
||||
final readonly class Str
|
||||
{
|
||||
public static function len(Stringable|string $value): int
|
||||
{
|
||||
#grapheme_strlen($value);
|
||||
return mb_strlen((string)$value);
|
||||
}
|
||||
|
||||
public static function empty(Stringable|string $value): bool
|
||||
{
|
||||
return self::len($value) === 0;
|
||||
}
|
||||
|
||||
public static function slice(Stringable|string $value, int $start, ?int $length = null): string
|
||||
{
|
||||
return grapheme_substr((string)$value, $start, $length);
|
||||
}
|
||||
|
||||
public static function trim(Stringable|string $value): string
|
||||
{
|
||||
return mb_trim((string)$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* ltrim
|
||||
* rtrim
|
||||
* ucfirst
|
||||
* lcfirst
|
||||
* upper
|
||||
* lower
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Core\ValueObjects;
|
||||
|
||||
use App\Framework\Core\Helper\Str;
|
||||
|
||||
/**
|
||||
* Idempotency Key Value Object
|
||||
*
|
||||
@@ -32,8 +34,8 @@ namespace App\Framework\Core\ValueObjects;
|
||||
*/
|
||||
final readonly class IdempotencyKey
|
||||
{
|
||||
private const MIN_LENGTH = 16;
|
||||
private const MAX_LENGTH = 255;
|
||||
private const int MIN_LENGTH = 16;
|
||||
private const int MAX_LENGTH = 255;
|
||||
|
||||
private function __construct(
|
||||
public string $value
|
||||
@@ -127,7 +129,7 @@ final readonly class IdempotencyKey
|
||||
*/
|
||||
public function toMasked(): string
|
||||
{
|
||||
$length = strlen($this->value);
|
||||
$length = Str::len($this->value);
|
||||
|
||||
if ($length <= 8) {
|
||||
return str_repeat('*', $length);
|
||||
@@ -144,7 +146,7 @@ final readonly class IdempotencyKey
|
||||
*/
|
||||
private function validate(): void
|
||||
{
|
||||
$length = strlen($this->value);
|
||||
$length = Str::len($this->value);
|
||||
|
||||
if ($length < self::MIN_LENGTH) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
||||
@@ -4,5 +4,11 @@ namespace App\Framework\Core\ValueObjects\PhoneNumber;
|
||||
|
||||
enum PhoneNumberFormat
|
||||
{
|
||||
case E164;
|
||||
|
||||
case INTERNATIONAL;
|
||||
|
||||
case NATIONAL;
|
||||
|
||||
case RFC3966;
|
||||
}
|
||||
|
||||
@@ -331,4 +331,4 @@ try {
|
||||
3. **Validation**: Use `Byte` objects for all size-related validation logic
|
||||
4. **Logging**: Use `toHumanReadable()` for user-friendly log messages
|
||||
5. **APIs**: Accept string formats and parse them into `Byte` objects
|
||||
6. **Performance**: Create `Byte` objects lazily when needed, store raw bytes when possible
|
||||
6. **Performance**: Create `Byte` objects lazily when needed, store raw bytes when possible
|
||||
|
||||
Reference in New Issue
Block a user