Initial commit: Pireon Admin — headless admin panel and public API

Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer
collective, backed by the Pireon OAuth identity server. The public site is a
separate, server-rendered application consuming /api/public/v1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 17:55:27 +02:00
commit 3897113313
534 changed files with 64050 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace Tests\Feature\Api;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
use Symfony\Component\Yaml\Yaml;
use Tests\TestCase;
/**
* The browsable API documentation.
*
* The specification was always there as a file; what this covers is that it is
* readable, that it stays in step with the routes it claims to describe, and
* that nothing about it depends on somebody else's CDN.
*/
class ApiDocsTest extends TestCase
{
use RefreshDatabase;
#[Test]
public function the_docs_page_opens_without_signing_in(): void
{
// The people who need it are writing the public frontend and have no
// reason to hold a panel account.
$this->get('/docs/api')
->assertOk()
->assertSee('swagger', escape: false);
}
#[Test]
public function it_points_at_the_installation_being_looked_at(): void
{
$html = (string) $this->get('/docs/api')->assertOk()->getContent();
// Not the canonical URL from the configuration: the same page is
// opened on a laptop, on staging and in production, and "try it out"
// has to reach whichever one it is.
$this->assertStringContainsString(json_encode(url('/api')), $html);
$this->assertStringContainsString(json_encode(asset('openapi.yaml')), $html);
}
#[Test]
public function it_carries_its_own_assets(): void
{
$html = (string) $this->get('/docs/api')->assertOk()->getContent();
// The docs have to work on a laptop with no internet, and a script tag
// pointing at somebody else's server is a dependency this application
// does not otherwise have.
$this->assertStringNotContainsString('cdn.', $html);
$this->assertStringNotContainsString('unpkg', $html);
foreach (['swagger-ui.css', 'swagger-ui-bundle.js', 'swagger-ui-standalone-preset.js'] as $asset) {
$this->assertFileExists(public_path("vendor/swagger-ui/{$asset}"));
$this->assertStringContainsString("vendor/swagger-ui/{$asset}", $html);
}
}
#[Test]
public function the_specification_parses(): void
{
$spec = Yaml::parseFile(public_path('openapi.yaml'));
$this->assertIsArray($spec);
$this->assertArrayHasKey('paths', $spec);
$this->assertNotEmpty($spec['paths']);
}
/**
* Every path the specification advertises exists as a route.
*
* Documentation that describes an endpoint nobody implemented is worse
* than none: it is believed.
*/
#[Test]
public function every_documented_endpoint_is_routed(): void
{
$spec = Yaml::parseFile(public_path('openapi.yaml'));
$routes = collect(app('router')->getRoutes()->getRoutes())
->flatMap(fn ($route) => collect($route->methods())
->map(fn (string $method) => strtolower($method).' '.$route->uri()))
->all();
$missing = [];
foreach ($spec['paths'] as $path => $operations) {
// The specification is served under an `/api` base URL, and route
// parameters are named independently on either side.
$uri = 'api'.preg_replace('/\{[^}]+\}/', '{param}', $path);
// A path item may also carry `parameters`, `summary` and friends;
// only the HTTP methods describe an endpoint.
$methods = array_intersect(
array_keys($operations),
['get', 'put', 'post', 'delete', 'patch', 'head', 'options', 'trace'],
);
foreach ($methods as $method) {
$normalised = collect($routes)
->map(fn (string $route) => preg_replace('/\{[^}]+\}/', '{param}', $route))
->contains(strtolower($method).' '.$uri);
if (! $normalised) {
$missing[] = strtoupper($method)." {$path}";
}
}
}
$this->assertSame([], $missing, "Documented but not routed:\n".implode("\n", $missing));
}
}