feat: CI/CD pipeline setup complete - Ansible playbooks updated, secrets configured, workflow ready

This commit is contained in:
2025-10-31 01:39:24 +01:00
parent 55c04e4fd0
commit e26eb2aa12
601 changed files with 44184 additions and 32477 deletions

View File

@@ -0,0 +1,229 @@
<?php
declare(strict_types=1);
namespace App\Infrastructure\SmartLink\Repositories;
use App\Domain\SmartLink\Entities\ClickEvent;
use App\Domain\SmartLink\Repositories\ClickEventRepository;
use App\Domain\SmartLink\ValueObjects\SmartLinkId;
use App\Framework\Attributes\DefaultImplementation;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Database\ConnectionInterface;
use App\Framework\Database\ValueObjects\QueryParameters;
use App\Framework\Database\ValueObjects\SqlQuery;
#[DefaultImplementation]
final readonly class DatabaseClickEventRepository implements ClickEventRepository
{
public function __construct(
private ConnectionInterface $connection
) {
}
public function save(ClickEvent $event): void
{
// Implementation coming from existing code
$this->connection->insert('smartlink_click_events', [
'id' => $event->id->toString(),
'smartlink_id' => $event->smartLinkId->toString(),
'ip_hash' => $event->ipHash,
'user_agent' => $event->userAgent,
'referer' => $event->referer,
'country_code' => $event->countryCode,
'device_type' => $event->deviceType,
'is_conversion' => $event->isConversion ? 1 : 0,
'clicked_at' => $event->clickedAt->format('Y-m-d H:i:s'),
]);
}
public function findByLinkId(SmartLinkId $linkId, ?Timestamp $since = null): array
{
$query = 'SELECT * FROM smartlink_click_events WHERE smartlink_id = ?';
$params = [$linkId->toString()];
if ($since !== null) {
$query .= ' AND clicked_at >= ?';
$params[] = $since->format('Y-m-d H:i:s');
}
$query .= ' ORDER BY clicked_at DESC';
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
return $this->connection->query($sqlQuery)->fetchAll();
}
public function getRecentClicksByIpHash(string $ipHash, int $minutes = 60): array
{
$since = Timestamp::now()->subtractMinutes($minutes);
$sqlQuery = new SqlQuery(
'SELECT * FROM smartlink_click_events WHERE ip_hash = ? AND clicked_at >= ? ORDER BY clicked_at DESC',
new QueryParameters([$ipHash, $since->format('Y-m-d H:i:s')])
);
return $this->connection->query($sqlQuery)->fetchAll();
}
public function countByLinkId(SmartLinkId $linkId): int
{
$sqlQuery = new SqlQuery(
'SELECT COUNT(*) as count FROM smartlink_click_events WHERE smartlink_id = ?',
new QueryParameters([$linkId->toString()])
);
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
public function countUniqueByLinkId(SmartLinkId $linkId): int
{
$sqlQuery = new SqlQuery(
'SELECT COUNT(DISTINCT ip_hash) as count FROM smartlink_click_events WHERE smartlink_id = ?',
new QueryParameters([$linkId->toString()])
);
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
public function getConversionsByLinkId(SmartLinkId $linkId): int
{
$sqlQuery = new SqlQuery(
'SELECT COUNT(*) as count FROM smartlink_click_events WHERE smartlink_id = ? AND is_conversion = TRUE',
new QueryParameters([$linkId->toString()])
);
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
// Analytics Aggregation Methods
public function getClickTimeSeriesByHour(Timestamp $since): array
{
$sqlQuery = new SqlQuery(
"SELECT
DATE_FORMAT(clicked_at, '%Y-%m-%d %H:00:00') as hour,
COUNT(*) as clicks,
COUNT(DISTINCT ip_hash) as unique_clicks
FROM smartlink_click_events
WHERE clicked_at >= ?
GROUP BY DATE_FORMAT(clicked_at, '%Y-%m-%d %H:00:00')
ORDER BY hour ASC",
new QueryParameters([$since->format('Y-m-d H:i:s')])
);
return $this->connection->query($sqlQuery)->fetchAll();
}
public function getGeographicDistribution(?Timestamp $since = null): array
{
$query = "SELECT
country_code,
COUNT(*) as click_count
FROM smartlink_click_events
WHERE country_code IS NOT NULL";
$params = [];
if ($since !== null) {
$query .= " AND clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$query .= " GROUP BY country_code ORDER BY click_count DESC";
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
return $this->connection->query($sqlQuery)->fetchAll();
}
public function getDeviceTypeDistribution(?Timestamp $since = null): array
{
$query = "SELECT
device_type,
COUNT(*) as click_count
FROM smartlink_click_events
WHERE device_type IS NOT NULL";
$params = [];
if ($since !== null) {
$query .= " AND clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$query .= " GROUP BY device_type ORDER BY click_count DESC";
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
return $this->connection->query($sqlQuery)->fetchAll();
}
public function getTopLinksByClicks(int $limit, ?Timestamp $since = null): array
{
$query = "SELECT
smartlink_id as link_id,
COUNT(*) as click_count,
COUNT(DISTINCT ip_hash) as unique_click_count
FROM smartlink_click_events";
$params = [];
if ($since !== null) {
$query .= " WHERE clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$query .= " GROUP BY smartlink_id ORDER BY click_count DESC LIMIT ?";
$params[] = $limit;
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
return $this->connection->query($sqlQuery)->fetchAll();
}
public function countTotal(?Timestamp $since = null): int
{
$query = "SELECT COUNT(*) as count FROM smartlink_click_events";
$params = [];
if ($since !== null) {
$query .= " WHERE clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
public function countUniqueTotal(?Timestamp $since = null): int
{
$query = "SELECT COUNT(DISTINCT ip_hash) as count FROM smartlink_click_events";
$params = [];
if ($since !== null) {
$query .= " WHERE clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
public function countConversionsTotal(?Timestamp $since = null): int
{
$query = "SELECT COUNT(*) as count FROM smartlink_click_events WHERE is_conversion = TRUE";
$params = [];
if ($since !== null) {
$query .= " AND clicked_at >= ?";
$params[] = $since->format('Y-m-d H:i:s');
}
$sqlQuery = new SqlQuery($query, new QueryParameters($params));
$result = $this->connection->query($sqlQuery)->fetchAll();
return (int) ($result[0]['count'] ?? 0);
}
}