## 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
137 lines
4.1 KiB
PHP
137 lines
4.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\Inventory;
|
|
|
|
use App\Models\OperationRun;
|
|
use InvalidArgumentException;
|
|
|
|
final readonly class TenantCoverageTruth
|
|
{
|
|
/**
|
|
* @param list<TenantCoverageTypeTruth> $rows
|
|
*/
|
|
public function __construct(
|
|
public int $tenantId,
|
|
public ?OperationRun $basisRun,
|
|
public bool $hasCurrentCoverageResult,
|
|
public int $supportedTypeCount,
|
|
public int $succeededTypeCount,
|
|
public int $failedTypeCount,
|
|
public int $skippedTypeCount,
|
|
public int $unknownTypeCount,
|
|
public int $followUpTypeCount,
|
|
public int $observedItemTotal,
|
|
public array $rows,
|
|
) {
|
|
if ($this->tenantId <= 0) {
|
|
throw new InvalidArgumentException('Tenant coverage truth requires a positive tenant id.');
|
|
}
|
|
|
|
if ($this->supportedTypeCount < 0 || $this->observedItemTotal < 0) {
|
|
throw new InvalidArgumentException('Tenant coverage truth counts must be zero or greater.');
|
|
}
|
|
}
|
|
|
|
public function basisRunId(): ?int
|
|
{
|
|
return $this->basisRun instanceof OperationRun
|
|
? (int) $this->basisRun->getKey()
|
|
: null;
|
|
}
|
|
|
|
public function basisRunOutcome(): ?string
|
|
{
|
|
return $this->basisRun instanceof OperationRun
|
|
? (string) $this->basisRun->outcome
|
|
: null;
|
|
}
|
|
|
|
public function basisCompletedAtLabel(): ?string
|
|
{
|
|
if (! $this->basisRun instanceof OperationRun) {
|
|
return null;
|
|
}
|
|
|
|
$timestamp = $this->basisRun->completed_at ?? $this->basisRun->started_at ?? $this->basisRun->created_at;
|
|
|
|
return $timestamp?->diffForHumans(['short' => true]);
|
|
}
|
|
|
|
public function topPriorityFollowUpRow(): ?TenantCoverageTypeTruth
|
|
{
|
|
foreach ($this->rows as $row) {
|
|
if ($row->followUpRequired) {
|
|
return $row;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function observedTypeCount(): int
|
|
{
|
|
return count(array_filter(
|
|
$this->rows,
|
|
static fn (TenantCoverageTypeTruth $row): bool => $row->observedItemCount > 0,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @return list<TenantCoverageTypeTruth>
|
|
*/
|
|
public function followUpRows(): array
|
|
{
|
|
return array_values(array_filter(
|
|
$this->rows,
|
|
static fn (TenantCoverageTypeTruth $row): bool => $row->followUpRequired,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* tenantId: int,
|
|
* basisRun: array{id: int, outcome: string, completedAt: string|null}|null,
|
|
* hasCurrentCoverageResult: bool,
|
|
* summary: array{
|
|
* supportedTypes: int,
|
|
* succeededTypes: int,
|
|
* failedTypes: int,
|
|
* skippedTypes: int,
|
|
* unknownTypes: int,
|
|
* followUpTypes: int,
|
|
* observedItems: int
|
|
* },
|
|
* rows: list<array<string, mixed>>
|
|
* }
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'tenantId' => $this->tenantId,
|
|
'basisRun' => $this->basisRun instanceof OperationRun
|
|
? [
|
|
'id' => (int) $this->basisRun->getKey(),
|
|
'outcome' => (string) $this->basisRun->outcome,
|
|
'completedAt' => $this->basisRun->completed_at?->toIso8601String(),
|
|
]
|
|
: null,
|
|
'hasCurrentCoverageResult' => $this->hasCurrentCoverageResult,
|
|
'summary' => [
|
|
'supportedTypes' => $this->supportedTypeCount,
|
|
'succeededTypes' => $this->succeededTypeCount,
|
|
'failedTypes' => $this->failedTypeCount,
|
|
'skippedTypes' => $this->skippedTypeCount,
|
|
'unknownTypes' => $this->unknownTypeCount,
|
|
'followUpTypes' => $this->followUpTypeCount,
|
|
'observedItems' => $this->observedItemTotal,
|
|
],
|
|
'rows' => array_map(
|
|
static fn (TenantCoverageTypeTruth $row): array => $row->toArray(),
|
|
$this->rows,
|
|
),
|
|
];
|
|
}
|
|
}
|