Offline-first personal finance app focused on:
- zero credit-card behavior
- tight monthly budget control
- visibility of subscriptions, installments, and recurring costs
- long-term planning without cloud dependency
This repository currently targets Android + Desktop, with shared business logic in Kotlin Multiplatform.
The app is functional and includes:
- month-by-month budget editing (inline in the budget card)
- expense tracking with recurring flag (
ONE_TIME/MONTHLY) - subscriptions and installment plans
- payment schedule generation for commitments
- future-month navigation and planning
- month rollover support with recurring copy behavior
- planning screen with forecast and quick scenarios
- profile/settings with language/theme/guardrails
- local DB migration hardening for legacy schema upgrades
shared- Clean Architecture split:
domain(models, repositories, use cases, rules)data(SQLDelight repositories)presentation(MainStore, immutableMainState)app(Compose UI/theme/i18n)
- Koin shared DI
- SQLDelight schema + migrations
- Domain tests
- Clean Architecture split:
androidApp- Android host app (
MainActivity) - Android SQLDelight driver wiring
- startup DB schema hardening for old installs
- Android host app (
desktopApp- Desktop host app
- Kotlin Multiplatform + Compose Multiplatform
- Koin (DI)
- SQLDelight (persistence)
- kotlinx-datetime
- kotlinx-serialization
- Coroutines + Flow
- Money stored as
Longcents. - No negative amounts.
- No-credit-card mindset: expense payment method flow remains debit-like in app UX.
- Safety guard: "No new installments" lock (default ON).
- Commitments (
subscriptions + installments) tracked separately from discretionary spend. - Future months are navigable/editable.
- Month rollover behavior:
- creates missing budget month
- copies previous month income when target month is new
- copies previous month allocations if target month has none
- copies recurring expenses (
MONTHLY, non-schedule-linked), deduplicated
- Forecast includes:
- commitments (subscriptions/installments)
- recurring expenses
- projected spend + projected free balance
Top-level layout:
- Header: app title + current month + previous/next month controls (hidden on
Perfil). - Bottom navigation:
Resumo,Despesas,Planejamento,Perfil.
- Orçamento mensal (Budget Hero):
- inline editable budget amount
- progress bar (
used / budget) - mini-metrics:
Despesas,Cobranças,Restante
- Comparação mensal:
- compares current month vs previous month
- deltas for expenses and billings
- Ação de mês:
- button to advance to next month
Read-first cards (lists):
- Nova despesa card with “Adicionar” action
- Assinaturas list card
- Parcelamentos list card
- Histórico list card (recent expenses with date/category metadata)
Write is dialog-based:
- Add Expense dialog: description, amount, category, recurring switch
- Add Subscription dialog: description, amount, billing day, category
- Add Installment dialog: description, monthly amount, installments count, category
- New Category dialog from category picker (
+ Nova categoria)
- Simulador:
- toggle to cancel highest subscription
- slider for recurring-cost reduction (%)
- configurable safety target (desired monthly leftover)
- Impacto do cenário:
- average monthly delta and 12-month delta
- Previsão mensal:
- future months with projected Margin (
income - projected spend) - direct comparison against safety target (
Above target/Below target+ delta)
- future months with projected Margin (
- Eventos de alívio:
- installment-end milestones and freed monthly cash
- Projeção de meta:
- goal amount + monthly contribution inputs
- projected completion month
- Guardrails: no-new-installments switch
- Idioma:
system/PT/EN - Tema:
system/light/dark - Google:
- Sign in/out with Google
- Drive sync action (uploads encrypted-transport backup file to app-private Drive space)
- account/sync status and latest sync timestamp
- Release info:
- app version (tag-propagated)
- open-source libraries/licenses dialog
- Workflows:
.github/workflows/ci-cd-quality-gate.yml(mainpushes).github/workflows/ci-cd-release.yml(manual unified release: Android + Windows + optional iOS)
- Trigger:
- manual
workflow_dispatchonly - choose a tag in
Use workflow from(no manual tag input) - inputs:
skip_quality_gate(true/false)build_android(true/false)build_windows(true/false)build_linux(true/false)build_macos(true/false)build_ios(true/false)
- manual
- Outputs published to GitHub Release:
- Android (optional): release APK (
androidApp) - Windows (optional): desktop artifacts (
.msi+ portable zip + optional.exe) - Linux (optional): desktop artifacts (
.deb+ portable.tar.gz) - macOS (optional): desktop artifacts (
.dmg+ portable.zip) - iOS (optional): signed
.ipa
- Android (optional): release APK (
- Version source priority:
-Papp.version=...APP_VERSIONenv var- GitHub tag (
GITHUB_REF_NAME) - fallback
1.0.0
- Android:
versionName= resolved versionversionCodederived from SemVer (1.2.3 -> 10203) unless-Papp.versionCodeis provided
- Desktop:
nativeDistributions.packageVersion= resolved version (withoutvprefix)
- Runtime/Profile:
sharedgeneratesBuildInfo.VERSION_NAMEandBuildInfo.VERSION_CODEused in UI
Android:
GOOGLE_SERVICES_JSON_B64(base64 ofgoogle-services.json)GYST_KEYSTORE_B64(base64 of.jks)GYST_KEYSTORE_PASSWORDGYST_KEY_ALIASGYST_KEY_PASSWORD
Desktop (required when build_windows=true or build_linux=true):
GYST_DESKTOP_OAUTH_JSON_B64(base64 of Desktop OAuth JSON)
iOS (required only when build_ios=true):
IOS_CERTIFICATE_P12_B64IOS_CERTIFICATE_PASSWORDIOS_PROVISIONING_PROFILE_B64IOS_KEYCHAIN_PASSWORDIOS_EXPORT_OPTIONS_PLIST_B64IOS_TEAM_IDIOS_BUNDLE_IDENTIFIER(optional; defaults tocom.samluiz.gyst)
Notes:
google-services.jsonis injected at workflow runtime. Do not commit this file.- iOS signing assets are injected and used only inside CI job runtime.
- PT and EN strings via
rememberStrings(...). - PT copy is currently being refined for punctuation/accents.
- Main schema:
shared/src/commonMain/sqldelight/com/samluiz/gyst/db/finance.sq
- Migration:
shared/src/commonMain/sqldelight/com/samluiz/gyst/db/2.sqm
- Android startup hardening:
- validates/repairs legacy
expensecolumns before driver init - avoids duplicate-column migration crashes from partial old states
- validates/repairs legacy
./gradlew :desktopApp:run- In Google Cloud Console, create an OAuth 2.0 Client ID of type Desktop app.
- Enable Google Drive API.
- Save the downloaded JSON as:
~/.gyst/google/desktop_oauth_client.json(recommended), or- set env var
GYST_GOOGLE_DESKTOP_OAUTH_PATHpointing to that file.
- Open
Profilein Desktop app, sign in with Google, then use Sync data / Restore backup.
Notes:
- Desktop sync uses the same private Drive scope (
drive.appdata) as Android. - OAuth token data is stored locally under
~/.gyst/google/tokens.
From Android Studio:
- Select
androidApprun configuration - Choose emulator/device
- Run
From terminal:
./gradlew :androidApp:installDebugIf needed:
./gradlew :androidApp:uninstallDebug :androidApp:installDebug- In Google Cloud Console, create an OAuth 2.0 Client ID (Android) for package
com.samluiz.gystand your signing SHA-1/SHA-256. - Enable Google Drive API.
- No broad file scope is used; app requests only
drive.appdata(app-private folder). - Run the app and authenticate in
Perfilbefore tapping sync.
Local iOS app host exists in iosApp/ and release automation is available in CI.
To enable iOS release in CI:
- Prepare Apple signing assets (distribution
.p12, provisioning profile, export options plist). - Add iOS secrets listed above.
- Trigger
CI/CD Releasewithbuild_ios=true.
Current iOS defaults:
iosApp/Configuration/Config.xcconfigPRODUCT_NAME=GystPRODUCT_BUNDLE_IDENTIFIER=com.samluiz.gyst
Run shared desktop-compatible tests:
./gradlew :shared:desktopTestNote: :shared:allTests may require valid Android SDK configuration in your environment.
- Local-only storage (offline-first).
- Seed data is initialized on first launch (
SeedDataInitializer). - If Android build fails with SDK path issues, set
local.properties(sdk.dir=...) orANDROID_HOME. - Secrets policy:
- never commit
google-services.jsonor.jks - keep
**/google-services.jsonin.gitignore - use GitHub Actions Secrets for CI/CD injection
- never commit
- Privacy Policy:
docs/legal/privacy-policy.md - Terms of Service:
docs/legal/terms-of-service.md - Publication notes for Google Console:
docs/legal/README.md
- Migrate deprecated datetime APIs (
monthNumber,dayOfMonth, deprecatedInstantalias usage). - Continue UI/accessibility polish and chart/report depth.
This project is licensed under the GNU General Public License v3.0 (GPL-3.0-or-later). See LICENSE for details.