Skip to content

Commit 023c00b

Browse files
os-zhuangclaude
andauthored
feat(spec)!: 通知模板孤儿语汇退役 —— ./system 不再导出 EmailTemplate/SMSTemplate/PushNotification/InAppNotification (#4616) (#4809)
* feat(spec)!: retire the orphan notification-template vocabulary from ./system (#4616) ADR-0049 enforce-or-remove, resolved by REMOVE in the v17 breaking window. `EmailTemplateSchema`, `SMSTemplateSchema`, `PushNotificationSchema` and `InAppNotificationSchema` (+ their four type aliases) existed ONLY as the member shapes of the `NotificationConfigSchema.template` union that #4610 (#4535 C3) deleted. Since then they have been reachable from no parent schema and from no metadata-type root — declared delivery capability the runtime never read. Three-repo consumer review (objectstack, cloud @ 5df2c69, objectui @ 785b8a5), by bare name rather than by import statement — which is what changed the answer: - SMSTemplate / PushNotification / InAppNotification: zero references outside their own declaration, their own unit tests and the generated artifacts. - EmailTemplateSchema: NOT consumer-free. objectui's metadata-admin registers it as the client-side validator for the `email_template` kind through a DYNAMIC import (app-shell/src/views/metadata-admin/clientValidation.ts:89), which an import-statement scan cannot see. That registration is itself the bug: the canonical schema for the kind is `EmailTemplateDefinitionSchema`, and validating an authored definition against the legacy shape reports its real keys as missing — the same defect spec 7.1.0 fixed on the framework side when it demoted `EmailTemplateSchema` to "an inline sub-shape inside `Notification`". Filed separately; removing the legacy export turns that silent mis-validation into a compile error at the one site that needs it. - ui `NotificationSeveritySchema`: REFUTED. The issue proposed retiring it in the same sweep on the premise that objectui pins only Type/Position/Action. objectui re-exports the type (packages/types), consumes it in core/src/protocols/NotificationProtocol.ts, pins the schema name in packages/types/src/__tests__/spec-ui-schema-reexports.test.ts, and types two severity->tone maps as Record<NotificationSeverityLevel, ...> precisely so a new spec severity fails type-check downstream. It is untouched, and the pin below asserts it stays ./ui-owned so the claim is not re-litigated. Route: whole-def removal (#4650 route 3), not a `retiredKey()` tombstone — a tombstone lives on a surviving schema's shape and none survives here. gen:schema adjudicates the four defs itself ("def no longer emitted by this build; whole-schema removals are adjudicated by json-schema.manifest.json and check:api-surface"), which is why the 22 authorable-surface lines and the 4 manifest keys are deleted in this commit. No ADR-0087 D2 conversion, deliberately: a conversion rewrites authored or stored sources, and no metadata document was ever parsed against these defs, so `os migrate meta` would have nothing to match — same disposition as #4610 in this module, and as #4767/#4783. Also corrects `kernel/metadata-plugin.zod.ts`'s `email_template` comment, which named `EmailTemplateSchema` where the registry resolves `EmailTemplateDefinitionSchema`. That one parenthetical is the documented source of the confusion, including objectui's. The pin is a TypeScript compiler-API test over the package.json exports map (all 16 entries), asserting each removed name has ZERO holders anywhere — not merely that ./system omits it — with anti-vacuity guards on entry resolution and surface size. #4642 established that the conditional-type pin #4610 left here is a no-op (tsconfig excludes **/*.test.ts), so it is folded in rather than left as a gate that cannot fail. Co-Authored-By: Claude <noreply@anthropic.com> * chore(spec): regenerate the three ratchets after merging #4789 — its rename must not ride out on this branch `git merge origin/main` brought in #4789 (kernel PackageDependencySchema -> ResolvedPackageDependencySchema, dual-source C7), which touches the same three generated artifacts this branch does. The merge reported NO conflicts and left NO conflict markers, and it was wrong in all three: api-surface.json re-added `PackageDependency (type)` + `PackageDependencySchema (const)` and dropped `ResolvedPackageDependency(Schema)` authorable-surface.json re-added the 4 `kernel/PackageDependency:*` lines and dropped the 4 `kernel/ResolvedPackageDependency:*` ones json-schema.manifest.json re-added `kernel/PackageDependency` and dropped `kernel/ResolvedPackageDependency` json-schema.manifest.json is routed to the `merge=os-regen` driver, which defers rather than regenerates, so nothing textual signals this — the C17/C10 silent revert, reproduced. `git merge-tree` does not run external merge drivers and so cannot see it either. Resolved the way #4783 did, without any textual merge: reset all three (plus api-surface-signatures.json) to origin/main, re-applied ONLY this PR's own deletion to the two hand-ratcheted files, then re-ran the generators over the merged source. The 22 authorable-surface lines and 4 manifest keys are once again deliberate deletions, now anchored at merge base ffab803, which gen:schema re-proved under #4650 route 3 ("def no longer emitted by this build"). Delta vs origin/main is now pure deletion in all three, with #4789's rename intact: api-surface.json -8 (4 const + 4 type), 0 insertions authorable-surface.json -22 lines, 0 insertions json-schema.manifest.json -4 keys, 0 insertions check:dual-source-exports reports 0 accepted dual-source (#4789's shrink to [] survives; this branch does not carry it back to 2). renamed-defs.ts is byte-identical to main and keeps all 6 entries including #4789's. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 127f091 commit 023c00b

8 files changed

Lines changed: 308 additions & 597 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
"@objectstack/spec": major
3+
---
4+
5+
feat(spec)!: `@objectstack/spec/system` no longer exports the orphan notification-template vocabulary — `EmailTemplate(Schema)`, `SMSTemplate(Schema)`, `PushNotification(Schema)`, `InAppNotification(Schema)` (#4616)
6+
7+
These four schemas existed **only** as the member shapes of the
8+
`NotificationConfigSchema.template` union, and #4610 (#4535 C3) deleted that
9+
union. Since then they have been reachable from no parent schema and from no
10+
metadata-type root: nothing in framework, cloud or objectui parsed a document
11+
against them, so they declared delivery capability the runtime never read
12+
(ADR-0049 enforce-or-remove, resolved by REMOVE in the v17 breaking window).
13+
14+
Migration — one line each, and in every case the replacement already exists:
15+
16+
- FROM `import { EmailTemplateSchema, type EmailTemplate } from '@objectstack/spec/system'`
17+
TO `import { EmailTemplateDefinitionSchema, type EmailTemplateDefinition } from '@objectstack/spec/system'`.
18+
**Shape change** — this is a different, richer contract, not a rename:
19+
`EmailTemplateDefinitionSchema` is keyed `name` + `locale` (not `id`), splits
20+
the body into `bodyHtml` / `bodyText` (not `body` + `bodyType`), and adds
21+
`label` / `category` / `active` / `fromOverride` / `replyTo`. It is also a
22+
`strictObject`, so the old keys are rejected loudly rather than stripped.
23+
This is the schema the `email_template` metadata kind has resolved to since
24+
spec **7.1.0**, which demoted `EmailTemplateSchema` when it fixed that Prime
25+
Directive #8 double-declaration and kept it "only as an inline sub-shape
26+
inside `Notification`" — #4610 removed that holder, and #4616 finishes the
27+
job. If your code registers a client-side or publish-time validator for
28+
`email_template`, it must point at `EmailTemplateDefinitionSchema`;
29+
`BUILTIN_METADATA_TYPE_SCHEMAS` (`kernel/metadata-type-schemas.ts`) is the
30+
authority.
31+
- FROM `import { SMSTemplateSchema, type SMSTemplate } from '@objectstack/spec/system'`
32+
TO: no spec replacement, and none is needed. SMS templates are
33+
`sys_notification_template` rows resolved by `(topic, 'sms', locale)`
34+
(`service-messaging/src/sms-channel.ts`) and rendered by
35+
`template-renderer.ts`; the provider-side template is Aliyun's pre-registered
36+
`TemplateCode` in `service-sms` — a vendor API shape, never a spec constant.
37+
- FROM `import { PushNotificationSchema, type PushNotification } from '@objectstack/spec/system'`
38+
and FROM `import { InAppNotificationSchema, type InAppNotification } from '@objectstack/spec/system'`
39+
TO: no replacement. Neither channel has a delivery implementation (#3197):
40+
the dispatcher dead-letters any message addressed to them, so these payload
41+
shapes advertised a capability nothing delivers. The live delivery ingress is
42+
`NotificationService.emit` (`INotificationService`,
43+
`@objectstack/spec/contracts`); the in-app bell reads `./api`'s
44+
`Notification(Schema)` inbox row; the presentation vocabulary is
45+
`@objectstack/spec/ui` (`NotificationTypeSchema`, `NotificationSeveritySchema`,
46+
`NotificationPositionSchema`, `NotificationActionSchema` — all unchanged).
47+
48+
Unchanged and explicitly NOT part of this removal:
49+
`@objectstack/spec/system`'s `NotificationChannel(Schema)` (live — re-exported
50+
by `@objectstack/spec/contracts`, consumed by `service-messaging`),
51+
`EmailTemplateDefinition*`, and every `@objectstack/spec/ui` notification
52+
export.
53+
54+
No ADR-0087 D2 conversion accompanies this change, deliberately: a conversion
55+
rewrites authored or stored sources, and these defs were reachable from no
56+
metadata-type root, so `os migrate meta` would have nothing to match. The
57+
removal is a TypeScript export-surface break only — same disposition as #4610
58+
in this very module. `json-schema.manifest.json` loses 4 keys and
59+
`authorable-surface.json` loses their 22 lines; both deletions are adjudicated
60+
by `gen:schema`'s #4650 route-3 check ("def no longer emitted by this build").

content/docs/references/system/notification.mdx

Lines changed: 12 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,23 @@ description: Notification protocol schemas
55

66
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
77

8-
Email Template Schema
8+
Notification Channel Enum
99

10-
Defines the structure and content of email notifications.
10+
Supported notification delivery channels.
1111

12-
Supports variables for personalization and file attachments.
12+
⚠️ PARTIALLY ENFORCED — the delivery channels actually registered by
1313

14-
@example
14+
`service-messaging` are `inbox`, `email`, and `sms` (#3197). `push`,
1515

16-
```json
16+
`slack`, `teams`, and `webhook` have no delivery implementation, and the
1717

18-
\{
18+
dispatcher dead-letters any message addressed to an unregistered channel.
1919

20-
"id": "welcome-email",
20+
Note also the naming drift: this enum says `in-app` while the implemented
2121

22-
"subject": "Welcome to \{\{company_name\}\}",
22+
channel registers as `inbox` (which this enum does not contain) —
2323

24-
"body": "<h1>Welcome \{\{user_name\}\}!</h1>",
25-
26-
"bodyType": "html",
27-
28-
"variables": ["company_name", "user_name"],
29-
30-
"attachments": [
31-
32-
\{
33-
34-
"name": "guide.pdf",
35-
36-
"url": "https://example.com/guide.pdf"
37-
38-
\}
39-
40-
]
41-
42-
\}
43-
44-
```
24+
reconcile before wiring this enum into the runtime.
4525

4626
<Callout type="info">
4727
**Source:** `packages/spec/src/system/notification.zod.ts`
@@ -50,45 +30,13 @@ Supports variables for personalization and file attachments.
5030
## TypeScript Usage
5131

5232
```typescript
53-
import { EmailTemplateSchema, InAppNotificationSchema, NotificationChannelSchema, PushNotificationSchema, SMSTemplateSchema } from '@objectstack/spec/system';
54-
import type { EmailTemplate, InAppNotification, NotificationChannel, PushNotification, SMSTemplate } from '@objectstack/spec/system';
33+
import { NotificationChannelSchema } from '@objectstack/spec/system';
34+
import type { NotificationChannel } from '@objectstack/spec/system';
5535

5636
// Validate data
57-
const result = EmailTemplateSchema.parse(data);
37+
const result = NotificationChannelSchema.parse(data);
5838
```
5939

60-
---
61-
62-
## EmailTemplate
63-
64-
### Properties
65-
66-
| Property | Type | Required | Description |
67-
| :--- | :--- | :--- | :--- |
68-
| **id** | `string` || Template identifier |
69-
| **subject** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` || Email subject — supports `{{var}`} interpolation |
70-
| **body** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` || Email body content — supports `{{var}`} interpolation |
71-
| **bodyType** | `Enum<'text' \| 'html' \| 'markdown'>` | optional | Body content type |
72-
| **variables** | `string[]` | optional | Template variables |
73-
| **attachments** | `{ name: string; url: string }[]` | optional | Email attachments |
74-
75-
76-
---
77-
78-
## InAppNotification
79-
80-
### Properties
81-
82-
| Property | Type | Required | Description |
83-
| :--- | :--- | :--- | :--- |
84-
| **title** | `string` || Notification title |
85-
| **message** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` || Notification message — supports `{{var}`} interpolation |
86-
| **type** | `Enum<'info' \| 'success' \| 'warning' \| 'error'>` || Notification type |
87-
| **actionUrl** | `string` | optional | Action URL |
88-
| **dismissible** | `boolean` | optional | User dismissible |
89-
| **expiresAt** | `number` | optional | Expiration timestamp |
90-
91-
9240
---
9341

9442
## NotificationChannel
@@ -108,33 +56,3 @@ Notification delivery channel (implemented today: inbox, email, sms — push/sla
10856

10957
---
11058

111-
## PushNotification
112-
113-
### Properties
114-
115-
| Property | Type | Required | Description |
116-
| :--- | :--- | :--- | :--- |
117-
| **title** | `string` || Notification title |
118-
| **body** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` || Notification body — supports `{{var}`} interpolation |
119-
| **icon** | `string` | optional | Notification icon URL |
120-
| **badge** | `number` | optional | Badge count |
121-
| **data** | `Record<string, any>` | optional | Custom data |
122-
| **actions** | `{ action: string; title: string }[]` | optional | Notification actions |
123-
124-
125-
---
126-
127-
## SMSTemplate
128-
129-
### Properties
130-
131-
| Property | Type | Required | Description |
132-
| :--- | :--- | :--- | :--- |
133-
| **id** | `string` || Template identifier |
134-
| **message** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` || SMS message content — supports `{{var}`} interpolation |
135-
| **maxLength** | `number` | optional | Maximum message length |
136-
| **variables** | `string[]` | optional | Template variables |
137-
138-
139-
---
140-

packages/spec/api-surface.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -896,15 +896,13 @@
896896
"EmailProviderSchema (const)",
897897
"EmailServiceConfig (type)",
898898
"EmailServiceConfigSchema (const)",
899-
"EmailTemplate (type)",
900899
"EmailTemplateDefinition (type)",
901900
"EmailTemplateDefinitionCategory (type)",
902901
"EmailTemplateDefinitionCategorySchema (const)",
903902
"EmailTemplateDefinitionInput (type)",
904903
"EmailTemplateDefinitionSchema (const)",
905904
"EmailTemplateDefinitionVariable (type)",
906905
"EmailTemplateDefinitionVariableSchema (const)",
907-
"EmailTemplateSchema (const)",
908906
"EmailVerificationConfig (type)",
909907
"EmailVerificationConfigSchema (const)",
910908
"EncryptionAlgorithm (type)",
@@ -950,8 +948,6 @@
950948
"HttpServerConfigSchema (const)",
951949
"ISettingsCapability (interface)",
952950
"ISettingsClient (interface)",
953-
"InAppNotification (type)",
954-
"InAppNotificationSchema (const)",
955951
"Incident (type)",
956952
"IncidentCategory (type)",
957953
"IncidentCategorySchema (const)",
@@ -1146,8 +1142,6 @@
11461142
"PlanSchema (const)",
11471143
"PresignedUrlConfig (type)",
11481144
"PresignedUrlConfigSchema (const)",
1149-
"PushNotification (type)",
1150-
"PushNotificationSchema (const)",
11511145
"QueueConfig (type)",
11521146
"QueueConfigInput (type)",
11531147
"QueueConfigSchema (const)",
@@ -1188,8 +1182,6 @@
11881182
"RowLevelIsolationStrategyInput (type)",
11891183
"RowLevelIsolationStrategySchema (const)",
11901184
"SETTINGS_CHANGE_EVENT (const)",
1191-
"SMSTemplate (type)",
1192-
"SMSTemplateSchema (const)",
11931185
"SamplingDecision (type)",
11941186
"SamplingStrategyType (type)",
11951187
"Schedule (type)",

packages/spec/authorable-surface.json

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5903,12 +5903,6 @@
59035903
"system/EmailServiceConfig:persist",
59045904
"system/EmailServiceConfig:provider",
59055905
"system/EmailServiceConfig:retries",
5906-
"system/EmailTemplate:attachments",
5907-
"system/EmailTemplate:body",
5908-
"system/EmailTemplate:bodyType",
5909-
"system/EmailTemplate:id",
5910-
"system/EmailTemplate:subject",
5911-
"system/EmailTemplate:variables",
59125906
"system/EmailTemplateDefinition:_lock",
59135907
"system/EmailTemplateDefinition:_lockDocsUrl",
59145908
"system/EmailTemplateDefinition:_lockReason",
@@ -6010,12 +6004,6 @@
60106004
"system/HttpServerConfig:security",
60116005
"system/HttpServerConfig:static",
60126006
"system/HttpServerConfig:trustProxy",
6013-
"system/InAppNotification:actionUrl",
6014-
"system/InAppNotification:dismissible",
6015-
"system/InAppNotification:expiresAt",
6016-
"system/InAppNotification:message",
6017-
"system/InAppNotification:title",
6018-
"system/InAppNotification:type",
60196007
"system/Incident:affectedDataClassifications",
60206008
"system/Incident:affectedSystems",
60216009
"system/Incident:category",
@@ -6470,12 +6458,6 @@
64706458
"system/PresignedUrlConfig:operation",
64716459
"system/PresignedUrlConfig:responseContentDisposition",
64726460
"system/PresignedUrlConfig:responseContentType",
6473-
"system/PushNotification:actions",
6474-
"system/PushNotification:badge",
6475-
"system/PushNotification:body",
6476-
"system/PushNotification:data",
6477-
"system/PushNotification:icon",
6478-
"system/PushNotification:title",
64796461
"system/QueueConfig:autoScale",
64806462
"system/QueueConfig:concurrency",
64816463
"system/QueueConfig:deadLetterQueue",
@@ -6536,10 +6518,6 @@
65366518
"system/RowLevelIsolationStrategy:database",
65376519
"system/RowLevelIsolationStrategy:performance",
65386520
"system/RowLevelIsolationStrategy:strategy",
6539-
"system/SMSTemplate:id",
6540-
"system/SMSTemplate:maxLength",
6541-
"system/SMSTemplate:message",
6542-
"system/SMSTemplate:variables",
65436521
"system/SchemaChange:changeType",
65446522
"system/SchemaChange:entityName",
65456523
"system/SchemaChange:entityType",

packages/spec/json-schema.manifest.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,7 +1258,6 @@
12581258
"system/EmailAndPasswordConfig",
12591259
"system/EmailProvider",
12601260
"system/EmailServiceConfig",
1261-
"system/EmailTemplate",
12621261
"system/EmailTemplateDefinition",
12631262
"system/EmailTemplateDefinitionCategory",
12641263
"system/EmailTemplateDefinitionVariable",
@@ -1280,7 +1279,6 @@
12801279
"system/HistogramBucketConfig",
12811280
"system/HttpDestinationConfig",
12821281
"system/HttpServerConfig",
1283-
"system/InAppNotification",
12841282
"system/Incident",
12851283
"system/IncidentCategory",
12861284
"system/IncidentNotificationMatrix",
@@ -1372,7 +1370,6 @@
13721370
"system/PackagePublishResult",
13731371
"system/Plan",
13741372
"system/PresignedUrlConfig",
1375-
"system/PushNotification",
13761373
"system/QueueConfig",
13771374
"system/QuotaEnforcementResult",
13781375
"system/RPO",
@@ -1387,7 +1384,6 @@
13871384
"system/RollbackPlan",
13881385
"system/RouteHandlerMetadata",
13891386
"system/RowLevelIsolationStrategy",
1390-
"system/SMSTemplate",
13911387
"system/SamplingDecision",
13921388
"system/SamplingStrategyType",
13931389
"system/Schedule",

packages/spec/src/kernel/metadata-plugin.zod.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,13 @@ export const MetadataTypeSchema = lazySchema(() => z.enum([
113113
// code contributions: plugin `contributes.routes` + declarative `apis:`
114114
// (router), `defineStack({ functions })` + `contributes.functions`
115115
// (function), and the plugin/service registry itself (service).
116-
'email_template', // Outbound email templates (EmailTemplateSchema)
116+
// #4616: the canonical schema is `EmailTemplateDefinitionSchema`
117+
// (`system/email-template.zod.ts`), which is what `BUILTIN_METADATA_TYPE_SCHEMAS`
118+
// resolves this kind to. This comment used to name `EmailTemplateSchema` — the
119+
// legacy sub-shape spec 7.1.0 demoted when it fixed that Prime Directive #8
120+
// double-declaration, and removed outright in #4616 — which is exactly how
121+
// consumers kept wiring the wrong one.
122+
'email_template', // Outbound email templates (EmailTemplateDefinitionSchema)
117123
'doc', // Package documentation — flat Markdown items (DocSchema, ADR-0046)
118124
'book', // Documentation navigation spine (BookSchema, ADR-0046 §6)
119125

0 commit comments

Comments
 (0)