Skip to content

Keep FW Lite Windows projects when the app is uninstalled - #2789

Draft
hahn-kev-bot wants to merge 2 commits into
developfrom
claude/fwlite-windows-data-survives-uninstall
Draft

hahn-kev-bot wants to merge 2 commits into
developfrom
claude/fwlite-windows-data-survives-uninstall

Conversation

@hahn-kev-bot

@hahn-kev-bot hahn-kev-bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

AI summary

Fixes #1391 for Windows. MSIX installs kept projects in the package's LocalState, and Windows deletes that folder on uninstall. Builds on the Harmony update in #2788 (merged).

Summary

 %LOCALAPPDATA%\Packages\FwLiteDesktop_<hash>\LocalState\   (deleted on uninstall)
   app.log, msal.cache                       # stays here
-  example.sqlite
-  localResourcesCache\example\…
-  failedSyncs\
+  example.sqlite.migrated                   # retired after a verified copy
+C:\ProgramData\SIL\FieldWorks Lite\<user>\   (MSIX doesn't virtualize ProgramData; survives uninstall)
+  projects\example\example.sqlite
+  localResourcesCache\example\…
+  failedSyncs\
+  fwlite-data-migration.json                # marker

One-time migration at startup (ProjectDataFolderMigration), resolved before any project path is used:

TryMigrate(LocalState, ProgramData\…\<user>)
  marker present                          -> use new root
  take migration lock (no timeout)
  take exclusive legacy lease             -> fails if another instance still runs on LocalState -> stay on legacy
  copy to <user>.migrating-<guid>
    media + failedSyncs (size-checked)
    each db: SQLite backup API (includes WAL) -> rewrite LocalResource.LocalPath prefix
             -> quick_check + per-table row counts + every referenced media file exists
  write marker, Directory.Move(staging, target)   # single commit point
  rename legacy *.sqlite -> *.sqlite.migrated     # a stale copy can't sync under the same ClientId
  any failure -> stay on LocalState (holding a shared lease), retry next start
  • LcmCrdtConfig.UseProjectFolders: new projects go in projects/{code}/{code}.sqlite. Discovery always finds both layouts, and the folder wins on a duplicate code. Only Windows MSIX turns it on, so other platforms, FwLiteWeb and Platform.Bible are unchanged.
  • FwLiteMauiConfig.ProjectDataDir defaults to ProgramData on packaged Windows unless BaseDataDir is overridden. Troubleshooting's "data folder" now opens the project root.
  • No startup-task mechanism (Startup tasks #1949) needed: this is a file copy before the app opens any project, not an in-database task.

Evidence

  • Unit tests (LcmCrdt.Tests): ProjectFolderLayoutTests (7) and ProjectDataFolderMigrationTests (10).
    • A real example project with saved media migrates. Entries and media are readable from the new root, and the legacy files are unchanged apart from the rename.
    • Covered: changes still in the WAL are included; only cache paths are rewritten; a corrupt db fails cleanly; a target that wasn't created by a migration is left alone; a re-run is a no-op; a crash leftover is cleaned up; concurrent starts all land on the new root; an instance still on LocalState blocks the migration.
    • Mutation-checked: removing the path rewrite fails 2 tests, and removing the lease check fails the instance-blocking test.
  • Manual MSIX check (Windows 11, harness identity FwLiteDesktopTest, so no real install was touched):
    • Before: a seeded flat project with media in LocalState.
    • After launch: the log says Migrated 1 projects from …\LocalState to C:\ProgramData\SIL\FieldWorks Lite\<user>. The files are visible from outside the package (not virtualized), the legacy db became .sqlite.migrated, the media path was rewritten, and the log has no errors. Creating an example project in-app wrote projects\example-project\example-project.sqlite.
    • After uninstall: the package folder is gone, and ProgramData kept both projects (quick_check ok, all entries present).

Merge Danger

Door: one-way, per user.

Once an install has migrated, an older build looks in LocalState, finds only .sqlite.migrated files and shows no projects. The data is intact, but a rollback would need a reverse migration or manual renames.

Blast Radius: Windows-MSIX.

Every MSIX user runs the migration on first start after updating.

  • It runs synchronously with no progress UI, so a large media cache means a slow first launch.
  • The folder is keyed by Windows user name, so renaming the account hides projects (they stay on disk).
  • The marker is per user folder, not per package: a second package identity (e.g. a future beta channel) that migrates first would make production skip its own LocalState.
  • Other local accounts can read the ProgramData folder (default ACL).

Test plan

  • dotnet test backend/FwLite/LcmCrdt.Tests --filter "FullyQualifiedName~ProjectDataFolderMigrationTests|FullyQualifiedName~ProjectFolderLayoutTests|FullyQualifiedName~OpenProjectTests|FullyQualifiedName~MediaTests" (45 pass on develop)
  • FwLiteMaui.Tests MauiTroubleshootingServiceTests; Windows MAUI head and FwLiteWeb build
  • Manual MSIX install → migrate → create project → uninstall → ProgramData survives
  • Upgrade an existing real install (release build → this build) and check its projects and media

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions github-actions Bot added 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related 🔩 FW Lite Core Shared MiniLcm, CRDT and sync libraries that ship in both FW Lite and FwHeadless labels Oct 22, 2026
Base automatically changed from claude/harmony-update-1fd508 to develop October 23, 2026 02:59
_defaultBaseDataDir = BaseDataDir;
}

public string BaseDataDir

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what else is this used for now? It feels like it would be too easy to use the wrong data dir without guidance.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it only holds app-local state: app.log, msal.cache, the new fw-lite-settings.json from develop, and the WebView profile. It's also where the old flat projects sit until they're migrated. Projects, media and failed syncs moved to ProjectDataDir.

Agreed it was too easy to grab the wrong one, and ProjectDataDir is a trap too: it's the intended folder, but a failed migration falls back to BaseDataDir. In 8e833c5:

  • Both properties now say what they're for, and ProjectDataDir says to read the folder in use from LcmCrdtConfig.ProjectPath / HarmonyConfig, never from the property.
  • The kernel no longer keeps a baseDataPath local, so nothing invites reuse.
  • The two-folder layout is in backend/FwLite/AGENTS.md and the troubleshooting guide.

If you'd rather the name carry it, I can rename the property to something like AppStateDir and keep BaseDataDir as the config key ([ConfigurationKeyName]), so env vars, CI and settings files keep working.

hahn-kev and others added 2 commits November 6, 2026 15:43
MSIX installs kept projects in the package's LocalState, which Windows
deletes on uninstall (#1391). Project data now lives in
C:\ProgramData\SIL\FieldWorks Lite\<user>, which MSIX does not
virtualize, with each project in projects\<code>\<code>.sqlite. The auth
cache and logs stay in LocalState.

Existing installs are migrated once at startup: each database is copied
with SQLite's backup API, media paths in the copy are re-pointed at the
new cache, and the copy is verified before a single directory rename
makes it live. The old databases are then renamed to .sqlite.migrated so
a stale copy can't sync under the same ClientId. Any failure keeps the
app on LocalState and retries next start; a lease stops a second
instance from migrating while another is still using LocalState.

Project discovery finds both layouts, so other platforms are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BaseDataDir now only holds app-local state (logs, auth cache, settings
file), and ProjectDataDir is only the intended project folder: a failed
migration falls back to BaseDataDir. Say so on both properties, point
code at LcmCrdtConfig.ProjectPath, and add the layout to the FwLite
AGENTS.md and the troubleshooting guide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hahn-kev
hahn-kev force-pushed the claude/fwlite-windows-data-survives-uninstall branch from b112de0 to 8e833c5 Compare November 6, 2026 08:44
@argos-ci

argos-ci Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
e2e (Inspect) ✅ No changes detected - Nov 6, 2026, 8:51 AM

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔩 FW Lite Core Shared MiniLcm, CRDT and sync libraries that ship in both FW Lite and FwHeadless 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project data is lost when app is uninstalled

2 participants