docs: add Sub2API monitor design
This commit is contained in:
118
docs/plans/2026-06-23-sub2api-monitor-design.md
Normal file
118
docs/plans/2026-06-23-sub2api-monitor-design.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# Sub2API Monitor Android Widget Design
|
||||||
|
|
||||||
|
Date: 2026-06-23
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Build a runnable Android prototype for monitoring Sub2API from a home-screen widget.
|
||||||
|
The first version focuses on the full user flow, visual layout, local-only
|
||||||
|
configuration, simulated monitoring data, and a data layer that can later be
|
||||||
|
replaced by real Sub2API admin APIs.
|
||||||
|
|
||||||
|
## Recommended Approach
|
||||||
|
|
||||||
|
Use native Android with Kotlin:
|
||||||
|
|
||||||
|
- Jetpack Compose for the in-app configuration screen.
|
||||||
|
- Jetpack Glance for the Android home-screen widget.
|
||||||
|
- DataStore for local configuration and cached widget state.
|
||||||
|
- A repository interface with a mock data source for the first version.
|
||||||
|
|
||||||
|
This keeps the widget integration native, makes the UI fast to iterate on, and
|
||||||
|
leaves a clean replacement point for the real network integration.
|
||||||
|
|
||||||
|
## App Configuration
|
||||||
|
|
||||||
|
The app provides one configuration screen with:
|
||||||
|
|
||||||
|
- Sub2API base URL input.
|
||||||
|
- Admin key input, hidden as a password field.
|
||||||
|
- Automatic refresh interval setting.
|
||||||
|
- Test connection action.
|
||||||
|
- Save configuration action.
|
||||||
|
|
||||||
|
The admin key is stored only on the device and is never rendered in the widget.
|
||||||
|
For the prototype, test connection uses the mock data source and reports a
|
||||||
|
success or failure result.
|
||||||
|
|
||||||
|
## Widget Experience
|
||||||
|
|
||||||
|
When no configuration exists, the widget shows:
|
||||||
|
|
||||||
|
> 请先配置 Sub2API
|
||||||
|
|
||||||
|
When configured, the widget renders as a phone home-screen monitoring dashboard:
|
||||||
|
|
||||||
|
- White translucent rounded card.
|
||||||
|
- Sub2API title.
|
||||||
|
- Last update time.
|
||||||
|
- Manual refresh button.
|
||||||
|
- Highlighted blocks for today's tokens, today's cost, today's request count,
|
||||||
|
and service status.
|
||||||
|
- Secondary metrics for average latency, RPM, TPM, active keys, and users.
|
||||||
|
- Recent 5 call records.
|
||||||
|
- Model cost TOP4.
|
||||||
|
- Lifetime tokens and lifetime cost.
|
||||||
|
|
||||||
|
The visual hierarchy emphasizes today's usage, today's cost, recent calls, and
|
||||||
|
model ranking.
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
The UI consumes a `Sub2ApiSnapshot` style state object containing:
|
||||||
|
|
||||||
|
- `lastUpdatedAt`
|
||||||
|
- `todayTokens`
|
||||||
|
- `todayCost`
|
||||||
|
- `todayRequests`
|
||||||
|
- `averageLatencyMs`
|
||||||
|
- `rpm`
|
||||||
|
- `tpm`
|
||||||
|
- `serviceStatus`
|
||||||
|
- `activeKeyCount`
|
||||||
|
- `userCount`
|
||||||
|
- `recentCalls`
|
||||||
|
- `modelTop`
|
||||||
|
- `totalTokens`
|
||||||
|
- `totalCost`
|
||||||
|
- optional error state
|
||||||
|
|
||||||
|
The widget should not bind directly to the mock implementation. It should depend
|
||||||
|
on repository-level state so a future real API client can provide the same
|
||||||
|
snapshot contract.
|
||||||
|
|
||||||
|
## Data Flow
|
||||||
|
|
||||||
|
1. The user opens the app and saves URL, admin key, and refresh interval.
|
||||||
|
2. Configuration is stored locally in DataStore.
|
||||||
|
3. The widget reads configuration and cached snapshot state.
|
||||||
|
4. Manual refresh invokes a widget action that asks the repository to fetch data.
|
||||||
|
5. Automatic refresh is represented through a scheduler boundary and can be
|
||||||
|
backed by WorkManager.
|
||||||
|
6. On success, the latest snapshot becomes the last known good snapshot.
|
||||||
|
7. On failure, the widget records the error state but keeps showing the previous
|
||||||
|
successful snapshot.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- No configuration: show the setup prompt.
|
||||||
|
- Fetch failure with previous data: show the previous data plus an error status.
|
||||||
|
- Fetch failure without previous data: show a concise error state.
|
||||||
|
- Admin key is never shown in widget text or logs.
|
||||||
|
|
||||||
|
## Testing Plan
|
||||||
|
|
||||||
|
Focus tests on behavior that should survive the later real API integration:
|
||||||
|
|
||||||
|
- Missing configuration maps to the unconfigured widget state.
|
||||||
|
- Saved configuration can be loaded.
|
||||||
|
- Mock repository returns complete monitoring data.
|
||||||
|
- Failed refresh preserves the last successful snapshot.
|
||||||
|
- Formatting functions render tokens, currency, latency, RPM, TPM, and time
|
||||||
|
consistently.
|
||||||
|
|
||||||
|
## Future Real API Integration
|
||||||
|
|
||||||
|
Add a real `Sub2ApiRemoteDataSource` behind the same repository contract. The
|
||||||
|
widget, Compose screen, and cached state should not need structural changes.
|
||||||
|
|
||||||
Reference in New Issue
Block a user