Skip to content

fix: only sync dirty files on page load, import server state first - #2

Merged
timcovar merged 6 commits into
mainfrom
fix/import-before-sync-on-hydrated-backend
Aug 5, 2026
Merged

fix: only sync dirty files on page load, import server state first#2
timcovar merged 6 commits into
mainfrom
fix/import-before-sync-on-hydrated-backend

Conversation

@timcovar

@timcovar timcovar commented Aug 5, 2026

Copy link
Copy Markdown

Summary

  • Fix stale localStorage cache overwriting externally-edited flag files on page load
  • syncRemoteBackend now only PUTs files that the user explicitly edited in the UI (isDirty: true)
  • Server state is always imported after any sync, ensuring external edits are respected

Problem

When the NGXS storage plugin restores a hydrated backend from localStorage, syncBackends was called with isHydrated: true. This triggered syncRemoteBackend which iterated over ALL cached files and PUT them to the server — even though they were stale (from a previous session). Only after that did importRemoteBackend fetch the current server state.

This caused flag files edited externally (e.g. via sell/local/flagd/flags.flagd.json) to be silently overwritten every time the UI was loaded in a browser with cached state.

Why incognito worked: No localStorageisHydrated starts false → skips syncRemoteBackend → goes straight to import.

Changes

In flag-file-store.state.ts:

  1. syncBackends: only call syncRemoteBackend when there are dirty files
  2. syncRemoteBackend: filter to only dirty files instead of syncing all files; remove the delete-remote-files-not-in-local logic (which could delete flags added externally)

Test plan

  • Load UI with stale localStorage cache → verify it imports server state without overwriting
  • Edit a flag in the UI → verify the dirty flag is synced on next page load
  • Edit a flag file externally → reload UI → verify the external edit is preserved

🤖 Generated with Claude Code

timcovar and others added 6 commits August 5, 2026 09:33
Previously, when the NGXS storage plugin restored a hydrated backend
from localStorage, syncBackends would PUT all cached file contents to
the server before importing the server's current state. This caused
externally-edited flag files to be silently overwritten with stale
localStorage data on every page load.

Now syncRemoteBackend only runs when there are user-edited (isDirty)
files, and only those dirty files are synced. The server's state is
always imported afterward, ensuring external edits are respected.

This explains why incognito mode worked (no localStorage = no stale
cache to sync) while normal browsing reverted flag edits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The server was not handling SIGTERM, causing Docker to wait the full
stop timeout (default 10s) before sending SIGKILL. Now axum::serve
uses with_graceful_shutdown to listen for both SIGTERM and SIGINT,
allowing the container to exit promptly on docker stop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The docker-publish job was building linux/amd64,linux/arm64 via QEMU
emulation on an x86 runner, causing 30+ minute Rust compilation times.

Since all consumers run arm64 (macOS with OrbStack/Docker Desktop),
switch to:
- ubuntu-24.04-arm runner (native arm64, no emulation)
- linux/arm64 platform only
- Remove QEMU setup step (no longer needed)

This should reduce publish time from ~30min to ~5min.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update all GitHub Actions to their latest major versions (Node 22 runtime)
to eliminate Node 20 deprecation warnings. Remove unused stub structs in
build.rs and suppress dead_code warning on AppState.config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GitHub Pages is not configured on this repo, so the docs-deploy job
never ran. Remove it along with the OpenAPI schema extract/upload steps
and docs screenshots upload that only served the docs build.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The azurite/azurite-init services require locally generated TLS certs
that aren't in the repo, causing CI playwright tests to fail. These
services already exist in docker-compose.azure.yaml for Azure-backed
development. The default compose now only starts flagd-ui and flagd,
which is all the e2e tests need.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@timcovar
timcovar merged commit acff76c into main Aug 5, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant