When a new version of Kiddoly comes out, you’ll be merging it into an app you’ve rebranded and that has real users. Three things need care: the content IDs that saved progress points to, the database on each device, and your Firebase rules and functions. Each version’s changelog entry says which of the three it touches.
Keep the original download in git
Merging is much easier if the untouched Kiddoly download sits on its own branch, so git can show where your changes and an update overlap.
git init
git add -A
git commit -m "Kiddoly 1.0.0"
git branch kiddoly-upstream
git checkout kiddoly-upstream
git add -A
git commit -m "Kiddoly 1.x.x"
git checkout main
git merge kiddoly-upstream
Read the changelog of every version between yours and the new one, not only the latest. After merging, run flutter pub get, the checks in Tests and quality checks and the content validator.
1. Keep content IDs stable
Saved progress points at IDs, not at labels or positions. Changing an ID that has already shipped doesn’t carry anything across: the records under the old ID stay stored but are no longer shown, and the new ID starts from nothing.
IDWhere it’s savedIf you change it after release
Item id
Item mastery, on each device and in progress/{moduleId}.itemMastery
The item’s mastery resets, so the quiz and “what to work on next” treat it as new.
Module id
progress/{moduleId}, each session’s moduleId, and a child’s limits.enabledModules
The game’s stars, progress and play history look reset. A child whose game switches named it no longer sees the game until a parent switches it on again.
Sticker id
Each child’s stickers list
Children who earned the sticker lose it from their book.
Avatar order
Each child’s avatarId
Children get a different avatar and buddy character. Add new avatars at the end only.
Product ID kiddoly_pro
The stores and the purchase record
Earlier purchases no longer match, so restoring them fails. Don’t change it after launch.
These are safe to change at any time: an item’s label, sublabel, spoken, image, distractors and level; a module’s title, icon and order; pack file names, as long as the manifest’s packs lists follow; and adding items, packs or modules. Stars are saved per level number, so moving an item to another level keeps them.
Kiddoly updates don’t rename a shipped item, module, sticker or avatar ID. If one ever has to change, that version’s changelog entry says so and explains what to do.
NoteRedeploy the dashboard after a content change. The dashboard builds its skills map from assets/content when it’s built. Until you redeploy it, it describes the old content. An app that sends an ID the dashboard doesn’t know causes no error; that item just isn’t shown.
2. Database migrations on the device
Each device keeps its data in an SQLite database (drift), defined in lib/data/db/tables.dart and lib/data/db/app_database.dart. Its version is schemaVersion, which is 4 in Kiddoly 1.0.0. When an app update raises it, the steps in onUpgrade run once, at the first launch after the update, and every child’s data is kept.
- A Kiddoly update that changes the database raises
schemaVersion and adds a new step at the end. It never edits an earlier step, because devices that have already run it won’t run it again. drift_schemas/ holds a snapshot of every version. test/data/migration_test.dart upgrades from each older version to the current one and checks that the data survives.
Changing the database yourself
- 01
Change the tables in tables.dart.
- 02
Raise schemaVersion by one, and add a step at the end of onUpgrade, such as if (from < 5) { await m.addColumn(children, children.nickname); }. Leave the earlier steps alone.
- 03
Regenerate the code, then snapshot the new version:
dart run build_runner build --delete-conflicting-outputs
dart run drift_dev schema dump lib/data/db/app_database.dart drift_schemas/
dart run drift_dev schema generate drift_schemas/ test/data/generated/
- 04
Add the new version to test/data/migration_test.dart, and run flutter test.
- 05
Before you publish, install the previous release on a device, play a few levels, then install the new build over it and check that the children and their progress are still there.
WarningWhen you and an update both add version 5. Two different version-5 steps can’t both run: a device that already has yours would skip ours. When a Kiddoly update adds a version number you’ve already used, give its step the next free number after yours, and make sure it works on a database that has your changes. Putting your own data in new tables, rather than changing Kiddoly’s, keeps these merges simple.
Firestore needs no migration step. The app reads server documents defensively: a missing optional field falls back to a default, and an unknown field is ignored. What does need care is the security rules, which list every field they accept.
3. Redeploying Firebase rules and functions
App updates reach users over days or weeks, so for a while old and new versions of the app write to the same database. The backend has to accept both.
- 01
Deploy the backend first. Run the rules tests against the emulators (Java 21), then deploy the rules, indexes and functions before you publish the app update that relies on them:
npm ci --prefix functions
npm ci --prefix tools/rules_test
firebase emulators:exec --only firestore --project demo-kiddoly "npm --prefix tools/rules_test test"
firebase deploy --only firestore:rules,firestore:indexes,functions
- 02
Only add, never take away. Make a new field optional in the rules, so older app versions that don’t send it keep working. Don’t remove a field from the rules while any version still in use writes it. Functions should keep accepting what older app versions send.
- 03
If the app goes first, the rules refuse its writes that carry the new field. Nothing is lost: the device keeps them in its upload queue and sends them again, at the latest the next time the app starts after the rules are deployed. The device stays paired.
- 04
Update the dashboard to match. Its validation in
dashboard/src/lib/validation/child.ts mirrors the rules, so redeploy it with any rules change. Keep the functions region identical in the three files listed in
Connect your Firebase project.
- 05
Force an update only as a last resort. Raising minSupportedVersion in config/remote stops older versions at an “update required” screen. Use it only when an old version can’t work with the new backend at all.
Upgrade checklist
- 01
Merge the new version and resolve conflicts.
- 02
Run flutter analyze, flutter test, the content validator and the dashboard and functions checks.
- 03
If the changelog mentions rules, indexes or functions, test and deploy them.
- 04
Redeploy the dashboard.
- 05
Raise version in pubspec.yaml, then test the upgrade over the previous release on a real device.
- 06
Publish the app update.
- 07
Raise minSupportedVersion only if old versions must stop.