← Independent Projects

Mobile / Fintech

Visual Kapital

A personal asset tracking application bringing financial dashboards, external data integrations, subscriptions, and portfolio analysis into a Kotlin Multiplatform product shipped on Android.

Watch the product demo ↗
Context
Independent product / Android release
Delivery
Android application

Engineering scope

Engineering Scope

Stack: Kotlin Multiplatform · Compose · Room · Ktor · RevenueCat

Inspect the source ↗

Visual Kapital is a personal asset-tracking application built with Kotlin Multiplatform and shipped on Android. It combines financial dashboards, stored holdings, market data and subscriptions, with shared Kotlin code for caching, UI state and portfolio calculations.

Released on Android. The repository also contains iOS source; portfolio calculations use approximations described below.

01 / Shared code

Share Kotlin code and isolate platform setup

Portfolio data, presentation and subscription behavior should not diverge between platform implementations. Database builders and HTTP engines still depend on the target environment.

I worked within the shared Kotlin Multiplatform and Compose application, where commonMain holds reusable code and Koin connects repositories, Room, Ktor and ViewModels. Platform-specific database builders and HTTP engines stay in their respective source sets.

Database builders, HTTP engines and application entry points still need platform-specific setup. Shared code reduces duplication while leaving those integration details in the Android and iOS source sets.

02 / Quote caching

Cache quotes and refresh stale symbols

A dashboard needs market prices alongside locally stored holdings. Fetching every quote on every read increases network dependence, while treating cached values as permanently current misrepresents freshness.

My integration work used FinancialRepository to coordinate remote prices and Room data. The batch path reuses fresh cached symbols, fetches stale or missing ones and stores the returned quotes with timestamps, reducing repeated requests for the dashboard.

The batch path uses a five-hour cutoff; the single-quote path accepts a same-day cache entry. Those different policies affect the age of prices shown in different views and need to be considered when interpreting a valuation.

03 / Dashboard state

Derive dashboard totals from holdings and quotes

Portfolio positions and external quotes have different lifecycles. Recomputing totals independently in each composable would scatter valuation rules and create inconsistent views.

For the financial dashboard, I worked with HomeViewModel to collect portfolio changes through Flow, load quotes and derive rows, totals and category distribution. HomeUiState carries the result into Compose; missing quotes fall back to the holding’s purchase price.

Falling back to purchase price keeps the holding visible when a quote is missing, but the resulting total is not a current market valuation. The distinction matters whenever the dashboard combines fresh prices with fallback values.

04 / Subscriptions

Load offerings and restore premium access

Premium access depends on offerings, purchase outcomes and restored entitlements. A local button state cannot independently establish that a subscription exists.

I worked on the RevenueCat subscription integration, covering offerings, package selection, customer entitlements and purchase restoration. PremiumViewModel exposes loading, errors and premium state through MutableStateFlow and maps the selected offer back to its purchasable package.

The displayed purchase state has to follow provider callbacks and entitlement updates. Loading offerings, completing a purchase and restoring an existing subscription are separate flows with their own errors.

05 / Portfolio analysis

Calculate exposure and explain portfolio suggestions

Exposure and risk indicators combine holdings with profiles, quotes and historical prices. Keeping those calculations in one place makes their assumptions easier to follow.

My work included the premium dashboard and analysis features. The ViewModel fetches data with coroutines, aggregates exposure by sector, geography and asset class, and calculates concentration and risk indicators. The rebalancing suggestions in this implementation follow explicit rules over those results.

Volatility and diversification estimates use simplified formulas and fallback values. They provide a summary of the portfolio, with results that depend on the available price history and the assumptions in those calculations.

Evidence & further reading

Technical references