-- allium: 1 -- Domain Event Bus (issue #26, phase 2) -- Scope: extension (multi-client synchronization over Phoenix.PubSub) -- Distilled from: lib/bds/events.ex, context broadcast call sites, -- lib/bds/desktop/shell_live.ex, lib/bds/cli_sync/watcher.ex entity EntityChangedEvent { project_id: String entity: String -- post, media, tag, template, script, project entity_id: String action: created | updated | deleted -- Same topic and payload shape as the CLI sync watcher, so one -- subscription covers in-app mutations and external CLI writes. } entity SettingsChangedEvent { project_id: String? -- absent for a global setting key: String -- e.g. ui.language } surface EventBusSurface { facing _: EventBus provides: ContextMutationSucceeded(project_id, entity, entity_id, action) GlobalSettingWritten(key) ClientSubscribed() ClientUnsubscribed() } rule BroadcastEntityMutation { when: ContextMutationSucceeded(project_id, entity, entity_id, action) -- Posts, Media, Tags, Templates, Scripts broadcast after every -- successful create/update/publish/delete (publish maps to updated). ensures: EntityChangedEvent.created( project_id: project_id, entity: entity, entity_id: entity_id, action: action ) } rule BroadcastSettingsChange { when: GlobalSettingWritten(key) ensures: SettingsChangedEvent.created(key: key) } rule ClientSynchronization { when: ClientSubscribed() -- Every shell subscribes on mount. Each subscriber receives events in -- publish order and refreshes only the affected project; deleted entities -- close their open tabs. A refresh never writes the mutation again. ensures: ClientRefreshOnEvent() } rule ClientUnsubscription { when: ClientUnsubscribed() -- A detached client receives no later events. ensures: ClientDetached() } rule ServerSideUiLanguage { when: GlobalSettingWritten(key) requires: key = "ui.language" -- The UI language is a single server-side setting: changing it in any -- client persists it and re-renders every connected client. The OS -- locale is only the fallback when the setting is unset. ensures: AllClientsRelocalized() }