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

vercelBot commented Jun 1, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 1, 2026 8:06am

Request Review

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Jun 1, 2026
@xuyushun441-sys
xuyushun441-sys merged commit 3a45780 into mainJun 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/steststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@xuyushun441-sys@os-zhuang