Skip to content

feat(messaging): synthesize inbox action_url from event source (ADR-0030 L5)#1456

Merged
xuyushun441-sys merged 2 commits into
mainfrom
feat/notification-action-url-from-source
Jun 1, 2026
Merged

feat(messaging): synthesize inbox action_url from event source (ADR-0030 L5)#1456
xuyushun441-sys merged 2 commits into
mainfrom
feat/notification-action-url-from-source

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

What

The Console bell reads sys_inbox_message (the ADR-0030 L5 in-app materialization), which carries only action_urlnot the L2 sys_notification event's source_object/source_id. Producers that pass a source but no explicit payload.url (collaboration @mention, record assignment) materialized inbox rows with no navigable link, so clicking the bell entry could not deep-link to the originating record.

This synthesizes an app-relative /{object}/{id} link from emit()'s source when no explicit payload.url/payload.actionUrl is supplied, in both the inline fan-out and the durable-outbox enqueue paths (actionUrlFor() helper). Precedence: explicit url → source-derived link → undefined.

Keeps the L5 materialization self-sufficient for navigation, which the objectui bell cut-over consumes (companion objectui PR repoints the bell to sys_inbox_message + sys_notification_receipt).

Why

Part of the ADR-0030 objectui cut-over. The re-modeled sys_notification is now the L2 event (no recipient/read columns); the bell can no longer fall back to source_object/source_id on the event, so the link must ride on the materialization.

Tests

3 new messaging-service.test.ts cases — source→/obj/id, explicit-url precedence, neither→undefined. All 95 @objectstack/service-messaging tests green.

Verification

Verified live in the showcase Console (fresh sqlite, full pipeline): a materialized sys_inbox_message with a delivered receipt lit the bell badge; the popover rendered the row; "mark all read" updated the existing receipt in place to read (no duplicate, unique index respected) and cleared the badge.

🤖 Generated with Claude Code

…030 L5)

The bell reads `sys_inbox_message` (the L5 materialization), which carries
only `action_url` — not the L2 event's `source_object`/`source_id`. Producers
that pass a `source` but no explicit `payload.url` (collaboration @mention,
record assignment) therefore materialized inbox rows with no navigable link,
so clicking the bell entry couldn't deep-link to the record.

Synthesize an app-relative `/{object}/{id}` link from `emit()`'s `source` when
no explicit `payload.url`/`payload.actionUrl` is given, in both the inline
fan-out and the durable-outbox enqueue paths. An explicit url still wins; with
neither url nor source the link stays undefined. This keeps the materialization
self-sufficient for navigation (the objectui bell consumes action_url).

Tests: 3 new cases (source→link, explicit-url precedence, neither→undefined);
all 95 service-messaging tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 1, 2026 8:06am

Request Review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Jun 1, 2026
@xuyushun441-sys xuyushun441-sys merged commit 3a45780 into main Jun 1, 2026
12 checks passed
@xuyushun441-sys xuyushun441-sys deleted the feat/notification-action-url-from-source branch June 1, 2026 08:15
xuyushun441-sys added a commit that referenced this pull request Jun 2, 2026
…min mechanism (ADR-0015 Addendum) (#1502)

* chore: bump objectui to fdd083657e2d

feat(studio): AI-draft review/diff mode in the object designer (v1) (#1456)

objectui@fdd083657e2da9832059492d4c88e818a5990a8d

* feat(service-datasource-admin): open-source the runtime datasource admin mechanism (ADR-0015 Addendum)

Move the runtime UI-created datasource lifecycle (list/test/create/update/
remove) out of the private cloud repo into the open framework as
@objectstack/service-datasource-admin, sitting next to its federation sibling
@objectstack/service-external-datasource.

This package is mechanism only: credential storage is delegated to a
host-provided SecretBinder over any ICryptoProvider (framework default:
InMemoryCryptoProvider), and drivers to a swappable factory. The tier line
falls on which crypto provider / driver factory a host injects — a neutral
technical seam — so a managed credential vault + multi-tenant overlay can be
layered on by a private host without forking. Consistent with the connector /
outbox / approval tiering principle: charge for credential custody +
multi-tenant ops + scale, not for the ability to manage a datasource.

- workspace:* deps, Apache-2.0, exports . and ./contracts
- serve is NOT wired to mount this by default yet (OSS-edition identity TBD)
- 29 tests pass; typecheck + build (incl. dts) clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys added a commit that referenced this pull request Jun 2, 2026
* chore: bump objectui to fdd083657e2d

feat(studio): AI-draft review/diff mode in the object designer (v1) (#1456)

objectui@fdd083657e2da9832059492d4c88e818a5990a8d

* fix(driver-sqlite-wasm): defer flush during transactions (#1494)

Under `persist: 'on-write'` an authenticated insert could fail with
`COMMIT; - cannot commit - no transaction is active`.

Root cause: sql.js `Database.export()` closes and reopens the database
(it has no in-place serialize). Closing a connection rolls back any open
transaction, so the fire-and-forget `void flush()` triggered after a
write inside a Knex transaction (e.g. the autonumber sequence
`BEGIN…COMMIT`) aborted that transaction, leaving the trailing COMMIT to
run with no active transaction. The failure is timing-dependent, which is
why objects with extra in-transaction writes (autonumber + sharing-rule
recompute, like crm_account) tripped it while a bare insert usually did
not.

Fix: make the connection transaction-aware. Track
BEGIN/COMMIT/ROLLBACK/SAVEPOINT/RELEASE; `flush()` now defers while a
transaction is open and runs once it fully closes. `close()` clears the
state so the final flush still persists committed data. The dialect
notifies the connection of every transaction-control statement before
markDirty.

Adds a regression test covering multi-statement transactions, on-write
disk persistence, autonumber inserts, and nested savepoints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: add changeset for #1494 fix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(driver-sqlite-wasm): serialize flushes; single flush per txn close

Follow-up to the #1494 fix. Two issues surfaced in CI / under load:

- A COMMIT triggered two flushes (one from noteTransactionControl, one
  from the dialect's trailing markDirty('run')). Overlapping sql.js
  export() close/reopens raced and could persist 0 bytes. Route
  transaction-control statements through noteTransactionControl only, so
  the transaction lifecycle owns flushing and fires exactly once on close.
- Replace the pendingFlush + recursive re-flush mechanism with a single
  strictly-serialized flush chain. export() mutates the live connection
  (close/reopen), so two exports must never overlap, and flush() must not
  resolve until the caller's own write has hit disk (deterministic for
  close()/tests). Key the post-commit flush off flushDeferred (not dirty)
  so on-disconnect mode still defers to close() instead of flushing on
  every COMMIT.

Full driver suite green across repeated full-suite runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys added a commit that referenced this pull request Jun 2, 2026
#1503)

* chore: bump objectui to fdd083657e2d

feat(studio): AI-draft review/diff mode in the object designer (v1) (#1456)

objectui@fdd083657e2da9832059492d4c88e818a5990a8d

* fix(dev): unify dev admin seed in-process; remove port-drift HTTP seed

`pnpm dev:showcase` often failed to provision a usable admin. The CLI
seeded over HTTP against a hard-coded localhost:3000, but dev auto-shifts
off a busy port — so the POST hit the wrong server (or nothing) and the
showcase instance never got an admin. A second, divergent seed in
plugin-dev inserted a raw sys_user row with no credential, producing an
un-loginable ghost admin (admin@dev.local).

Consolidate to a single in-process seed in the runtime:

- plugin-auth: maybeSeedDevAdmin() runs on kernel:ready, creates the admin
  (admin@objectos.ai / admin123) through better-auth's real signUpEmail
  pipeline (hashed credential + hooks), so it is fully loginable;
  plugin-security's first-user middleware promotes it to platform admin.
  Empty-DB only (excludes the SystemUserId.SYSTEM account), idempotent,
  never overwrites an existing account. Hard-gated to NODE_ENV=development;
  opt out with OS_SEED_ADMIN=0. No port, no readiness race.

- cli/dev: delete the HTTP seedAdminAccount entirely; --seed-admin now just
  passes OS_SEED_ADMIN[_EMAIL|_PASSWORD] to the serve child. Drop the dead
  `port` param from the watch loop.

- cli/serve: publish the actually-bound port — process.send({type:
  'objectstack:listening', port, url}) over IPC + a runtime.<env>.json
  state file under OS_HOME for external supervisors.

- plugin-dev: remove the credential-less raw sys_user insert; seedAdminUser
  now maps to the unified OS_SEED_ADMIN toggle.

Verified on the showcase: loginable admin + platform-admin promotion,
correct seed under port auto-shift (3999 busy -> 4000), runtime.json
written, --no-seed-admin opt-out, and idempotency on a persistent DB (no
duplicate user / permission set). Tests: plugin-auth 88, plugin-dev 7,
cli 144 — all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore: add changeset for dev seed-admin fix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys pushed a commit that referenced this pull request Jun 2, 2026
feat(studio): AI-draft review/diff mode in the object designer (v1) (#1456)

objectui@fdd083657e2da9832059492d4c88e818a5990a8d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants