[{"data":1,"prerenderedAt":153},["ShallowReactive",2],{"i-lucide:layers":3,"i-lucide:git-commit-horizontal":8,"i-lucide:refresh-cw":10,"i-lucide:book-open":12,"i-lucide:image":14,"i-lucide:webhook":16,"i-lucide:home":18,"i-lucide:layout-grid":20,"i-lucide:tag":22,"i-lucide:newspaper":24,"i-lucide:map":26,"i-lucide:flask-conical":28,"i-lucide:arrow-right":30,"i-lucide:chevron-right":32,"i-lucide:search":34,"i-lucide:monitor":36,"content:\u002Finternal\u002Farchitecture\u002Fnotifications":38,"i-lucide:info":151,"i-lucide:layers-2":148,"i-lucide:key-round":148,"i-lucide:shield-check":148,"i-lucide:box":148,"i-lucide:share-2":148,"i-lucide:clock":148,"i-lucide:dices":148,"i-lucide:building-2":148,"i-lucide:sprout":148,"i-lucide:puzzle":148,"i-lucide:shield-alert":148,"i-lucide:blocks":148,"i-lucide:bell":148,"i-lucide:activity":148},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z\"\u002F>\u003Cpath d=\"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12\"\u002F>\u003Cpath d=\"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"3\"\u002F>\u003Cpath d=\"M3 12h6m6 0h6\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M3 12a9 9 0 0 1 9-9a9.75 9.75 0 0 1 6.74 2.74L21 8\"\u002F>\u003Cpath d=\"M21 3v5h-5m5 4a9 9 0 0 1-9 9a9.75 9.75 0 0 1-6.74-2.74L3 16\"\u002F>\u003Cpath d=\"M8 16H3v5\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 5v16m8.001-2A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2a5 5 0 0 1 4-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\"\u002F>\u003Ccircle cx=\"9\" cy=\"9\" r=\"2\"\u002F>\u003Cpath d=\"m21 15l-3.086-3.086a2 2 0 0 0-2.828 0L6 21\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2\"\u002F>\u003Cpath d=\"m6 17l3.13-5.78c.53-.97.1-2.18-.5-3.1a4 4 0 1 1 6.89-4.06\"\u002F>\u003Cpath d=\"m12 6l3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":19},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8\"\u002F>\u003Cpath d=\"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":21},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"7\" height=\"7\" x=\"3\" y=\"3\" rx=\"1\"\u002F>\u003Crect width=\"7\" height=\"7\" x=\"14\" y=\"3\" rx=\"1\"\u002F>\u003Crect width=\"7\" height=\"7\" x=\"14\" y=\"14\" rx=\"1\"\u002F>\u003Crect width=\"7\" height=\"7\" x=\"3\" y=\"14\" rx=\"1\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":23},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z\"\u002F>\u003Ccircle cx=\"7.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":25},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 18h-5m8-4h-8m-6 8h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2\"\u002F>\u003Crect width=\"8\" height=\"4\" x=\"10\" y=\"6\" rx=\"1\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":27},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0zm.894.211v15M9 3.236v15\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":29},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2M6.453 15h11.094M8.5 2h7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":31},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":33},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":35},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m21 21l-4.34-4.34\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":37},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\"\u002F>\u003Cpath d=\"M8 21h8m-4-4v4\"\u002F>\u003C\u002Fg>",{"id":39,"title":40,"body":41,"description":141,"extension":142,"eyebrow":143,"hostedOnly":6,"meta":144,"navigation":145,"path":146,"seo":147,"short":148,"stem":149,"__hash__":150},"docs\u002Finternal\u002Farchitecture\u002Fnotifications.md","Notifications & Tasks",{"type":42,"value":43,"toc":132},"minimark",[44,48,53,56,60,63,71,75,90,94,101,105,119],[45,46,47],"p",{},"Reaching a user sounds simple and is not. An email can bounce, a device can be offline, a preference can say \"not this kind\", and the event that triggered a notification may be long pruned by the time a retry runs. Chronicler puts all of that behind one bounded context, so the rest of the system can raise a notification and forget about the machinery.",[49,50,52],"h2",{"id":51},"raise-a-fact-let-the-router-decide","Raise a fact, let the router decide",[45,54,55],{},"A source context does not choose a channel or write an email. It pushes a notification through one opaque async contract, and the event it raises carries only semantic facts, what happened and to whom. A router then decides, at handle time, which channels apply, which template to use, how long it lives, whether it supersedes an earlier one, and whether to batch it. Keeping that decision in one place means a new source of notifications does not have to learn how email works.",[49,57,59],{"id":58},"delivery-that-survives-its-own-failures","Delivery that survives its own failures",[45,61,62],{},"Delivery fans out to per-channel workers over a separate, prunable stream: email through a swappable transport, in-app through a durable inbox with a live SSE feed. The reliability details are where the care shows.",[45,64,65,66,70],{},"The email channel works out the recipient's address at send time, from the user id, rather than trusting an address copied onto the original event. The delivery record is a self-contained ",[67,68,69],"strong",{},"outbox"," row that carries the notification kind and its render parameters, so a retry can re-render the message even after the source event has been pruned. A failure is sorted into permanent or transient: a permanent one is marked dead and recorded, a transient one backs off and is retried by a chore, and anything carrying a one-time token is never retried, because a stale token is worse than a missing email. Crucially, the channel worker never returns an error for a send failure, so one undeliverable address cannot crash-loop and poison the whole worker.",[49,72,74],{"id":73},"when-an-operator-has-to-step-in","When an operator has to step in",[45,76,77,78,81,82,85,86,89],{},"Operators can see the delivery ledger, scoped like the audit log, and act on a stuck message. ",[67,79,80],{},"Revive"," returns a dead delivery to the retry queue, so a transient outage no longer strands mail forever. ",[67,83,84],{},"Cancel"," stops a delivery before it goes. ",[67,87,88],{},"Resend"," re-issues an already-sent notification as a new one, linked to the original. Reading the rendered content of a message is gated behind its own separate permission, because the convenience of a preview should not quietly hand every operator the contents of users' mail.",[49,91,93],{"id":92},"tasks-are-the-other-half","Tasks are the other half",[45,95,96,97,100],{},"A notification is a nudge that happens once. A ",[67,98,99],{},"task"," is a durable item that sits there until it is dealt with: a self-authored todo, a banner the user must acknowledge, an onboarding step, a schema problem to fix. One task aggregate covers all of them through a category and a typed detail, with a shared open-and-resolve lifecycle. A source context can raise a one-off task, or declare the full set of problems for a target so that fixed ones heal themselves. Who sees a task is worked out late, by matching an audience token against the user's live grants. A task may send a notification, but the sending is the notification context's job.",[49,102,104],{"id":103},"where-this-connects","Where this connects",[45,106,107,108,113,114,118],{},"Notifications lean on the durable read-model state described in ",[109,110,112],"a",{"href":111},"\u002Finternal\u002Farchitecture\u002Fobservability","Observability and operations",", and tasks resolve their audience through ",[109,115,117],{"href":116},"\u002Finternal\u002Farchitecture\u002Fauthorization","Authorization",".",[120,121,124],"callout",{"title":122,"tone":123},"Read the record for the detail","note",[45,125,126,127,131],{},"This page is the guide. The full records under ",[128,129,130],"code",{},"docs\u002Fadrs"," carry the retry classification, the audience-token model, and the alternatives that were weighed and rejected.",{"title":133,"searchDepth":134,"depth":134,"links":135},"",2,[136,137,138,139,140],{"id":51,"depth":134,"text":52},{"id":58,"depth":134,"text":59},{"id":73,"depth":134,"text":74},{"id":92,"depth":134,"text":93},{"id":103,"depth":134,"text":104},"How Chronicler reaches a user reliably - one context that owns delivery, an outbox that survives retries, and the tasks that demand attention.","md","Architecture",{},{"title":40},"\u002Finternal\u002Farchitecture\u002Fnotifications",{"title":40,"description":141},null,"internal\u002Farchitecture\u002Fnotifications","NPzWyodXRTMLgVkjeDjtx0aX8aaKd7YNmv8QLeRVlV0",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":152},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 16v-4m0-4h.01\"\u002F>\u003C\u002Fg>",1788784066570]