diff --git a/README.md b/README.md new file mode 100644 index 0000000..54edaef --- /dev/null +++ b/README.md @@ -0,0 +1,155 @@ +# 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`