- 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.
181 lines
5.0 KiB
PHP
181 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Domain\PreSave;
|
|
|
|
use App\Domain\PreSave\ValueObjects\RegistrationStatus;
|
|
use App\Domain\PreSave\ValueObjects\StreamingPlatform;
|
|
use App\Framework\Core\ValueObjects\Timestamp;
|
|
|
|
/**
|
|
* Pre-Save Registration Entity
|
|
*
|
|
* Represents a user's registration for a pre-save campaign
|
|
*/
|
|
final readonly class PreSaveRegistration
|
|
{
|
|
public function __construct(
|
|
public ?int $id,
|
|
public int $campaignId,
|
|
public string $userId,
|
|
public StreamingPlatform $platform,
|
|
public RegistrationStatus $status,
|
|
public Timestamp $registeredAt,
|
|
public ?Timestamp $processedAt = null,
|
|
public ?string $errorMessage = null,
|
|
public int $retryCount = 0,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Create new registration
|
|
*/
|
|
public static function create(
|
|
int $campaignId,
|
|
string $userId,
|
|
StreamingPlatform $platform,
|
|
): self {
|
|
return new self(
|
|
id: null,
|
|
campaignId: $campaignId,
|
|
userId: $userId,
|
|
platform: $platform,
|
|
status: RegistrationStatus::PENDING,
|
|
registeredAt: Timestamp::now(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Mark as completed
|
|
*/
|
|
public function markAsCompleted(): self
|
|
{
|
|
return new self(
|
|
id: $this->id,
|
|
campaignId: $this->campaignId,
|
|
userId: $this->userId,
|
|
platform: $this->platform,
|
|
status: RegistrationStatus::COMPLETED,
|
|
registeredAt: $this->registeredAt,
|
|
processedAt: Timestamp::now(),
|
|
errorMessage: null,
|
|
retryCount: $this->retryCount,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Mark as failed with error message
|
|
*/
|
|
public function markAsFailed(string $errorMessage): self
|
|
{
|
|
return new self(
|
|
id: $this->id,
|
|
campaignId: $this->campaignId,
|
|
userId: $this->userId,
|
|
platform: $this->platform,
|
|
status: RegistrationStatus::FAILED,
|
|
registeredAt: $this->registeredAt,
|
|
processedAt: Timestamp::now(),
|
|
errorMessage: $errorMessage,
|
|
retryCount: $this->retryCount + 1,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Mark as revoked (user disconnected OAuth)
|
|
*/
|
|
public function markAsRevoked(): self
|
|
{
|
|
return new self(
|
|
id: $this->id,
|
|
campaignId: $this->campaignId,
|
|
userId: $this->userId,
|
|
platform: $this->platform,
|
|
status: RegistrationStatus::REVOKED,
|
|
registeredAt: $this->registeredAt,
|
|
processedAt: Timestamp::now(),
|
|
errorMessage: 'OAuth token revoked by user',
|
|
retryCount: $this->retryCount,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reset for retry
|
|
*/
|
|
public function resetForRetry(): self
|
|
{
|
|
if (! $this->status->canRetry()) {
|
|
throw new \RuntimeException('Cannot retry registration in status: ' . $this->status->value);
|
|
}
|
|
|
|
return new self(
|
|
id: $this->id,
|
|
campaignId: $this->campaignId,
|
|
userId: $this->userId,
|
|
platform: $this->platform,
|
|
status: RegistrationStatus::PENDING,
|
|
registeredAt: $this->registeredAt,
|
|
processedAt: null,
|
|
errorMessage: null,
|
|
retryCount: $this->retryCount,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if should be processed
|
|
*/
|
|
public function shouldProcess(): bool
|
|
{
|
|
return $this->status->shouldProcess();
|
|
}
|
|
|
|
/**
|
|
* Check if max retries exceeded
|
|
*/
|
|
public function hasExceededMaxRetries(int $maxRetries = 3): bool
|
|
{
|
|
return $this->retryCount >= $maxRetries;
|
|
}
|
|
|
|
/**
|
|
* Convert to array for storage/API
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'id' => $this->id,
|
|
'campaign_id' => $this->campaignId,
|
|
'user_id' => $this->userId,
|
|
'platform' => $this->platform->value,
|
|
'status' => $this->status->value,
|
|
'registered_at' => $this->registeredAt->toTimestamp(),
|
|
'processed_at' => $this->processedAt?->toTimestamp(),
|
|
'error_message' => $this->errorMessage,
|
|
'retry_count' => $this->retryCount,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Create from database row
|
|
*
|
|
* @param array<string, mixed> $row
|
|
*/
|
|
public static function fromArray(array $row): self
|
|
{
|
|
return new self(
|
|
id: isset($row['id']) ? (int) $row['id'] : null,
|
|
campaignId: (int) $row['campaign_id'],
|
|
userId: (string) $row['user_id'],
|
|
platform: StreamingPlatform::from($row['platform']),
|
|
status: RegistrationStatus::from($row['status']),
|
|
registeredAt: Timestamp::fromFloat((float) $row['registered_at']),
|
|
processedAt: isset($row['processed_at']) ? Timestamp::fromFloat((float) $row['processed_at']) : null,
|
|
errorMessage: $row['error_message'] ?? null,
|
|
retryCount: (int) ($row['retry_count'] ?? 0),
|
|
);
|
|
}
|
|
}
|