Save workspace changes
This commit is contained in:
88
.deploy/artwork-evolution-release/docs/Discover/fresh.md
Normal file
88
.deploy/artwork-evolution-release/docs/Discover/fresh.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Fresh
|
||||
|
||||
## Route
|
||||
|
||||
- URL: `GET /discover/fresh`
|
||||
- Controller: `App\Http\Controllers\Web\DiscoverController::fresh()`
|
||||
- Service: `App\Services\ArtworkSearchService::discoverFresh()`
|
||||
|
||||
## What the page reads
|
||||
|
||||
Fresh is Meilisearch-backed, then hydrated from MySQL.
|
||||
|
||||
The page does not directly query `artworks` for ranking order.
|
||||
It relies on the search index being up to date.
|
||||
|
||||
If the search-backed result comes back empty, the controller falls back to a direct MySQL query ordered by `published_at DESC, id DESC` so the page does not render blank while search is catching up.
|
||||
|
||||
## Search query
|
||||
|
||||
`discoverFresh()` uses:
|
||||
|
||||
- filter: `is_public = true AND is_approved = true`
|
||||
- sort:
|
||||
- `published_at_ts:desc`
|
||||
|
||||
`published_at_ts` is a numeric timestamp field stored in the search document specifically so same-day uploads can be ordered correctly by hour and minute.
|
||||
|
||||
## Why the dedicated timestamp field exists
|
||||
|
||||
Historically, the index sorted by a date-only `created_at` string, which meant all uploads on the same calendar day could collapse to the same sort value.
|
||||
|
||||
The current implementation uses `published_at_ts` to preserve intra-day ordering and avoid newer uploads being buried behind older uploads from the same date.
|
||||
|
||||
## Page behavior
|
||||
|
||||
Fresh now uses the raw newest-first search result without any curated blending or grid filler injection.
|
||||
|
||||
That means:
|
||||
|
||||
- page 1 is not mixed with spotlight content
|
||||
- page 1 is not padded with older trending artworks
|
||||
- deeper pages follow the same ordering model as page 1
|
||||
|
||||
If older artworks appear near the top, the likely causes are stale search documents or stale cache, not intentional feed mixing.
|
||||
|
||||
If the page renders completely empty even though recent public artworks exist, the DB fallback should populate it. A blank page after that points to a real data visibility problem, not just search freshness.
|
||||
|
||||
## Data sources
|
||||
|
||||
Ranking eligibility depends on:
|
||||
|
||||
- `is_public`
|
||||
- `is_approved`
|
||||
- presence in Meilisearch
|
||||
- `published_at_ts` in the indexed document
|
||||
|
||||
Hydration reads full rows from MySQL after the search query returns IDs.
|
||||
|
||||
When the fallback path is used, the page is served directly from MySQL and does not require Meilisearch for that request.
|
||||
|
||||
## Relevant jobs and schedules
|
||||
|
||||
Fresh does not have a dedicated score calculation job.
|
||||
It depends on publication and indexing freshness.
|
||||
|
||||
Relevant active schedules:
|
||||
|
||||
- `artworks:publish-scheduled` every minute
|
||||
- `skinbase:flush-redis-stats` every 5 minutes (not for ordering, but for displayed stats freshness)
|
||||
|
||||
Index freshness depends on:
|
||||
|
||||
- normal Scout indexing from artwork updates
|
||||
- scheduled-publication indexing after an artwork transitions from scheduled to published
|
||||
- manual/full imports after search-document schema changes
|
||||
|
||||
## Cache behavior
|
||||
|
||||
- Cache key: `discover.fresh.{page}`
|
||||
- TTL: 300 seconds
|
||||
|
||||
## Notes
|
||||
|
||||
- Fresh is the page most sensitive to stale indexing because it is supposed to surface the latest publish action immediately.
|
||||
- If an artwork is public in MySQL but absent from Fresh, the usual causes are:
|
||||
- it has not been indexed yet
|
||||
- app cache has not expired yet
|
||||
- the artwork is not actually public and approved at the same time
|
||||
Reference in New Issue
Block a user