Upgrade and migration
from an older version.
What to do when you move to a new major version: what changes in the database, in the environment variables and in the Firestore documents, and the order to deploy in. Read it before you replace anything in production.
01Which upgrade are you doing?
| You run now | Moving to | What it means | Go to |
|---|---|---|---|
| 2.x, the native Android (Java) app | 4.0.0 | A new project. Nothing is upgraded in place; you set 4.0 up next to your old app and publish it as an update of your store listing. | From 2.x to 4.0 |
| 4.0.x | A later 4.x release | Same project, same data. You merge the new code into your copy and deploy in a fixed order. | Updating within 4.x |
Copy the console's data (admin/data/, or dump your Postgres) together with ADMIN_SECRET_KEY, and export Firestore (gcloud firestore export gs://YOUR_BUCKET). Keep your own copy of the project in Git so you can see and undo every change (Encryption keys and backups).
02From 2.x (Java) to 4.0
4.0.0 is the first Flutter release of this item. It is a new code base with a new backend, so the "migration" is a fresh setup plus a few decisions about your existing users.
What changes
| Area | 2.x (Java) | 4.0 |
|---|---|---|
| App | Native Android (Java), separate AdMob, AppLovin and Facebook variants | One Flutter project for Android, iOS and a web demo; AdMob, Unity Ads and ironSource LevelPlay in one build |
| Database | Your old backend | Cloud Firestore in your own Firebase project (Blaze plan). There is no schema to upgrade: every collection is new, created by the Cloud Functions as users use the app |
| Server code | Your old backend | Cloud Functions in firebase/functions/ (Node 22), plus Cloud Scheduler jobs created on deploy |
| Admin | The 2.x admin | The operator console in admin/ (Node 22) with its own small database (SQLite file or Postgres) |
| Rewards | Coins with a manual PayPal redemption | Points with no cash value; an optional, separate cash wallet funded only by offerwalls and surveys (Wallet) |
New environment variables
2.x had none of these. Copy the example files and fill them in; never commit the real files.
| File | Variable | Required | What it is |
|---|---|---|---|
admin/.env (from admin/.env.example) | ADMIN_SECRET_KEY | Yes | Encrypts the secrets the console stores. openssl rand -hex 32. Back it up (why) |
GOOGLE_APPLICATION_CREDENTIALS | Yes, outside Google Cloud | Path to your Firebase service account key file | |
FIREBASE_PROJECT_ID | No | Only when the key file does not name the project | |
PORT | No | Default 8790 | |
DATABASE_URL | No | Postgres instead of the SQLite file, for serverless hosts or several instances | |
FIRESTORE_EMULATOR_HOST | Local only | Points the console at the Firestore emulator | |
ADMIN_DATA | No | Leave empty. sample is only for the public demo | |
ADMIN_DEMO_PASSWORD | No | Leave empty on your own install | |
firebase/functions/.env (from .env.example) | FUNCTIONS_REGION | No | Default us-central1. It becomes part of every callback URL |
ENFORCE_APP_CHECK | No | Default true. Set false only while you wire App Check up |
Firestore document structure in 4.0
Everything is written by the Cloud Functions or the console; the app reads only what the rules allow. The main documents:
| Path | Holds | Written by |
|---|---|---|
config/public | Brand, economy, ads, features, wallet settings the app reads live | The console, at every start and every save |
config/private | Ad and offerwall verification secrets, PayPal and store keys | The console; never readable by the app |
users/{uid} and users/{uid}/ledger, /daily | Profile, points balance, one ledger row per credit or debit, daily counters | Cloud Functions |
wallets/{uid} and wallets/{uid}/entries | Cash balances in cents (pending, available, locked) and their entries; only with the wallet on | Cloud Functions |
payoutRequests | Cash payout requests and their approval state | Cloud Functions and the console |
quizzes, tasks, offers, storeItems, seasons, events, sponsors | Content you manage in the console | The console |
leaderboards, teams, friends, publicProfiles, inbox | Social and engagement data | Cloud Functions |
The complete field-by-field reference is in docs/CONTRACT.md, docs/CONTRACT-3.1.md and docs/CONTRACT-4.0.md in the package; the access rules are in firebase/firestore.rules.
Steps
- Keep your old app runningDo not switch anything off yet. Your 2.x app and backend stay as they are until 4.0 is live.
- Set 4.0 up as a new appFollow Installation: Firebase project on Blaze, deploy rules, indexes and functions, start the console, connect the app.
- Keep your Android application id and upload keyBuild 4.0 with your existing application id and upload key, and raise the version code above your last upload, so it installs as an update of your current Play listing (Rebranding, Signing).
- Decide what happens to old coin balancesSee below, and tell your users before you publish.
- Update your store listingCoins become points with no cash value. Remove any text that promises money for watching ads (Platform rules).
- Publish, then retire the old backendOnce 4.0 is live and your users have moved, keep a final export of the old backend for your records and switch it off.
Old users and coin balances
No import tool is included: the 2.x data lives in your old backend, in a format this package does not read, and 4.0 users get new Firebase user ids when they sign in. Your options:
- Start fresh, and say so in the app update notes. The simplest and most common choice.
- Honour old balances by hand: after a user signs in to 4.0 and sends you their old account details, an owner opens console → Users → the user → Adjust points with a reason such as "2.x balance". The row is recorded in the ledger (type
admin) and the audit log. Points have no cash value in 4.0, whatever the old coins were worth. - Pay out old coin redemptions in your old system before you switch it off, if you promised them.
03Updating within 4.x
Later 4.x releases keep the same project layout and the same data. Every release lists, in the Changelog, its new environment variables, new or changed Firestore documents and anything you must do by hand under Upgrade notes. If a release has no such heading, there is nothing to do by hand.
- Back upConsole data with
ADMIN_SECRET_KEY, and a Firestore export (above). - Merge the new code into your copyCommit your current project to Git. Unzip the new release into a separate folder, copy it over a new branch of your project, and review the diff: your changes (brand, ids, icons, texts) show up as conflicts or reverted lines you keep. Do not overwrite
admin/.env,firebase/functions/.env,app/lib/firebase_options.dart,google-services.jsonorGoogleService-Info.plist. - Compare the example env files
git diffadmin/.env.exampleandfirebase/functions/.env.example. Add any new variable to your real.envfiles. - Deploy the backend firstFrom
firebase/:firebase deploy --only firestore:rules,firestore:indexes,functions. New indexes can take a few minutes to build; the Firebase console shows their state. - Update and restart the consoleIn
admin/:npm ci, then restart. Its own tables are created automatically at start if they are missing. It then rewritesconfig/publicandconfig/privatefrom your saved settings, adding every new setting with its default, and raisesconfig/public.version. Your existing values and secrets are kept. - Check console → StatusIt reports a failed config write, a missing secret or a skipped line.
- Build and release the appRaise the version and build number, build and upload (Release). Users on the old app keep working against the new backend, because the functions and the app fall back to defaults for settings an older build does not know.
Within 4.x, documents in users, wallets and the other collections are read as they are; new fields get their defaults when they are missing. If a future release ever needs a one-time data change, its Upgrade notes will name the command and say what it changes, before you run it.