This is a Kotlin Multiplatform project targeting Android, iOS, Web, Desktop.
-
/composeAppis for code that will be shared across your Compose Multiplatform applications. It contains several subfolders:commonMainis for code that’s common for all targets.- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
iosMainwould be the right folder for such calls.
-
/iosAppcontains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
You're gonna need it for the local development. I'd recommend downloading Docker Desktop.
This is needed for modifying the db schema and having a proper local development db as well. How to install: you can check their website, but tldr:
Use Homebrew:
brew install supabase/tap/supabaseThey recommend using Scoop, but that's another dependency. Use whatever works for y'all.
We use IntelliJ Idea, but Android Studio works just as good (apart from being somewhat slower in my experience).
0 - Make sure you have a .env.local file with the appropriate values. See .env.example for some of the values, as well as the structure
1 - Start Docker Desktop
2 - Start the local Supabase environment:
supabase start3 - (Optional) If you want to reset the DB to use the seed data:
supabase db resetThen, you can visit the Studio link in your console, and navigate to the Table Editor to view your local data (for me, it's http://127.0.0.1:54323/project/default/editor/)
4 - Run the desktop app with Compose Hot Reload:
./gradlew :composeApp:hotRunDesktop --auto -Psupabase.env=localThis uses the desktop JVM target and automatically reloads UI changes when you save files.
Must have:
These platforms are the primary focus and must remain fully supported.
- Web (WasmJS)
Nice to have:
These platforms are currently working, but they are secondary because the web app is available to everyone. If support breaks or becomes too expensive to maintain, it is acceptable to drop the platform. When that happens, update this file to clearly mark the platform as unsupported or broken.
- Desktop (JVM)
- Android
We don't have it anywhere where it would be publicly accessible, but if you have Teams access, you can browse it here
e.g ledgers, editing events after they happened, etc
TBD
- We don't score the teams' scores explicitly - they can be calculated easily from the ledger at any time. This approach is more failsafe
- Points vs money:
teams do not have a separate mutable "money" balance.
A team's shop budget is derived from gameplay as:
current score minus the total price of already purchased shop items.
In practice, successful
TasksLedgerrows count as score,Teams.additionalScoreAwardedstores signed manual score corrections, and shop affordability is checked against that derived budget.
We use Netlify to host our frontend.
The web app builds to composeApp/build/dist/wasmJs/productionExecutable.
This repository includes a wrangler.jsonc with pages_build_output_dir pointing at that directory
The shared client config is generated with BuildKonfig from Gradle
properties or environment variables at build time. The browser app does not load .env files directly at runtime.
This repo's Gradle build reads .env.local and .env.production and passes their values into BuildKonfig.
Local Supabase is still the default so development builds do not accidentally write to the hosted project unless you explicitly opt into prod.
Default local Supabase configuration:
- URL:
http://127.0.0.1:54321 - Key: the Supabase CLI default local
anonkey
Build or run against local Supabase:
./gradlew :composeApp:wasmJsBrowserDevelopmentRun -Psupabase.env=localUse the desktop hot-reload target for faster UI iteration when useful, but always verify shared UI changes in the web
build as well. The wasmJsBrowserDevelopmentRun workflow gives you the web version for real browser testing, but it
does not support Compose Hot Reload like the desktop JVM target does.
Build or run against production only when intentional:
./gradlew :composeApp:wasmJsBrowserDevelopmentRun -Psupabase.env=prodSupported overrides:
-Psupabase.env=local|prodorSUPABASE_ENV-Psupabase.url=...orSUPABASE_URL-Psupabase.key=...orSUPABASE_KEY-Pbatkabank.apiBaseUrl=...orBATKABANK_API_BASE_URL
Use the public anon or publishable key in client apps. Never use a service_role or secret key in Web, Android,
iOS, or Desktop builds.
The repository includes a GitHub Actions workflow at .github/workflows/supabase-backup.yml that runs daily at
02:00 UTC and can also be started manually from the Actions tab.
It follows the Supabase CLI backup flow and uploads compressed roles, schema, and data dumps into a private
Supabase Storage bucket under database/<timestamp>/.
(The schema and data dumps are scoped to the app's public schema so they can be restored cleanly into an existing
Supabase project without colliding with managed auth or storage rows.)
The following GitHub repository secrets have been configured:
SUPABASE_BACKUP_DB_URL: remote Postgres connection string used bysupabase db dumpSUPABASE_PROJECT_URL: project URL such ashttps://<project-ref>.supabase.coSUPABASE_SECRET_KEY: secret key used to create the bucket if needed and upload files
To restore, download one backup set from Storage, unzip the downloaded zip file, and run the following command with the proper db-url and backup-dir:
scripts/restore-supabase-backup.sh --db-url 'postgres://...' --backup-dir ~/Downloads/supabase-filesOptional flags:
--keep-unzippedto keep.sqlfiles when the backup only contains.sql.gz--with-rolesto applyroles.sqlbefore restoringpublicschema/data
The restore helper only restores the app schema/data from public. This intentionally skips managed
Supabase schemas such as auth and storage, even if those tables are somehow present in a backup file (they shouldn't be).