# Implausibly An open-source Android dashboard app for self-hosted [Plausible Analytics](https://plausible.io/) CE. The existing third-party apps are all closed-source. If you're running self-hosted Plausible specifically because you care about control and transparency, a closed-source dashboard app is an odd fit. Implausibly is: - **Fully open source** (GPL-3.0) — audit it, fork it, contribute - **Self-hosted first** — configurable base URL, no Plausible.io assumptions - **No account or subscription** — just your Plausible API key - **Zero telemetry** — no analytics in the analytics app - **No Google Play Services** — pure AndroidX, F-Droid compatible ## Screenshots *Coming soon — the app is functional but screenshots haven't been captured yet.* ## Features - **Multi-instance support** — connect to multiple Plausible servers - **Full dashboard** — visitors, pageviews, bounce rate, visit duration - **Visitor chart** — custom Canvas line chart with area fill - **Dimension breakdowns** — top sources, pages, countries, devices, browsers, OS - **Date range selector** — today, 7d, 30d, 6mo, 12mo - **Pull-to-refresh** — swipe down to reload - **Caching** — SQLDelight cache with TTL per date range; shows cached data instantly on launch - **Encrypted API keys** — stored via EncryptedSharedPreferences (AES-256-GCM) - **Clone instances** — duplicate an instance config to track a different site with the same credentials - **Smart navigation** — remembers your last-viewed dashboard and opens directly to it - **Material 3** — light and dark theme ## Requirements - Android 8.0+ (API 26) - A self-hosted Plausible CE instance with API v2 enabled - An API key (or a public shared link) ## Building ```bash # Clone git clone ssh://git@kode.naiv.no:2222/olemd/implausible.git cd implausible # Build debug APK ./gradlew assembleDebug # Run unit tests ./gradlew test # Install on connected device ./gradlew installDebug # Lint ./gradlew lint ``` Requires JDK 17. The Gradle wrapper is included — no separate Gradle installation needed. ## Architecture Four-layer unidirectional data flow: ``` UI (Jetpack Compose + Material 3) | observes StateFlow ViewModel (per screen, sealed UiState) | calls Repository (cache-first, coordinates API + DB) | delegates to Remote (Ktor) + Local Cache (SQLDelight) ``` Everything goes through one API endpoint: `POST /api/v2/query`. The dashboard fires 8 concurrent queries per load. ### Tech stack | Component | Library | |-----------|---------| | UI | Jetpack Compose + Material 3 | | HTTP | Ktor (OkHttp engine) | | Serialization | kotlinx.serialization | | Local DB | SQLDelight | | DI | Hilt | | Preferences | DataStore | | Secrets | EncryptedSharedPreferences | | Charts | Custom Canvas (no library) | ### Package structure ``` no.naiv.implausibly/ data/ remote/ Ktor API client, DTOs local/ SQLDelight generated code repository/ StatsRepository, InstanceRepository, SiteRepository, CacheManager ApiKeyStore Encrypted key storage AppPreferences DataStore preferences domain/model/ Domain models (decoupled from API/DB) di/ Hilt modules ui/ setup/ Instance onboarding sites/ Site list / management dashboard/ Stats dashboard, components, sections navigation/ NavHost, routes theme/ Material 3 theme common/ Shared UI (UiState, LoadingIndicator, ErrorState) ``` ## API The app uses the [Plausible Stats API v2](https://plausible.io/docs/stats-api). Rate limit is 600 requests/hour — with 8 queries per dashboard load, that's ~75 refreshes/hour. ### Caching Cache key = SHA-256 hash of `(instanceId, siteId, dateRange)`. TTL varies: | Date range | Cache TTL | |------------|-----------| | Realtime | Never cached | | Today | 5 min | | 7d, 30d | 30 min | | 6mo, 12mo | 2 hours | On app open: show cached data immediately, refresh in background. ## Roadmap ### Phase 2 (planned) - Filter system (bottom sheet, combinable filters) - Material You dynamic color - Landscape layout - Realtime polling - Sites API auto-discovery - Custom date ranges - F-Droid submission ### Phase 3 (future) - Comparison mode (this period vs previous) - Goal conversions - Segments support - Home screen widgets (Glance) ## License [GPL-3.0-only](LICENSE) This means any distributed fork must also be open source under the same license. All dependencies are GPL-compatible (Apache 2.0, MIT). ## Contributing Contributions welcome. The project is hosted on Forgejo at `kode.naiv.no`. All source files must include the SPDX header: `// SPDX-License-Identifier: GPL-3.0-only`