TenantAtlas/apps/platform/app/Services/Alerts/AlertDestinationLastTestResolver.php
ahmido ce0615a9c1 Spec 182: relocate Laravel platform to apps/platform (#213)
## Summary
- move the Laravel application into `apps/platform` and keep the repository root for orchestration, docs, and tooling
- update the local command model, Sail/Docker wiring, runtime paths, and ignore rules around the new platform location
- add relocation quickstart/contracts plus focused smoke coverage for bootstrap, command model, routes, and runtime behavior

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/PlatformRelocation`
- integrated browser smoke validated `/up`, `/`, `/admin`, `/admin/choose-workspace`, and tenant route semantics for `200`, `403`, and `404`

## Remaining Rollout Checks
- validate Dokploy build context and working-directory assumptions against the new `apps/platform` layout
- confirm web, queue, and scheduler processes all start from the expected working directory in staging/production
- verify no legacy volume mounts or asset-publish paths still point at the old root-level `public/` or `storage/` locations

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #213
2026-04-08 08:40:47 +00:00

72 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Alerts;
use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Support\Alerts\AlertDestinationLastTestStatus;
use App\Support\Alerts\AlertDestinationLastTestStatusEnum;
use Carbon\CarbonImmutable;
class AlertDestinationLastTestResolver
{
/**
* Resolve the derived "last test" status for a given destination.
*
* Uses the most recent `alert_deliveries` row with `event_type = 'alerts.test'`,
* ordered by `created_at` desc then `id` desc (deterministic tie-breaking).
*/
public function resolve(AlertDestination $destination): AlertDestinationLastTestStatus
{
$delivery = AlertDelivery::query()
->where('workspace_id', (int) $destination->workspace_id)
->where('alert_destination_id', (int) $destination->getKey())
->where('event_type', AlertDelivery::EVENT_TYPE_TEST)
->orderByDesc('created_at')
->orderByDesc('id')
->first();
if ($delivery === null) {
return AlertDestinationLastTestStatus::never();
}
$status = $this->mapStatus((string) $delivery->status);
$timestamp = $this->mapTimestamp($delivery, $status);
return new AlertDestinationLastTestStatus(
status: $status,
timestamp: $timestamp,
deliveryId: (int) $delivery->getKey(),
);
}
private function mapStatus(string $deliveryStatus): AlertDestinationLastTestStatusEnum
{
return match ($deliveryStatus) {
AlertDelivery::STATUS_SENT => AlertDestinationLastTestStatusEnum::Sent,
AlertDelivery::STATUS_FAILED => AlertDestinationLastTestStatusEnum::Failed,
AlertDelivery::STATUS_QUEUED,
AlertDelivery::STATUS_DEFERRED => AlertDestinationLastTestStatusEnum::Pending,
default => AlertDestinationLastTestStatusEnum::Failed,
};
}
private function mapTimestamp(AlertDelivery $delivery, AlertDestinationLastTestStatusEnum $status): ?CarbonImmutable
{
return match ($status) {
AlertDestinationLastTestStatusEnum::Sent => $delivery->sent_at
? CarbonImmutable::instance($delivery->sent_at)
: null,
AlertDestinationLastTestStatusEnum::Failed => $delivery->updated_at
? CarbonImmutable::instance($delivery->updated_at)
: null,
AlertDestinationLastTestStatusEnum::Pending => $delivery->send_after
? CarbonImmutable::instance($delivery->send_after)
: ($delivery->created_at ? CarbonImmutable::instance($delivery->created_at) : null),
AlertDestinationLastTestStatusEnum::Never => null,
};
}
}