commit 9827439fd21c1901ef9fc6135a37f92b3d497597 Author: Mimikko-zeus Date: Tue Jun 23 10:16:28 2026 +0800 docs: add Sub2API monitor design diff --git a/docs/plans/2026-06-23-sub2api-monitor-design.md b/docs/plans/2026-06-23-sub2api-monitor-design.md new file mode 100644 index 0000000..a521e7d --- /dev/null +++ b/docs/plans/2026-06-23-sub2api-monitor-design.md @@ -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. +