Wire an email-template barrel and move the reminder sweeps onto it - #99
Merged
Conversation
Closes the app's only localizable notification path. `src/email-templates/` now exists with a named `dulyEmailTemplates` array, `objectstack.config.ts` carries the one `emailTemplates:` entry, and the three reminder sweeps name a `template` + `templateData` instead of inline English `title`/`message`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p
The inbox-row probe waited 15s inside vitest's default 5s test timeout, so a missing delivery failed with the generic timeout instead of the labelled message naming what never arrived. Measured on the dangling-name ablation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #69
All three steps of the card, not just the barrel.
src/email-templates/index.tsexports a nameddulyEmailTemplatesarray, carrying the same "named array, neverObject.values" comment as every other barrel in this repo.objectstack.config.tsgains exactly two lines — the import andemailTemplates: dulyEmailTemplates— in the same shape as the pre-created empty barrels already listed there.notifynodes swapped from inlinetitle/messagetotemplate+templateData. The §8 deviation recorded insrc/flows/reminders.flow.ts's header is gone with them; no display text is authored in that file any more.What a "bundle" is here
One
(name, locale)ROW, not one template.IEmailServiceresolves(name, locale)at delivery, so each of the three names carries two rows —enandzh-CN, exactly the two localesi18n.supportedLocalesdeclares. Six rows, three names.duly.task_lead_time·duly.task_due_soon·duly.task_overdue.This does not add a translation-coverage check — that is #18's deliverable, and #18's shape-discovering gate sees these rows the moment it lands. The only locale assertion in this PR is that each referenced bundle has an
enrow (the source-language anchor the app's owndefaultLocale: 'en'resolves to); "every supported locale is covered" is deliberately left to #18.The notifications still send — measured, with the body
test/email-templates.test.tsboots a real kernel with the real automation, job, messaging and email services, drives the realTimeRelativeTriggersweep (the job service'strigger()runs the same handler the 08:00 cron would), and reads the row the inbox channel wrote:and the same bundle at
locale: 'zh-CN'resolves to这项任务已进入你的待办列表,截止日期 2026-09-08。— which is the thing this card bought.Why the assertion is on the body and not on "a notification was emitted": a template that resolves to nothing emits a notification too. Ablated — one character off the name (
duly.task_lead_tim) — the flow run log is byte-identical to the green run:The only difference is that no inbox row is ever written: the inbox channel classifies
TEMPLATE_NOT_FOUNDas PERMANENT, so the delivery dead-letters while the run reports success. Three tests go red on that ablation, including the end-to-end one. Nothing else in the toolchain catches it —pnpm validateparses the bundles (measured: an unrecognized key inside one takes validate to exit 1 naming the key) but never checks atemplatename on a notify node against them.Two measured details worth reviewing
{{{…}}}insubject/bodyText,{{…}}inbodyHtml.renderTemplateHTML-escapes a double-brace hole. The inbox writes the rendered subject intotitleand the rendered text intobody_md, neither of which is an HTML document, so the escaping form would put'on screen for every duty whose subject contains an apostrophe — whichtitle: '{record.subject}'never did. Measured both ways;bodyHtmlkeeps the escaping form.bodyTextis authored, not derived. Omitted, the service derives it by stripping tags frombodyHtml, which would make the in-app notification body a side effect of the markup. Authored, the sentence the owner reads is the same one the inlinemessagesent before this card.Five new devDependencies
@objectstack/{service-automation,service-job,service-messaging,plugin-email,trigger-schedule}.email,messagingandjobare inPLATFORM_ALWAYS_ON_CAPABILITIESandtriggersis already declared, soobjectstack devmounts all five for real — but the CLI owns that list andcreateStandaloneStack()returns only the datasource/metadata/ObjectQL base, so the suite has to mount them itself to exercise the delivery path the app actually runs on. Dev-only: nothing insrc/imports them.Gates
pnpm validate && pnpm typecheck && pnpm test && pnpm build— all green at4ca5549(the branch head), 27 files / 674 tests. No changeset: this repo has no changeset mechanism.Landing first as far as
origin/mainshows (75d086f, unmoved) — #18 mergesmainand re-runs.Generated by Claude Code
Generated by Claude Code