TenantAtlas/apps/platform/app/Support/Inventory/TenantCoverageTruth.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

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,
),
];
}
}