feat(organisation): add dashboard-stats endpoint

GET /organisations/{organisation}/dashboard-stats returns members,
events (with status breakdown + active count), persons, the first five
members sorted by join date, and the five most recent activity log
entries. Business logic lives in OrganisationDashboardService; access
follows OrganisationPolicy@view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 10:27:37 +02:00
parent 036fb3002f
commit 671e0c9889
5 changed files with 341 additions and 0 deletions

View File

@@ -7,14 +7,20 @@ namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\V1\StoreOrganisationRequest;
use App\Http\Requests\Api\V1\UpdateOrganisationRequest;
use App\Http\Resources\Api\V1\OrganisationDashboardStatsResource;
use App\Http\Resources\Api\V1\OrganisationResource;
use App\Models\Organisation;
use App\Services\OrganisationDashboardService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\Gate;
final class OrganisationController extends Controller
{
public function __construct(
private readonly OrganisationDashboardService $dashboardService,
) {}
public function index(): AnonymousResourceCollection
{
Gate::authorize('viewAny', Organisation::class);
@@ -54,4 +60,13 @@ final class OrganisationController extends Controller
return $this->success(new OrganisationResource($organisation->fresh()));
}
public function dashboardStats(Organisation $organisation): JsonResponse
{
Gate::authorize('view', $organisation);
return $this->success(new OrganisationDashboardStatsResource(
$this->dashboardService->statsFor($organisation),
));
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Http\Resources\Api\V1;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* @property-read array<string, mixed> $resource
*/
final class OrganisationDashboardStatsResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'members_count' => $this->resource['members_count'],
'events_count' => $this->resource['events_count'],
'events_by_status' => $this->resource['events_by_status'],
'active_events_count' => $this->resource['active_events_count'],
'persons_count' => $this->resource['persons_count'],
'top_members' => $this->resource['top_members'],
'recent_activity' => $this->resource['recent_activity'],
];
}
}