From ce89a33f844309d3ed3da216dede1e77decd3f11 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Tue, 16 Jun 2026 16:19:04 +0800 Subject: [PATCH] =?UTF-8?q?refactor(audit):=20move=20sys=5Fattachment=20ow?= =?UTF-8?q?nership=20audit=20=E2=86=92=20storage=20(ADR-0052=20P0b)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A file↔record link belongs with the storage domain, not the compliance ledger. `plugin-audit` stops registering `sys_attachment`; `service-storage` now contributes it (definition stays in platform-objects). Both plugins are always-on, so the object stays available — no behavior change. Audit sheds one of its dumping-ground objects, moving toward a pure append-only ledger. `sys_notification` is intentionally NOT moved: it is mid-migration to an event model (migrate-sys-notification-to-event.ts, ADR-0030) and touching it now would collide with that in-flight work. - plugin-audit: drop SysAttachment from registered objects + import - service-storage: depend on platform-objects, import + register SysAttachment - ADR-0052 §6 P0b updated (sys_attachment done; sys_notification deferred) Verified in the showcase: sys_attachment still resolves (meta + data 200), no double-registration; plugin-audit 18/18 + service-storage 48/48 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/adr/0052-audit-is-not-the-activity-feed.md | 11 +++++++---- packages/plugins/plugin-audit/src/audit-plugin.ts | 14 +++++++------- packages/services/service-storage/package.json | 1 + .../service-storage/src/storage-service-plugin.ts | 6 +++++- pnpm-lock.yaml | 3 +++ 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/docs/adr/0052-audit-is-not-the-activity-feed.md b/docs/adr/0052-audit-is-not-the-activity-feed.md index 660132a0b0..81dbe5bb68 100644 --- a/docs/adr/0052-audit-is-not-the-activity-feed.md +++ b/docs/adr/0052-audit-is-not-the-activity-feed.md @@ -281,10 +281,13 @@ rather than written twice. human-readable summaries. Smallest change, biggest daily payoff, no migration — it only improves the *render* of rows the writer already emits. **This ADR ships P0a.** -- **P0b — ownership, no behavior change.** Move `sys_attachment` → storage, - `sys_notification` → messaging (code already concedes these). Make - "collaboration/activity is a platform primitive" an explicit capability rather - than an audit side-effect; keep it default-available so no UI regresses. +- **P0b — ownership, no behavior change.** ✅ `sys_attachment` registration moved + `plugin-audit` → `service-storage` (both always-on, so it stays available; the + definition stays in `platform-objects`). `sys_notification` is **deferred** — it + is mid-migration to an event model (`metadata/.../migrate-sys-notification-to-event.ts`, + ADR-0030), so moving it now would collide with that in-flight work. Still TODO: + make "collaboration/activity is a platform primitive" an explicit capability + rather than an audit side-effect; keep it default-available so no UI regresses. - **P1 — kill the split-brain + milestone templates (§5b.2).** Choose the canonical collaboration backend (§5), migrate/alias `sys_comment`, repoint ChatterPanel, surface reactions/threads. Add declarative object-level milestone diff --git a/packages/plugins/plugin-audit/src/audit-plugin.ts b/packages/plugins/plugin-audit/src/audit-plugin.ts index d2a942ff77..887256c4e8 100644 --- a/packages/plugins/plugin-audit/src/audit-plugin.ts +++ b/packages/plugins/plugin-audit/src/audit-plugin.ts @@ -3,12 +3,12 @@ import type { Plugin, PluginContext } from '@objectstack/core'; import type { IDataEngine } from '@objectstack/spec/contracts'; import { SysAuditLog, SysActivity, SysComment } from './objects/index.js'; -// Registered here but still owned by platform-objects (the plugin contributes -// them to the kernel without owning the definition yet): -// - sys_notification — reworked by ADR-0030 messaging (notification→event). -// - sys_attachment — a file↔record link belonging with service-storage's -// sys_file; moves in the storage-domain decomposition, not this audit move. -import { SysNotification, SysAttachment } from '@objectstack/platform-objects/audit'; +// `sys_notification` is contributed here but owned by platform-objects; it is +// being reworked by ADR-0030 messaging (notification→event), so it stays put +// until that migration lands. `sys_attachment` moved to @objectstack/service- +// storage (ADR-0052 §3 ownership: a file↔record link belongs with storage, not +// the compliance ledger). +import { SysNotification } from '@objectstack/platform-objects/audit'; import { installAuditWriters, type MessagingEmitSurface } from './audit-writers.js'; /** @@ -37,7 +37,7 @@ export class AuditPlugin implements Plugin { scope: 'system', defaultDatasource: 'cloud', namespace: 'sys', - objects: [SysAuditLog, SysActivity, SysComment, SysAttachment, SysNotification], + objects: [SysAuditLog, SysActivity, SysComment, SysNotification], // ADR-0029 D7 — contribute the Audit Logs entry into the Setup app's // `group_diagnostics` slot. The plugin owns sys_audit_log (K2). navigationContributions: [ diff --git a/packages/services/service-storage/package.json b/packages/services/service-storage/package.json index 694104ce3d..420a68adb8 100644 --- a/packages/services/service-storage/package.json +++ b/packages/services/service-storage/package.json @@ -20,6 +20,7 @@ "dependencies": { "@objectstack/core": "workspace:*", "@objectstack/observability": "workspace:*", + "@objectstack/platform-objects": "workspace:*", "@objectstack/spec": "workspace:*" }, "peerDependencies": { diff --git a/packages/services/service-storage/src/storage-service-plugin.ts b/packages/services/service-storage/src/storage-service-plugin.ts index 7fa5e69c7d..8a56f0dd1d 100644 --- a/packages/services/service-storage/src/storage-service-plugin.ts +++ b/packages/services/service-storage/src/storage-service-plugin.ts @@ -14,6 +14,10 @@ import type { S3StorageAdapterOptions } from './s3-storage-adapter.js'; import { StorageMetadataStore } from './metadata-store.js'; import { registerStorageRoutes } from './storage-routes.js'; import { SystemFile, SystemUploadSession } from './objects/index.js'; +// ADR-0052 §3 ownership: `sys_attachment` (a file↔record link) belongs with the +// storage domain, not the audit/compliance ledger. Definition stays in +// platform-objects; storage now contributes (registers) it instead of audit. +import { SysAttachment } from '@objectstack/platform-objects/audit'; import { SwappableStorageService } from './swappable-storage-service.js'; /** @@ -170,7 +174,7 @@ export class StorageServicePlugin implements Plugin { version: '1.0.0', type: 'plugin', scope: 'system', - objects: [SystemFile, SystemUploadSession], + objects: [SystemFile, SystemUploadSession, SysAttachment], }); } catch { // manifest service may not be available in all environments diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e31998868f..01b1d23db3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2033,6 +2033,9 @@ importers: '@objectstack/observability': specifier: workspace:* version: link:../../observability + '@objectstack/platform-objects': + specifier: workspace:* + version: link:../../platform-objects '@objectstack/spec': specifier: workspace:* version: link:../../spec