d0b1529c3f
Native Kotlin + Jetpack Compose (Material 3) client for the BountyBoard platform. Cookie-session + CSRF auth with a configurable base URL, the full role-based feature set (admin / consultant / developer), local + OIDC SSO sign-in, and background push notifications (WorkManager poll) for alerts and messages. Bundles the app's editorial "ledger" design system and the original Fraunces / Schibsted Grotesk / Spline Sans Mono typefaces. Includes a prebuilt debug APK (BountyBoard-debug.apk) for side-loading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
102 lines
5.1 KiB
Markdown
102 lines
5.1 KiB
Markdown
# Bounty Board — Android
|
||
|
||
A native Android client for the [Bounty Board](../BountyBoard) consulting work-management
|
||
platform. Built with **Kotlin + Jetpack Compose (Material 3)**, it covers the full
|
||
role-based feature set — admin, consultant, and developer — over the server's
|
||
cookie-session + CSRF API.
|
||
|
||
The visual identity mirrors the web app's "ledger / bounty-poster" aesthetic: warm
|
||
paper grounds, brown/amber ink, hard offset shadows (no blur), 2px corners, ◈ bounty
|
||
chips, and the original **Fraunces / Schibsted Grotesk / Spline Sans Mono** typefaces
|
||
(bundled, instanced from the web app's variable fonts).
|
||
|
||
## First run
|
||
|
||
The app opens on a **Login** page. The default server is
|
||
`https://bountyboard.anypreta.com/`. Expand **Server** on the login screen to point the
|
||
app at any other Bounty Board instance — the base URL is persisted and every request is
|
||
retargeted at runtime. Sign in with email/password, register a developer account, or use
|
||
"Forgot password". A forced password change is handled automatically when the server
|
||
requires it.
|
||
|
||
## Features
|
||
|
||
- **Auth** — login (with configurable base URL), self-registration, forgot password,
|
||
forced password change. Session + CSRF are handled transparently by a persistent
|
||
cookie jar and a double-submit interceptor.
|
||
- **Developer** — bounty board with search / project / min-bounty / sort filters and
|
||
claim flow; My Tasks kanban (Assigned · In progress · In review · Done); per-task
|
||
start / submit / abandon / withdraw; comments; time logging; metrics dashboard;
|
||
leaderboard.
|
||
- **Consultant** — atomization board (grouped by project, status filters, quick
|
||
publish); subdivide / extend / edit / publish; reviews queue with an acceptance-
|
||
criteria checklist; approve / decline claims; assign-to-AI; developer pool management;
|
||
metrics.
|
||
- **Admin** — users (roles, disable, force-reset, delete); projects/customers wizard
|
||
(per-system credential fields, test connection, sync now); runtime settings; audit
|
||
log; live service-status panel.
|
||
- **Shared** — task detail with full role-aware action bar and timeline; real-time-feel
|
||
messaging (DMs, group/project conversations, image + file attachments, read receipts);
|
||
notification center with deep links; profile (avatar upload, bio/contact, theme
|
||
picker with all six themes, leaderboard opt-out, sign-out-everywhere); public profile
|
||
cards.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
data/ AppContainer (manual DI) · Repository · SessionManager · SettingsStore (DataStore)
|
||
net/ Retrofit ApiService · PersistentCookieJar · CSRF + dynamic-host interceptors · DTOs
|
||
model/ wire data classes
|
||
ui/
|
||
theme/ palette (6 themes) · typography · 2px shapes · hard-offset shadow modifier
|
||
components/ BBButton · BBCard · BountyChip · StatusBadge · BBAvatar · BBTextField · dialogs · TaskCard
|
||
nav/ AppRoot (bootstrap/auth gate) · MainShell (role drawer + NavHost) · Routes
|
||
auth/ developer/ consultant/ admin/ task/ messaging/ shared/ profile/ feature screens + ViewModels
|
||
```
|
||
|
||
- **Networking**: OkHttp + Retrofit (Gson). The base URL is dynamic — a host-selection
|
||
interceptor rewrites scheme/host/port per request, so changing the server on the login
|
||
screen takes effect immediately without rebuilding Retrofit. Coil shares the OkHttp
|
||
stack so `/files/{id}` image loads carry the session cookie.
|
||
- **Auth**: cookie-session only. `bb_session` (httpOnly) and `bb_csrf` are persisted in a
|
||
`PersistentCookieJar`; mutating requests echo `bb_csrf` into the `X-CSRF-Token` header.
|
||
- **State**: ViewModels expose Compose `mutableStateOf` snapshots; screens are stateless
|
||
and driven by `LocalAppContainer`.
|
||
|
||
## Building
|
||
|
||
Requirements: **JDK 17 or 21** (AGP 8.5 does not support newer JDKs as the build JVM),
|
||
the Android SDK with **platform 34** and **build-tools 34.0.0**, and Gradle 8.9+.
|
||
|
||
The easiest path is to open the project in **Android Studio** (Koala / 2024.1+), let it
|
||
sync, and Run.
|
||
|
||
From the CLI (the Gradle wrapper is included; point `JAVA_HOME` at a JDK 17–21):
|
||
|
||
```bash
|
||
cd BountyBoard_android
|
||
JAVA_HOME=/path/to/jdk-21 ./gradlew assembleDebug # APK → app/build/outputs/apk/debug/
|
||
JAVA_HOME=/path/to/jdk-21 ./gradlew installDebug # install on a connected device/emulator
|
||
```
|
||
|
||
A prebuilt debug APK is committed at **`BountyBoard-debug.apk`** in the project root —
|
||
`adb install -r BountyBoard-debug.apk` to side-load it directly.
|
||
|
||
`local.properties` already points `sdk.dir` at `~/Android/Sdk`; adjust if your SDK lives
|
||
elsewhere. The app allows cleartext traffic so you can point it at a local `http://`
|
||
dev server.
|
||
|
||
### Sign-in
|
||
|
||
Local email/password **and** OIDC SSO both work. "Sign in with SSO" opens the server's
|
||
OIDC redirect flow in an in-app browser; once the IdP redirects back, the session cookies
|
||
are captured into the app's HTTP stack and you're signed in. If the server has no OIDC
|
||
configured, the app reports that instead of failing silently.
|
||
|
||
## Notes
|
||
|
||
- `minSdk 26`, `targetSdk 34`. No proprietary services; the launcher icon, splash, and
|
||
fonts are all bundled.
|
||
- The server contract is documented in `../BountyBoard/api/openapi.yaml` and
|
||
`../BountyBoard/specification.md`; this client implements the §6 application API.
|