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>
402 lines
10 KiB
TypeScript
402 lines
10 KiB
TypeScript
/**
|
|
* Pireon Admin API — the public payloads.
|
|
*
|
|
* Generated from openapi.yaml by `php artisan api:types`. Do not edit:
|
|
* change the specification instead, and the contract test will hold the
|
|
* API to it.
|
|
*/
|
|
|
|
/**
|
|
* The same record's path in each language that has a translation. Feed
|
|
* these straight into `<link rel="alternate" hreflang>`. Languages with
|
|
* no translation are absent, so no advertised URL ever 404s.
|
|
*/
|
|
export type Alternates = Record<string, string>;
|
|
|
|
/**
|
|
* Everything needed to render an image well server-side. A path alone
|
|
* was never enough: without `width`/`height` the page reflows as images
|
|
* arrive, without `srcset` every visitor downloads the original, and
|
|
* without `alt` the page is not accessible.
|
|
*
|
|
* Degrades on purpose — an upload whose derived versions are not ready
|
|
* yet still carries a `url`, with the rest null, so the frontend renders
|
|
* a plain `<img>` rather than a gap.
|
|
*/
|
|
export interface Image {
|
|
/**
|
|
* Absolute, because the frontend is on another host.
|
|
*/
|
|
url: string;
|
|
/**
|
|
* Empty string when the image is decorative — that is what `alt=""`
|
|
* means — never absent. Follows the requested language.
|
|
*/
|
|
alt: string;
|
|
width?: number;
|
|
height?: number;
|
|
aspect_ratio?: number;
|
|
mime?: string;
|
|
/**
|
|
* Tiny blurred data URI to paint while the real image loads.
|
|
*/
|
|
placeholder?: string;
|
|
/**
|
|
* Keyed by format, ready to use verbatim — build a `<picture>` with
|
|
* AVIF first and WebP behind it. Only widths that actually exist are
|
|
* listed, and an image is never scaled up.
|
|
*/
|
|
srcset?: Record<string, string>;
|
|
}
|
|
|
|
/**
|
|
* A call for contributors. The commitment fields are the point: time is
|
|
* the scarce resource in a volunteer collective, and stating it plainly
|
|
* is what lets someone decide.
|
|
*/
|
|
export interface PublicCall {
|
|
id: number;
|
|
locale: string;
|
|
title: string;
|
|
slug: string;
|
|
description?: string;
|
|
/**
|
|
* The explicit exchange offered for unpaid work.
|
|
*/
|
|
what_you_get?: string;
|
|
status: 'open' | 'filled' | 'closed';
|
|
hours_per_week?: number;
|
|
duration_weeks?: number;
|
|
total_hours?: number;
|
|
seniority?: 'any' | 'junior' | 'mid' | 'senior';
|
|
closes_at?: string;
|
|
project: PublicProject;
|
|
technologies: PublicTechnology[];
|
|
alternates: Alternates;
|
|
path?: string;
|
|
}
|
|
|
|
export interface PublicCategory {
|
|
id: number;
|
|
name?: string;
|
|
slug?: string;
|
|
description?: string;
|
|
color?: string;
|
|
position: number;
|
|
pages_count: number;
|
|
}
|
|
|
|
export interface PublicClient {
|
|
id: number;
|
|
/**
|
|
* A proper noun, so it is the same in every language.
|
|
*/
|
|
name: string;
|
|
slug: string;
|
|
sector?: string;
|
|
url?: string;
|
|
/**
|
|
* Its alt text is the organisation's name.
|
|
*/
|
|
logo?: Image;
|
|
projects_count: number;
|
|
}
|
|
|
|
export interface PublicIssue {
|
|
number: number;
|
|
title: string;
|
|
url: string;
|
|
labels: string[];
|
|
is_good_first_issue: boolean;
|
|
is_help_wanted: boolean;
|
|
/**
|
|
* Nobody has claimed it. A claimed issue is not an invitation.
|
|
*/
|
|
is_available: boolean;
|
|
comments: number;
|
|
created_at?: string;
|
|
repository: { full_name: string; url?: string; primary_language?: string; project?: { title: string; slug: string } };
|
|
}
|
|
|
|
export interface PublicMember {
|
|
id: number;
|
|
name: string;
|
|
slug: string;
|
|
headline?: string;
|
|
bio?: string;
|
|
avatar?: Image;
|
|
github_username?: string;
|
|
links: Record<string, string>;
|
|
is_founder: boolean;
|
|
/**
|
|
* False for people who have left; their work is kept.
|
|
*/
|
|
is_current: boolean;
|
|
joined_at?: string;
|
|
left_at?: string;
|
|
/**
|
|
* Their role on a project, when nested under one.
|
|
*/
|
|
role?: string;
|
|
technologies: PublicTechnology[];
|
|
projects: PublicProject[];
|
|
alternates: Alternates;
|
|
path: string;
|
|
}
|
|
|
|
export interface PublicPage {
|
|
id: number;
|
|
locale: string;
|
|
title?: string;
|
|
slug?: string;
|
|
excerpt?: string;
|
|
body?: string;
|
|
meta_title?: string;
|
|
meta_description?: string;
|
|
status: string;
|
|
is_featured: boolean;
|
|
featured_image?: Image;
|
|
published_at?: string;
|
|
/**
|
|
* When the record leaves the site. Enforced by the query itself, so
|
|
* it holds whether or not anything is running. Use it to expire a
|
|
* cache downstream at the same moment.
|
|
*/
|
|
unpublish_at?: string;
|
|
updated_at: string;
|
|
category: PublicCategory;
|
|
alternates: Alternates;
|
|
path?: string;
|
|
}
|
|
|
|
export interface PublicProject {
|
|
id: number;
|
|
locale: string;
|
|
title: string;
|
|
slug: string;
|
|
tagline?: string;
|
|
/**
|
|
* Detail endpoint only.
|
|
*/
|
|
description?: string;
|
|
/**
|
|
* Why the technical choices were made. Detail endpoint only.
|
|
*/
|
|
decisions?: string;
|
|
/**
|
|
* What went wrong and what was learned. Detail endpoint only.
|
|
*/
|
|
postmortem?: string;
|
|
/**
|
|
* What a search engine or a chat preview should show instead of the
|
|
* title. Detail endpoint only.
|
|
*/
|
|
meta_title?: string;
|
|
/**
|
|
* Detail endpoint only.
|
|
*/
|
|
meta_description?: string;
|
|
status: 'idea' | 'active' | 'paused' | 'completed' | 'archived';
|
|
is_featured: boolean;
|
|
/**
|
|
* Flagged directly, or carrying at least one open call.
|
|
*/
|
|
needs_help: boolean;
|
|
cover_image?: Image;
|
|
/**
|
|
* Screenshots and before-and-after, in the order they were arranged
|
|
* in the panel. **Detail endpoint only** — a listing of twenty
|
|
* projects has no use for every screenshot of each one.
|
|
*/
|
|
gallery: (Image & { caption?: string })[];
|
|
demo_url?: string;
|
|
/**
|
|
* The NGO or association the work serves. Used to be two free-text
|
|
* fields, which made the same organisation two different things.
|
|
*/
|
|
client?: PublicClient;
|
|
services: PublicService[];
|
|
testimonials: PublicTestimonial[];
|
|
talks: PublicTalk[];
|
|
started_at?: string;
|
|
ended_at?: string;
|
|
published_at?: string;
|
|
/**
|
|
* When the record leaves the site. Enforced by the query itself, so
|
|
* it holds whether or not anything is running. Use it to expire a
|
|
* cache downstream at the same moment.
|
|
*/
|
|
unpublish_at?: string;
|
|
updated_at: string;
|
|
technologies: PublicTechnology[];
|
|
members: PublicMember[];
|
|
lead: PublicMember;
|
|
calls: PublicCall[];
|
|
repositories: PublicRepository[];
|
|
alternates: Alternates;
|
|
path?: string;
|
|
}
|
|
|
|
/**
|
|
* Mirrored from the git provider and refreshed hourly.
|
|
*/
|
|
export interface PublicRepository {
|
|
id: number;
|
|
provider: 'github' | 'gitlab' | 'gitea';
|
|
full_name: string;
|
|
url?: string;
|
|
description?: string;
|
|
primary_language?: string;
|
|
/**
|
|
* Bytes of code per language.
|
|
*/
|
|
languages: Record<string, number>;
|
|
topics: string[];
|
|
license?: string;
|
|
stars: number;
|
|
forks: number;
|
|
contributors_count: number;
|
|
open_issues_count: number;
|
|
is_archived: boolean;
|
|
/**
|
|
* Nothing pushed for six months. Lets the frontend avoid presenting
|
|
* dead work as live.
|
|
*/
|
|
is_dormant: boolean;
|
|
pushed_at?: string;
|
|
synced_at?: string;
|
|
good_first_issues: PublicIssue[];
|
|
}
|
|
|
|
export interface PublicService {
|
|
id: number;
|
|
locale: string;
|
|
title: string;
|
|
slug: string;
|
|
tagline?: string;
|
|
/**
|
|
* Detail endpoint only.
|
|
*/
|
|
description?: string;
|
|
/**
|
|
* What a search engine or a chat preview should show instead of the
|
|
* title. Detail endpoint only.
|
|
*/
|
|
meta_title?: string;
|
|
/**
|
|
* Detail endpoint only.
|
|
*/
|
|
meta_description?: string;
|
|
/**
|
|
* A Heroicons name, e.g. `heroicon-o-code-bracket`.
|
|
*/
|
|
icon?: string;
|
|
is_featured: boolean;
|
|
position: number;
|
|
/**
|
|
* So a cache downstream can tell whether its copy is still the
|
|
* current one.
|
|
*/
|
|
updated_at?: string;
|
|
/**
|
|
* The published work that backs the offer. Detail endpoint only.
|
|
*/
|
|
projects: PublicProject[];
|
|
technologies: PublicTechnology[];
|
|
testimonials: PublicTestimonial[];
|
|
alternates: Alternates;
|
|
path?: string;
|
|
}
|
|
|
|
export interface PublicTalk {
|
|
id: number;
|
|
/**
|
|
* Not translated: the name of a talk given once, in one language.
|
|
*/
|
|
title: string;
|
|
language: string;
|
|
summary?: string;
|
|
event: string;
|
|
city?: string;
|
|
held_at?: string;
|
|
video_url?: string;
|
|
slides_url?: string;
|
|
speaker?: PublicMember;
|
|
}
|
|
|
|
export interface PublicTechnology {
|
|
id: number;
|
|
/**
|
|
* Not translated — technology names are proper nouns.
|
|
*/
|
|
name: string;
|
|
slug: string;
|
|
category: 'language' | 'framework' | 'datastore' | 'infrastructure' | 'tool' | 'practice';
|
|
color?: string;
|
|
icon?: string;
|
|
/**
|
|
* The technology's own logo. Its `alt` is the technology's name —
|
|
* there is nothing to write and nothing to get wrong.
|
|
*/
|
|
logo?: Image;
|
|
website?: string;
|
|
/**
|
|
* Radar placement. Null for technologies used but not placed.
|
|
*/
|
|
ring?: 'adopt' | 'trial' | 'assess' | 'hold';
|
|
description?: string;
|
|
/**
|
|
* Why it sits in that ring.
|
|
*/
|
|
radar_note?: string;
|
|
projects_count: number;
|
|
members_count: number;
|
|
}
|
|
|
|
export interface PublicTestimonial {
|
|
id: number;
|
|
quote: string;
|
|
/**
|
|
* The language it was actually said in.
|
|
*/
|
|
original_locale: string;
|
|
/**
|
|
* False when the quote you are reading was translated by us. Say so —
|
|
* "translated from Spanish" — rather than implying they phrased it
|
|
* that way.
|
|
*/
|
|
is_original: boolean;
|
|
author: { name: string; role?: string; avatar?: Image };
|
|
given_at?: string;
|
|
client?: PublicClient;
|
|
}
|
|
|
|
/**
|
|
* Either a plain string (applies to the active language) or an object
|
|
* keyed by locale.
|
|
*/
|
|
export type TranslatedField = Record<string, string>;
|
|
|
|
/** What each public endpoint answers with, under `data`. */
|
|
export interface PublicApiPayloads {
|
|
'/public/v1/site': { locales: ({ code: string; name: string; flag: string; is_default: boolean })[]; default_locale: string; content_version: number; submissions_enabled: boolean; stats: { projects: number; active_projects: number; members: number; open_calls: number; good_first_issues: number; stars: number } };
|
|
'/public/v1/slugs': Record<string, ({ id: number; updated_at: string; alternates: Record<string, string> })[]>;
|
|
'/public/v1/redirects': ({ from: string; to: string; status: 301 | 302; locale?: string })[];
|
|
'/public/v1/projects': PublicProject[];
|
|
'/public/v1/projects/{slug}': PublicProject;
|
|
'/public/v1/members': PublicMember[];
|
|
'/public/v1/members/{slug}': PublicMember;
|
|
'/public/v1/calls': PublicCall[];
|
|
'/public/v1/calls/{slug}': PublicCall;
|
|
'/public/v1/services': PublicService[];
|
|
'/public/v1/services/{slug}': PublicService;
|
|
'/public/v1/clients': PublicClient[];
|
|
'/public/v1/testimonials': PublicTestimonial[];
|
|
'/public/v1/talks': PublicTalk[];
|
|
'/public/v1/pages': PublicPage[];
|
|
'/public/v1/pages/{slug}': PublicPage;
|
|
'/public/v1/technologies': PublicTechnology[];
|
|
'/public/v1/radar': PublicTechnology[];
|
|
'/public/v1/good-first-issues': PublicIssue[];
|
|
}
|