feat: LWW timestamps for bidirectional federation profile & layout sync

Profile and space layout changes on remote instances were being
overwritten by stale data on reconnect. Adds Last-Writer-Wins
timestamps so the client-relay mesh rejects stale writes:

- profile_updated_at column on users table with migration + backfill
- Server LWW guards on PATCH /users/@me and PUT /space-layout
- Bidirectional profileSync: pulls newer remote profiles to home
- LWW layout sync replaces home-authoritative _layoutFromTrueHome flag
- Layout pushes to ALL connected instances in parallel
This commit is contained in:
Jannis Braun
2026-03-12 18:28:37 +01:00
parent acbcf4d4e8
commit 83699d7e91
10 changed files with 294 additions and 115 deletions
+2 -2
View File
@@ -67,7 +67,7 @@ export class BackspaceApiClient {
};
readonly spaceLayout: {
update: (data: { items: SpaceLayoutItem[]; folders: Record<string, { name: string | null; color: string | null; spaceIds: string[] }> }) => Promise<{ items: SpaceLayoutItem[]; folders: SpaceFolder[] }>;
update: (data: { items: SpaceLayoutItem[]; folders: Record<string, { name: string | null; color: string | null; spaceIds: string[] }>; updatedAt?: number }) => Promise<{ items: SpaceLayoutItem[]; folders: SpaceFolder[]; updatedAt?: number }>;
};
readonly spaces: {
@@ -278,7 +278,7 @@ export class BackspaceApiClient {
this.spaceLayout = {
update: (data) =>
request<{ items: SpaceLayoutItem[]; folders: SpaceFolder[] }>('PUT', '/users/@me/space-layout', data),
request<{ items: SpaceLayoutItem[]; folders: SpaceFolder[]; updatedAt?: number }>('PUT', '/users/@me/space-layout', data),
};
this.spaces = {