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

90
app/Models/Client.php Normal file
View File

@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Concerns\BumpsContentVersion;
use App\Models\Concerns\HasImages;
use App\Models\Concerns\HasRevisions;
use Database\Factories\ClientFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Translatable\HasTranslations;
/**
* An organisation the work was for.
*
* This used to be a name typed into every project by hand, which meant the
* same association written twice was two different entities and a logo had
* nowhere to live. Being a record instead makes the wall of logos possible and
* makes "everything we did for them" a question with an answer.
*/
#[Fillable(['name', 'slug', 'sector', 'logo', 'url', 'is_public', 'position'])]
class Client extends Model
{
/** @use HasFactory<ClientFactory> */
use BumpsContentVersion, HasFactory, HasImages, HasRevisions, HasTranslations, SoftDeletes;
/**
* The name is a proper noun — an association is called what it is called
* in every language — so only the prose about it is translated.
*
* @var array<int, string>
*/
public array $translatable = ['sector'];
protected function casts(): array
{
return [
'is_public' => 'boolean',
'position' => 'integer',
];
}
/**
* @return array<int, string>
*/
public function imageAttributes(): array
{
return ['logo'];
}
/**
* @return BelongsTo<Media, $this>
*/
public function logoMedia(): BelongsTo
{
return $this->imageRelation('logo');
}
/**
* @return HasMany<Project, $this>
*/
public function projects(): HasMany
{
return $this->hasMany(Project::class);
}
/**
* @return HasMany<Testimonial, $this>
*/
public function testimonials(): HasMany
{
return $this->hasMany(Testimonial::class);
}
/**
* @param Builder<$this> $query
* @return Builder<$this>
*/
public function scopePublic(Builder $query): Builder
{
return $query->where('is_public', true);
}
}