Skip to content

Add persistent versioned cache for analytics endpoints - #111

Open
Francespo wants to merge 123 commits into
devfrom
copilot/cache-fix-2026-05-24
Open

Add persistent versioned cache for analytics endpoints#111
Francespo wants to merge 123 commits into
devfrom
copilot/cache-fix-2026-05-24

Conversation

@Francespo

Copy link
Copy Markdown
Owner

Objective

Reduce the cost of the daily analytics and catalog queries by caching the expensive responses until the next data refresh.

Context & Symptoms

  • Lists, cards, and dashboard snapshot endpoints repeatedly recompute the same aggregates for identical query parameters.
  • Data ingestion happens once per day, so repeated recalculation during the day is unnecessary.
  • The import and scraper jobs are the natural invalidation points for cached analytics results.

Expected Outcome

  • Expensive endpoint responses are cached persistently on disk.
  • Cache entries are invalidated when the daily import/scrape workflow completes.
  • Common dashboard and catalog responses are warmed immediately after ingest so the first user requests are fast.

Francespo and others added 30 commits March 4, 2026 19:28
Fixed the backend import issues with faction char and improved the
startup script to avoid opening new windows and handle dynamic ports.
…provements

# Conflicts:
#	backend/analytics/factions.py
#	backend/analytics/ships.py
… with search bar

- Add GET /api/tournaments/locations endpoint returning distinct locations
- Split location filter into 3 dynamic sub-filters (Continent, Country, City)
- Countries update based on selected Continents, Cities based on selected Countries
- Add mini search bar to filter location entries
- Remove duplicate Unknown entries from continent list
…tructure

- Move ShipChassisFilter below Faction on ships, cards, lists, squadrons pages
- Remove accordion expand/collapse; make it a flat static section
- Ship icons in filter inherit text color (uncolored)
- Faction symbols remain colored next to ship names
- Respects specificity hierarchy: Sort By > Faction > Ship Chassis
Closes #37. This PR fixes three critical bugs in the analytics modules:

1. **Tournament filters ignored**: Added centralized location filtering
via �pply_tournament_filters() and updated SQL filters.
2. **Lists count 0**: Added lists aggregation to core.py.
3. **Frontend filters ignored**: Merged main, resolved UI conflicts, and
fixed a Svelte a11y bug (�11y_consider_explicit_label) that caused a 500
error.
# Conflicts:
#	backend/analytics/factions.py
#	backend/analytics/ships.py
…provements

# Conflicts:
#	backend/analytics/ships.py
#	backend/api/ships.py
#	frontend/src/routes/lists/+page.svelte
#	frontend/src/routes/ships/+page.svelte
…ion bugs (#45)

Closes #42.

## Technical Changes
- Replaced SSR data loading in `+page.ts` with reactive client-side
`$effect` fetching to resolve route navigation desync and crashes.
- Replaced hardcoded 'XWA / Analysis Mode' title with the
`<ContentSourceToggle />` component in the header.
- Implemented reactive data fetching based on the global
`filters.dataSource` state to seamlessly switch between XWA and Legacy
data sets without requiring a page reload.
Closes #38

## Summary

Adds the Ships / Chassis page with filtering capabilities and fixes the
hover scaling behavior on ship cards.

## Changes

### Backend
- **New** `backend/routers/ships.py`: FastAPI router exposing `GET
/api/ships` with optional `faction` and `source` query params.
- **Modified** `backend/main.py`: Registers the ships router under
`/api` prefix.
- **Fixed** `backend/utils/xwing_data/core.py`: Corrected `ROOT_DIR`
path (`parents[4]` to `parents[3]`).

### Frontend
- **New** `frontend/src/routes/ships/+page.svelte`: Ships page with
chassis filter dropdown, faction filter, responsive card grid, and
**hover scale on entire card container** (not inner icon).
- **Modified** `frontend/src/routes/+layout.svelte`: Added navigation
bar with Ships link.
- **Modified** `frontend/vite.config.js`: API proxy to FastAPI backend.

## Technical Rationale

The hover scaling fix places `transform: scale(1.06)` on the outer
`.ship-card` container rather than inner icon wrappers, ensuring the
entire card elevates uniformly on hover.
# Conflicts:
#	frontend/src/routes/squadrons/+page.svelte
Closes #43.

- Alphabetized SortSelector options list.
- Changed SVG arrows to use distinct upward/downward pointing icons.
- Updated Squadrons page to use SortSelector component.
- Used getFactionLabel instead of raw faction key in SquadronRowCard.
Removes remaining garbage files and logs from main.
Closes #44. Identified 6 missing ship icons in xwing-miniatures.css by
comparing with JSON data. Added mappings for ieininterceptor,
delta7baethersprite, cr90corelliancorvette, iesebomber, and
upsilonclassshuttle. Trident remains without icon as per user feedback.

---------

Co-authored-by: Francesco Esposito <95753785+Francespo@users.noreply.github.com>
…57)

## Description
This PR fixes the accidental creation of a local font directory in the
frontend and establishes a single source of truth using a symlink.

- Migrated centered xwing-miniatures.css to
external_data/xwing-miniatures-font/dist/.
- Removed local rontend/static/fonts/xwing-miniatures-font/ directory.
- Created a directory junction (symlink) pointing to the source in
external_data.
- Squashed branch history into a single clean commit.

Co-authored-by: Francesco Esposito <95753785+Francespo@users.noreply.github.com>
Closes #52. \n\n### Changes Made:\n- **Standardized Labeling**: All
unknown tournament formats and scenarios now use the label 'Unknown'.\n-
**Fixed UNK Badges**: Verified that unknown formats correctly display
the 'UNK' badge in the Tournament Browser list.\n- **Sidebar UI
Polish**:\n - Restored horizontal dividers between all major filter
sections.\n - Fixed double divider issue when Active Filters list is
empty.\n - Restored bottom borders for accordion items.\n - Standardized
vertical spacing across all sections (Date, Location, Format, Platform,
Search, and Sort) by removing redundant margins and padding for a clean,
contiguous look.

---------

Co-authored-by: Francesco Esposito <95753785+Francespo@users.noreply.github.com>
Francespo and others added 22 commits March 24, 2026 18:10
Fixes #97.

Removes the forced left-column scrolling on the Support page by keeping
the desktop layout within the viewport and moving scrollbar styling to a
shared `.custom-scrollbar` rule. Mobile stays in the single-column flow.
## Summary

Make faction presentation consistent in the dashboard by showing full
faction names in the Faction Performance tooltip and rendering faction
badges through the shared glyph helpers so Resistance displays reliably.

Fixes #95

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#108)

This PR adds a **SQLite wrapper** for offline scraper testing, improves
the Longshanks and Rollbetter scrapers, fixes the missing `winner_id` in
match records, and updates the GitHub Action to support a SQLite-only
run mode.

- **`backend/scripts/scrape_tournaments_sqlite.py`** — wrapper that sets
`DATABASE_URL` to a local SQLite file before importing the main scraper.
Enables offline testing without Postgres. Usage:
  ```bash
  python -m backend.scripts.scrape_tournaments_sqlite \
    --sqlite-path scraped.db \
    --platform longshanks+rollbetter \
    --time-range 7
  ```

- **`scrape_tournaments.py`** — added `--tournament-url` flag for
scraping individual URLs directly (supports Rollbetter, Longshanks, and
ListFortress). Added `--tournament-url` support for benchmark
validation.
- **`rollbetter_scraper.py`** — scoped match table selection to the
active tab panel and added a `wait_for_selector` before reading round
data. This fixes several rounds that previously reported "No match table
found".
- **`longshanks_scraper.py`** — replaced jQuery `trigger(change)` with
the sites own `load_games()` helper (which is how the page actually
loads match data). Scoped `.results` lookups to the `#games` container.
Fixed date parsing to use the start date from Longshanks date ranges.

- **`save_tournament_data`** — `winner_id` was never set when converting
match dicts to `Match` objects. Now resolves `winner_name_temp` against
the player name map to populate the foreign key. **All 20 matches in the
validation scrape now have a non-null `winner_id`** (previously 0).

- **`scrape_tournaments.yml`** — added `none` as an environment option
(SQLite-only, no Postgres). Exposed `upload_sqlite_artifact` as an input
toggle. Postgres writes only occur for `prod`/`dev`. When `environment:
none`, uses the SQLite wrapper.

- ✅ Local SQLite scrape of 10 benchmark tournaments matches expected
counts (Rollbetter events match exactly; Longshanks now captures
**more** matches thanks to the `load_games()` fix — previously missed
rounds)
- ✅ GH Action ran successfully against **dev** Postgres (8 new
tournaments from Apr 15–30, grew DB from 604 → 612)
- ✅ GH Action correctly uses `DEV_DATABASE_URL` secret when
environment=dev
- ✅ SQLite artifact uploaded as expected
- ✅ `winner_id` now correctly populated in all match records
- ✅ Local scrape of Apr 1–7 produced 5 tournaments, 26 players, 36
matches across both platforms

Closes # (no issue linked)

---------
@m3tacron-dev-prod

m3tacron-dev-prod Bot commented May 24, 2026

Copy link
Copy Markdown

The preview deployment for francespo/m3tacron:dev is ready. 🟢

Open backend | Open frontend | Open Build Logs | Open Application Logs

Last updated at: 2026-05-24 21:22:55 CET

@Francespo
Francespo force-pushed the copilot/cache-fix-2026-05-24 branch from a37825c to 25a937c Compare May 24, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants