Add the shared domain event bus.

This commit is contained in:
2026-07-19 13:48:03 +02:00
parent 429f471e4e
commit a2abb901cd
28 changed files with 1534 additions and 65 deletions

View File

@@ -4,7 +4,8 @@
-- Distilled from: src/main/engine/CliNotifier.ts, NotificationWatcher.ts
entity DbNotification {
entity_type: String -- post, media, script, template
project_id: String?
entity_type: String -- post, media, tag, script, template, project, setting
entity_id: String
action: created | updated | deleted
from_cli: Boolean
@@ -19,14 +20,15 @@ surface CliSyncRuntimeSurface {
facing _: CliSyncRuntime
provides:
CliMutationPerformed(entity_type, entity_id, action)
CliMutationPerformed(project_id, entity_type, entity_id, action)
DbFileChangeDetected()
}
rule CliWriteNotification {
when: CliMutationPerformed(entity_type, entity_id, action)
when: CliMutationPerformed(project_id, entity_type, entity_id, action)
-- CLI inserts notification row; app watches for it
ensures: DbNotification.created(
project_id: project_id,
entity_type: entity_type,
entity_id: entity_id,
action: action,
@@ -43,7 +45,7 @@ rule AppWatchNotifications {
for n in unseen:
ensures: n.seen_at = now
ensures: EngineCacheInvalidated(n.entity_type)
ensures: EntityChangedEvent(n.entity_type, n.entity_id, n.action)
ensures: EntityChangedEvent(n.project_id, n.entity_type, n.entity_id, n.action)
-- IPC event to renderer for UI refresh
}

View File

@@ -5,7 +5,8 @@
-- lib/bds/desktop/shell_live.ex, lib/bds/cli_sync/watcher.ex
entity EntityChangedEvent {
entity: String -- post, media, tag, template, script
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
@@ -13,6 +14,7 @@ entity EntityChangedEvent {
}
entity SettingsChangedEvent {
project_id: String? -- absent for a global setting
key: String -- e.g. ui.language
}
@@ -20,16 +22,18 @@ surface EventBusSurface {
facing _: EventBus
provides:
ContextMutationSucceeded(entity, entity_id, action)
ContextMutationSucceeded(project_id, entity, entity_id, action)
GlobalSettingWritten(key)
ClientSubscribed()
ClientUnsubscribed()
}
rule BroadcastEntityMutation {
when: ContextMutationSucceeded(entity, entity_id, action)
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
@@ -43,13 +47,18 @@ rule BroadcastSettingsChange {
rule ClientSynchronization {
when: ClientSubscribed()
-- Every shell (LiveView GUI or TUI session) subscribes on mount and
-- refreshes affected views on each event; deleted entities close
-- their open tabs. This keeps all connected clients synchronized
-- regardless of which client or pipeline originated the change.
-- 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: "ui.language")
-- The UI language is a single server-side setting: changing it in any