Skip to content

Add optional sync backend for multi-device synchronization#54

Open
bl4ckh4nd wants to merge 2 commits intoBEKO2210:mainfrom
bl4ckh4nd:add-sync-backend
Open

Add optional sync backend for multi-device synchronization#54
bl4ckh4nd wants to merge 2 commits intoBEKO2210:mainfrom
bl4ckh4nd:add-sync-backend

Conversation

@bl4ckh4nd
Copy link

Summary

  • Adds an optional self-hosted sync backend (Fastify + SQLite) enabling multi-device synchronization
  • Implements a conflict-free sync engine on the client using updatedAt timestamps (last-write-wins)
  • New sync settings UI in the Settings page: configure server URL, enable/disable sync, manual sync trigger and status display
  • Docker Compose file included for easy self-hosting

Architecture

  • sync-backend/ — Node.js server (Fastify, SQLite via better-sqlite3) exposing REST endpoints for products, storage locations, and consumption logs
  • src/lib/sync.ts — Client sync engine: pushes local changes, pulls remote changes, resolves conflicts by updatedAt
  • src/lib/syncConfig.ts — Persists sync server URL and enabled state in localStorage
  • src/lib/db.ts — Extended with syncId fields and sync queue tracking

Test plan

  • Sync disabled by default — app behaves exactly as before
  • Enter a valid server URL in Settings → sync activates
  • Add/edit/delete a product on one device → changes appear on a second device after sync
  • Conflict: edit same product on two devices offline → device with newer updatedAt wins
  • Docker Compose: docker compose -f docker-compose.sync.yml up starts the backend
  • All existing tests pass (npm run test)

… support

- Add package.json with dependencies and scripts for starting the server and running tests.
- Implement server.js with endpoints for device pairing, sync push/pull, and health check.
- Create SQLite database schema for households, devices, entities, and changes.
- Implement logic for handling changes with last-write-wins strategy and tombstone deletes.
- Add server tests for pairing devices, authentication, sync operations, and error handling.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe39d661aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

src/lib/db.ts Outdated
Comment on lines +459 to +460
barcode: typeof payload.barcode === 'string' ? payload.barcode : existing?.barcode,
category:

Choose a reason for hiding this comment

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

P1 Badge Preserve explicit field clears during product sync

In applyProductUpsertFromSync, optional fields default to existing whenever a key is missing, but outbound sync payloads are JSON-serialized (see pushChanges) so undefined fields are dropped. This means clearing optional product fields (e.g. barcode, notes, photo, minStock) on one device is transmitted as an omitted key and other devices keep the old value, so state does not converge after sync.

Useful? React with 👍 / 👎.

Comment on lines +538 to +539
{!syncIsPaired ? (
<button

Choose a reason for hiding this comment

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

P2 Badge Allow re-pairing after changing sync backend

The pair flow is hidden once syncIsPaired is true, but that flag only checks whether stored credentials exist. If the user edits Server URL (or the backend data is reset), the app keeps old household/token credentials, sync calls fail with authorization errors, and there is no UI path to enter a sync code and pair again, leaving users stuck unless they manually clear storage.

Useful? React with 👍 / 👎.

P1: toSyncProductPayload now serializes optional fields (barcode, photo,
minStock, notes) as explicit null instead of omitting them via
JSON.stringify. applyProductUpsertFromSync uses 'key in payload' to
distinguish an intentional clear (null) from an absent key (fallback to
existing), so clearing a field on one device correctly propagates to peers.

P2: Add a 'Neu koppeln' path in Settings that clears stored pairing
credentials (householdId/deviceToken) and shows the sync-code input again,
allowing users to re-pair after switching servers or resetting backend data.
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