docs(portal): document the discovery portal, endpoints and mature filter
This commit is contained in:
@@ -3,6 +3,10 @@
|
|||||||
This document describes the layout components that form the structure of the
|
This document describes the layout components that form the structure of the
|
||||||
Flashpoint Web application.
|
Flashpoint Web application.
|
||||||
|
|
||||||
|
Public pages use `PortalLayout` instead of `AppShell`; see
|
||||||
|
[Discovery Portal](../../10-features/12-discovery-portal.md). `AppShell` remains
|
||||||
|
for settings and admin pages.
|
||||||
|
|
||||||
## Component Hierarchy
|
## Component Hierarchy
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ Flashpoint Web frontend.
|
|||||||
/activities → ActivitiesView (requires "activities.read")
|
/activities → ActivitiesView (requires "activities.read")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Layouts
|
||||||
|
|
||||||
|
Public routes (home, browse, game and player pages, favorites, playlists,
|
||||||
|
downloaded, dashboard) render in `PortalLayout`; settings and admin routes
|
||||||
|
render in `MainLayout` with the sidebar. See
|
||||||
|
[Discovery Portal](../10-features/12-discovery-portal.md).
|
||||||
|
|
||||||
## Route Protection
|
## Route Protection
|
||||||
|
|
||||||
### ProtectedRoute Component
|
### ProtectedRoute Component
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ Default: 100 requests per 15 minutes. Headers: `X-RateLimit-Limit`,
|
|||||||
- [GET /api/games/:id/launch](./games-api.md#get-launch-data)
|
- [GET /api/games/:id/launch](./games-api.md#get-launch-data)
|
||||||
- [GET /api/games/:id/related](./games-api.md#get-related-games)
|
- [GET /api/games/:id/related](./games-api.md#get-related-games)
|
||||||
|
|
||||||
|
### Discovery
|
||||||
|
|
||||||
|
- [GET /api/discovery/daily](./discovery-api.md#get-game-of-the-day)
|
||||||
|
- [GET /api/discovery/playlists](./discovery-api.md#get-playlist-shelves)
|
||||||
|
|
||||||
### Users
|
### Users
|
||||||
|
|
||||||
- [GET /api/users](./users-api.md#list-users)
|
- [GET /api/users](./users-api.md#list-users)
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Discovery API
|
||||||
|
|
||||||
|
Homepage picks drawn from the Flashpoint curated playlists (`Data/Playlists`).
|
||||||
|
Only arcade playlists are used, and mature games are left out unless
|
||||||
|
`showExtreme=true` (see
|
||||||
|
[Mature Content](../10-features/12-discovery-portal.md#mature-content)).
|
||||||
|
|
||||||
|
## Get Game of the Day
|
||||||
|
|
||||||
|
`GET /api/discovery/daily?date=2026-10-12` - No auth required
|
||||||
|
|
||||||
|
Query params: `date` (YYYY-MM-DD, default: today in UTC), `showExtreme`
|
||||||
|
(default: false)
|
||||||
|
|
||||||
|
Picks the same game for everyone on a given date, from all curated playlists
|
||||||
|
combined. Games missing from the install are skipped.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"date": "2026-10-12",
|
||||||
|
"game": { "id": "0a4ffe5c-...", "title": "The World's Hardest Game 4", ... },
|
||||||
|
"playlist": { "id": "f45d2eb2-...", "title": "Rage for the Ages" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Error: `404 Not Found` if no curated games exist
|
||||||
|
|
||||||
|
## Get Playlist Shelves
|
||||||
|
|
||||||
|
`GET /api/discovery/playlists?count=3&perShelf=7&seed=42` - No auth required
|
||||||
|
|
||||||
|
Query params: `count` (default: 3), `perShelf` (games per playlist, default: 7),
|
||||||
|
`seed` (0-2147483647, default: 0), `showExtreme` (default: false)
|
||||||
|
|
||||||
|
Returns `count` curated playlists, each with a sample of its games. The same
|
||||||
|
seed always returns the same playlists and games.
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "f45d2eb2-...",
|
||||||
|
"title": "Jingle Jollies",
|
||||||
|
"total": 30,
|
||||||
|
"games": [{ "id": "7de03fe2-...", "title": "Christmas Escape", ... }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
@@ -10,10 +10,14 @@ Body (JSON): `search` (title/developer/publisher), `platform`, `series`,
|
|||||||
`developers`, `publishers`, `playModes`, `languages`, `library`
|
`developers`, `publishers`, `playModes`, `languages`, `library`
|
||||||
(arcade|theatre), `downloaded` (boolean, optional - restrict to games whose
|
(arcade|theatre), `downloaded` (boolean, optional - restrict to games whose
|
||||||
data is present on disk), `tags`, `yearFrom`, `yearTo`, `dateAddedSince` (ISO
|
data is present on disk), `tags`, `yearFrom`, `yearTo`, `dateAddedSince` (ISO
|
||||||
datetime), `dateModifiedSince` (ISO datetime), `sortBy`
|
datetime), `dateModifiedSince` (ISO datetime), `releasedFrom`, `releasedTo`
|
||||||
(title|releaseDate|dateAdded|dateModified|developer, default: title),
|
(YYYY-MM-DD, inclusive; only matches day-precise release dates), `sortBy`
|
||||||
`sortOrder` (asc|desc, default: asc), `page` (default: 1), `limit` (default: 50,
|
(title|releaseDate|dateAdded|dateModified|developer|random, default: title),
|
||||||
max: 100), `showBroken` (default: false), `showExtreme` (default: false)
|
`seed` (0-2147483647, for `random`: the same seed gives the same order across
|
||||||
|
pages), `sortOrder` (asc|desc, default: asc), `page` (default: 1), `limit`
|
||||||
|
(default: 50, max: 100), `showBroken` (default: false), `showExtreme` (default:
|
||||||
|
false, include
|
||||||
|
[mature games](../10-features/12-discovery-portal.md#mature-content))
|
||||||
|
|
||||||
Returns paginated array with essential game fields (id, title, developer,
|
Returns paginated array with essential game fields (id, title, developer,
|
||||||
platformName, library, tags, orderTitle).
|
platformName, library, tags, orderTitle).
|
||||||
@@ -39,7 +43,8 @@ with name/code and count.
|
|||||||
|
|
||||||
`GET /api/games/random?library=arcade` - No auth required
|
`GET /api/games/random?library=arcade` - No auth required
|
||||||
|
|
||||||
Query param: `library` (optional)
|
Query params: `library` (optional), `platforms` (comma-separated, optional),
|
||||||
|
`showExtreme` (default: false)
|
||||||
|
|
||||||
Returns single random game object.
|
Returns single random game object.
|
||||||
|
|
||||||
@@ -137,7 +142,7 @@ canPlayInBrowser, and downloading status.
|
|||||||
|
|
||||||
`GET /api/games/:id/related?limit=10` - No auth required
|
`GET /api/games/:id/related?limit=10` - No auth required
|
||||||
|
|
||||||
Query param: `limit` (default: 10, max: 50)
|
Query params: `limit` (default: 10, max: 50), `showExtreme` (default: false)
|
||||||
|
|
||||||
Returns array of related games based on developer/series/tags.
|
Returns array of related games based on developer/series/tags.
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ Returns key-value pairs (stored as strings). Common keys:
|
|||||||
- game_view_mode (grid|list)
|
- game_view_mode (grid|list)
|
||||||
- games_per_page (string, numeric)
|
- games_per_page (string, numeric)
|
||||||
- auto_play_next (true|false)
|
- auto_play_next (true|false)
|
||||||
- show_extreme_content (true|false)
|
- show_mature (1|0) - show mature games; see
|
||||||
|
[Mature Content](../10-features/12-discovery-portal.md#mature-content)
|
||||||
|
|
||||||
## Update User Settings
|
## Update User Settings
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
Dynamic theme system with light/dark modes and 22 customizable color palettes.
|
Dynamic theme system with light/dark modes and 22 customizable color palettes.
|
||||||
Uses CSS variables for instant theme switching with Zustand state management.
|
Uses CSS variables for instant theme switching with Zustand state management.
|
||||||
|
|
||||||
|
Public pages are styled by portal color schemes instead, which override these
|
||||||
|
tokens while mounted; see
|
||||||
|
[Discovery Portal](../10-features/12-discovery-portal.md#color-schemes).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -37,14 +37,19 @@ grid and list view options.
|
|||||||
- Platform, Series, Developer, Publisher
|
- Platform, Series, Developer, Publisher
|
||||||
- Play Mode, Language, Tags
|
- Play Mode, Language, Tags
|
||||||
- Year Range (1970-2100)
|
- Year Range (1970-2100)
|
||||||
|
- Release date range (day-precise dates, e.g. a Time Machine week)
|
||||||
- Library (arcade/theatre)
|
- Library (arcade/theatre)
|
||||||
- Downloaded only
|
- Downloaded only
|
||||||
- Show/hide broken games and extreme content
|
- Show/hide broken games and
|
||||||
|
[mature content](./12-discovery-portal.md#mature-content)
|
||||||
|
|
||||||
**Sorting:**
|
**Sorting:**
|
||||||
|
|
||||||
- By: Title, Release Date, Date Added, Developer
|
- By: Shuffled (default), Title (default for searches), Release Date, Date
|
||||||
|
Added, Developer
|
||||||
- Order: Ascending (A-Z) or Descending (Z-A)
|
- Order: Ascending (A-Z) or Descending (Z-A)
|
||||||
|
- The shuffle seed is kept in the URL so pages keep a stable order; Reshuffle
|
||||||
|
picks a new one
|
||||||
|
|
||||||
**Pagination:**
|
**Pagination:**
|
||||||
|
|
||||||
@@ -102,7 +107,9 @@ Get paginated list of games with filters.
|
|||||||
- `playModes`, `languages`, `tags` - Comma-separated
|
- `playModes`, `languages`, `tags` - Comma-separated
|
||||||
- `library` - 'arcade' or 'theatre'
|
- `library` - 'arcade' or 'theatre'
|
||||||
- `yearFrom`, `yearTo` - Release year range
|
- `yearFrom`, `yearTo` - Release year range
|
||||||
- `sortBy` - 'title', 'releaseDate', 'dateAdded', 'developer'
|
- `releasedFrom`, `releasedTo` - Release date range (YYYY-MM-DD)
|
||||||
|
- `sortBy` - 'title', 'releaseDate', 'dateAdded', 'developer', 'random'
|
||||||
|
- `seed` - Shuffle seed for 'random'
|
||||||
- `sortOrder` - 'asc' or 'desc'
|
- `sortOrder` - 'asc' or 'desc'
|
||||||
- `page` - Page number
|
- `page` - Page number
|
||||||
- `limit` - Items per page
|
- `limit` - Items per page
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ CREATE TABLE system_settings (
|
|||||||
#### App Tab
|
#### App Tab
|
||||||
|
|
||||||
- **Site Name** - Customize application name
|
- **Site Name** - Customize application name
|
||||||
|
- **Tagline** - Optional line shown under the site name in the portal header
|
||||||
- **Maintenance Mode** - Enable/disable maintenance mode
|
- **Maintenance Mode** - Enable/disable maintenance mode
|
||||||
- **Default Theme** - Set default theme (light, dark, system)
|
- **Default Theme** - Set default theme (light, dark, system)
|
||||||
- **Default Primary Color** - Set default color scheme
|
- **Default Primary Color** - Set default color scheme
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# Discovery Portal
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The public pages use an arcade portal layout styled after 2010-era Flash game
|
||||||
|
sites, with a homepage built for discovery instead of lists of recent changes.
|
||||||
|
Account and admin pages keep the application layout.
|
||||||
|
|
||||||
|
## Shell
|
||||||
|
|
||||||
|
`PortalLayout` (`frontend/src/components/portal/`) wraps the homepage, browse,
|
||||||
|
game, player, favorites, playlists, downloaded and dashboard routes:
|
||||||
|
|
||||||
|
- A framed fixed-width page (1180px, desktop first)
|
||||||
|
- A wordmark built from the **Site Name** setting, with the optional **Tagline**
|
||||||
|
setting underneath
|
||||||
|
- Search, and a user menu holding the library, account and admin links and the
|
||||||
|
mature content switch
|
||||||
|
- Genre categories linking to browse by tag: Action, Adventure, Puzzle, Shooter,
|
||||||
|
Platformer, Sports, Strategy, Driving, Escape the Room and Dress Up, plus
|
||||||
|
Animations
|
||||||
|
- Keyboard shortcuts: `/` focuses search, `R` opens a random game
|
||||||
|
|
||||||
|
## Color Schemes
|
||||||
|
|
||||||
|
Portal colors are token sets in `components/portal/schemes.ts`. Each scheme sets
|
||||||
|
`--p-*` properties for the portal's own styles (`portal.css`) and overrides the
|
||||||
|
shadcn tokens (`--background`, `--primary`, ...) so shared components match. The
|
||||||
|
tokens are applied to `<body>` while the portal is mounted, which takes
|
||||||
|
precedence over the app theme on `<html>` and also reaches dialogs and menus
|
||||||
|
rendered into the body.
|
||||||
|
|
||||||
|
One scheme ships, **Chilled** (slate background, sage boxes). Adding a scheme
|
||||||
|
means adding an entry to `PORTAL_SCHEMES`; no component changes are needed.
|
||||||
|
|
||||||
|
Display text uses Fredoka (OFL, bundled via `@fontsource-variable/fredoka`);
|
||||||
|
body text uses Verdana.
|
||||||
|
|
||||||
|
## Homepage
|
||||||
|
|
||||||
|
- **Game of the Day:** the same pick for everyone on a given day, from the
|
||||||
|
Flashpoint curated playlists, with a link to the previous day's pick
|
||||||
|
- **Time Machine:** games released in a given week, starting from a random day
|
||||||
|
between 2005 and 2014. Users can step by week, jump to a random day, or click
|
||||||
|
the date to pick any day. "See all" opens browse filtered to that week. Only
|
||||||
|
games with a day-precise release date are included.
|
||||||
|
- **Jump back in:** the signed-in user's recently played games
|
||||||
|
- **Playlist shelves:** three random curated playlists with a sample of their
|
||||||
|
games
|
||||||
|
|
||||||
|
See the [Discovery API](../06-api-reference/discovery-api.md).
|
||||||
|
|
||||||
|
## Default Ordering
|
||||||
|
|
||||||
|
Browse lists default to a shuffle instead of title order. The shuffle is seeded
|
||||||
|
and the seed is kept in the URL (`seed=`), so paging, back navigation and shared
|
||||||
|
links keep the same order; Reshuffle picks a new seed. Searches still default to
|
||||||
|
title order.
|
||||||
|
|
||||||
|
## Mature Content
|
||||||
|
|
||||||
|
Flashpoint's `extreme` game flag is not set in current metadata, so mature games
|
||||||
|
are identified the way the Flashpoint Launcher does: by the tag filter groups
|
||||||
|
marked `extreme` in `preferences.json` (falling back to
|
||||||
|
`.preferences.defaults.json`, then to the launcher's default groups:
|
||||||
|
Pornography, Fetishes, Violence, Bigotry and Pornography Extreme).
|
||||||
|
|
||||||
|
`MatureContentService` resolves those tags to game IDs once per database load.
|
||||||
|
Search, random, related games and discovery exclude them unless the request sets
|
||||||
|
`showExtreme=true`.
|
||||||
|
|
||||||
|
Users opt in with **Show mature games** in the user menu. The choice is stored
|
||||||
|
in the browser (`flashpoint-mature-content`), and for signed-in users also in
|
||||||
|
the account's `show_mature` setting, which is applied when they sign in on
|
||||||
|
another browser.
|
||||||
@@ -27,6 +27,8 @@ Web application.
|
|||||||
date/time formatting and localization across the application
|
date/time formatting and localization across the application
|
||||||
11. [Maintenance Mode](./11-maintenance-mode.md) - Temporarily restrict access
|
11. [Maintenance Mode](./11-maintenance-mode.md) - Temporarily restrict access
|
||||||
during system updates while allowing admin access
|
during system updates while allowing admin access
|
||||||
|
12. [Discovery Portal](./12-discovery-portal.md) - Arcade portal layout, color
|
||||||
|
schemes, discovery homepage and mature content filtering
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user