87 lines
3.0 KiB
Markdown
87 lines
3.0 KiB
Markdown
---
|
|
id: 77c0b897-4124-432f-84de-700ff82dcde1
|
|
type: code_pattern
|
|
title: "Two-phase cached loading pattern for API-heavy screens in Rust TUI"
|
|
tags: [sba-scouting, rust, caching, ratatui, async, tokio, sqlx, standings, api, pattern]
|
|
importance: 0.8
|
|
confidence: 0.8
|
|
created: "2026-03-02T00:33:19.472159+00:00"
|
|
updated: "2026-03-02T02:20:58.504326+00:00"
|
|
relations:
|
|
- target: 1d64c80d-61ec-434f-902a-3a511e2b92c2
|
|
type: RELATED_TO
|
|
direction: outgoing
|
|
strength: 0.71
|
|
edge_id: 971778f6-4161-4ae3-be07-44f5e4645577
|
|
- target: fc4eb194-1b19-4bb7-8b63-97ae30c8a3e0
|
|
type: RELATED_TO
|
|
direction: outgoing
|
|
strength: 0.72
|
|
edge_id: a78f60a1-1597-4b18-835d-c6bc8d97c535
|
|
- target: e5ec55be-ced4-4c30-8390-940b45dc2ed5
|
|
type: RELATED_TO
|
|
direction: outgoing
|
|
strength: 0.7
|
|
edge_id: 8e624197-1bd1-49cd-9082-437551829431
|
|
- target: e1fad787-7de7-4f62-afb7-6df2ffdea1ed
|
|
type: RELATED_TO
|
|
direction: incoming
|
|
strength: 0.9
|
|
edge_id: 4cbd5bef-19ad-4c61-b737-234618b32dba
|
|
- target: 27a1f728-ec90-469c-a6ab-5644d333322f
|
|
type: RELATED_TO
|
|
direction: outgoing
|
|
strength: 0.7
|
|
edge_id: a24de396-42d1-4311-af1b-0d3dbf6f8d7a
|
|
- target: a2d02aea-07fd-4528-8158-f2f42a23a2dd
|
|
type: RELATED_TO
|
|
direction: incoming
|
|
strength: 0.5
|
|
edge_id: b0015c81-b5ab-4972-8811-04dc5ddaebf4
|
|
- target: 346c5a34-3fed-44ff-832a-b0c9eb42ca88
|
|
type: RELATED_TO
|
|
direction: incoming
|
|
strength: 0.8
|
|
edge_id: fbf4a323-421b-4964-ba27-bffd66df6d69
|
|
- target: e1fad787-7de7-4f62-afb7-6df2ffdea1ed
|
|
type: REQUIRES
|
|
direction: outgoing
|
|
strength: 0.85
|
|
edge_id: cb95feca-40ee-4cfb-af50-cd2e1b8844cd
|
|
- target: 1b71b163-b56f-4226-9731-a76ef245e532
|
|
type: RELATED_TO
|
|
direction: incoming
|
|
strength: 0.75
|
|
edge_id: 863714f3-635e-427a-a1fb-499b14b192e8
|
|
---
|
|
|
|
# Two-Phase Cached Loading Pattern
|
|
|
|
## Context
|
|
Implemented for the standings screen in SBA Scout Rust TUI. Should be reused for other API-heavy screens.
|
|
|
|
## Pattern
|
|
|
|
### Phase 1: Instant cache load on mount
|
|
- Load from SQLite cache on `mount()` — instant display
|
|
- Cache table (`standings_cache`) stores JSON blob per season with `fetched_at` timestamp
|
|
- Show "updated Xm ago" indicator to user
|
|
|
|
### Phase 2: Background refresh
|
|
- Spawn background `tokio::task` to fetch from live API
|
|
- Update DB cache after successful fetch
|
|
- Send `StandingsRefreshed` message back to UI via `mpsc::UnboundedSender<AppMessage>`
|
|
- Show spinner while refreshing
|
|
|
|
## Key Implementation Details
|
|
- Use `serde::Serialize` on response types for JSON round-trip through DB (`serde_json::to_string` / `from_str`)
|
|
- Cache table needs: `season` (key), `data_json` (TEXT), `fetched_at` (DATETIME)
|
|
- Handle stale cache gracefully — always show cached data immediately, refresh in background
|
|
|
|
## Critical API Shape Gotcha
|
|
The Major Domo CLI returns bare arrays, but the actual REST API wraps responses:
|
|
```json
|
|
{"count": N, "standings": [...]}
|
|
```
|
|
Always verify real API response shape, not just CLI output. Mismatched deserialization will silently fail or panic.
|