[{"data":1,"prerenderedAt":1011},["ShallowReactive",2],{"navigation_docs_en":3,"-en-notify-database":441,"-en-notify-database-surround":1006},[4,45,60,81,112,129,146,173,197,213,242,279,356,372,384,403,429],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"queue","i-lucide-layers","\u002Fen\u002Fqueue","en\u002F10.queue",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Overview","\u002Fen\u002Fqueue\u002Foverview","en\u002F10.queue\u002F1.overview","i-lucide-list-ordered",{"title":57,"path":58,"stem":59,"icon":47},"Tasks","\u002Fen\u002Fqueue\u002Ftasks","en\u002F10.queue\u002F2.tasks",{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":44},"events","i-lucide-workflow","\u002Fen\u002Fevents","en\u002F11.events",[66,71,76],{"title":67,"path":68,"stem":69,"icon":70},"Events","\u002Fen\u002Fevents\u002Foverview","en\u002F11.events\u002F1.overview","i-lucide-radio",{"title":72,"path":73,"stem":74,"icon":75},"Outbox","\u002Fen\u002Fevents\u002Foutbox","en\u002F11.events\u002F2.outbox","i-lucide-inbox",{"title":77,"path":78,"stem":79,"icon":80},"Scheduling","\u002Fen\u002Fevents\u002Fscheduler","en\u002F11.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":82,"icon":83,"path":84,"stem":85,"children":86,"page":44},"auth","i-lucide-shield-check","\u002Fen\u002Fauth","en\u002F12.auth",[87,92,97,102,107],{"title":88,"path":89,"stem":90,"icon":91},"Authentication","\u002Fen\u002Fauth\u002Foverview","en\u002F12.auth\u002F1.overview","i-lucide-key-round",{"title":93,"path":94,"stem":95,"icon":96},"RBAC","\u002Fen\u002Fauth\u002Frbac","en\u002F12.auth\u002F2.rbac","i-lucide-users",{"title":98,"path":99,"stem":100,"icon":101},"Policies","\u002Fen\u002Fauth\u002Fpolicy","en\u002F12.auth\u002F3.policy","i-lucide-gavel",{"title":103,"path":104,"stem":105,"icon":106},"Using auth standalone","\u002Fen\u002Fauth\u002Fstandalone","en\u002F12.auth\u002F4.standalone","i-lucide-plug",{"title":108,"path":109,"stem":110,"icon":111},"Social login with goth, standalone","\u002Fen\u002Fauth\u002Fsocial-standalone","en\u002F12.auth\u002F5.social-standalone","i-lucide-log-in",{"title":113,"icon":114,"path":115,"stem":116,"children":117,"page":44},"mail","i-lucide-mail","\u002Fen\u002Fmail","en\u002F13.mail",[118,121,125],{"title":52,"path":119,"stem":120,"icon":114},"\u002Fen\u002Fmail\u002Foverview","en\u002F13.mail\u002F1.overview",{"title":122,"path":123,"stem":124,"icon":114},"SMTP","\u002Fen\u002Fmail\u002Fsmtp","en\u002F13.mail\u002F2.smtp",{"title":126,"path":127,"stem":128,"icon":114},"MJML","\u002Fen\u002Fmail\u002Fmjml","en\u002F13.mail\u002F3.mjml",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":44},"notify","i-lucide-bell","\u002Fen\u002Fnotify","en\u002F14.notify",[135,138,142],{"title":52,"path":136,"stem":137,"icon":131},"\u002Fen\u002Fnotify\u002Foverview","en\u002F14.notify\u002F1.overview",{"title":139,"path":140,"stem":141,"icon":131},"Database channel","\u002Fen\u002Fnotify\u002Fdatabase","en\u002F14.notify\u002F2.database",{"title":143,"path":144,"stem":145,"icon":131},"Broadcast channel","\u002Fen\u002Fnotify\u002Fbroadcast","en\u002F14.notify\u002F3.broadcast",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":44},"storage","i-lucide-hard-drive","\u002Fen\u002Fstorage","en\u002F15.storage",[152,155,159,163,168],{"title":52,"path":153,"stem":154,"icon":148},"\u002Fen\u002Fstorage\u002Foverview","en\u002F15.storage\u002F1.overview",{"title":156,"path":157,"stem":158},"Disk API","\u002Fen\u002Fstorage\u002Fdisk-api","en\u002F15.storage\u002F2.disk-api",{"title":160,"path":161,"stem":162,"icon":148},"Memory and local disk","\u002Fen\u002Fstorage\u002Flocal","en\u002F15.storage\u002F3.local",{"title":164,"path":165,"stem":166,"icon":167},"S3","\u002Fen\u002Fstorage\u002Fs3","en\u002F15.storage\u002F4.s3","i-lucide-cloud",{"title":169,"path":170,"stem":171,"icon":172},"Testing","\u002Fen\u002Fstorage\u002Ftesting","en\u002F15.storage\u002F5.testing","i-lucide-flask-conical",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":44},"telemetry","i-lucide-activity","\u002Fen\u002Ftelemetry","en\u002F16.telemetry",[179,182,187,192],{"title":52,"path":180,"stem":181,"icon":175},"\u002Fen\u002Ftelemetry\u002Foverview","en\u002F16.telemetry\u002F1.overview",{"title":183,"path":184,"stem":185,"icon":186},"Logging","\u002Fen\u002Ftelemetry\u002Flogging","en\u002F16.telemetry\u002F2.logging","i-lucide-scroll-text",{"title":188,"path":189,"stem":190,"icon":191},"OpenTelemetry","\u002Fen\u002Ftelemetry\u002Fopentelemetry","en\u002F16.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":193,"path":194,"stem":195,"icon":196},"Sentry","\u002Fen\u002Ftelemetry\u002Fsentry","en\u002F16.telemetry\u002F4.sentry","i-lucide-bug",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F17.reference",[203,208],{"title":204,"path":205,"stem":206,"icon":207},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F17.reference\u002F1.configuration","i-lucide-settings",{"title":209,"path":210,"stem":211,"icon":212},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F17.reference\u002F2.dependencies","i-lucide-package",{"title":214,"icon":215,"path":216,"stem":217,"children":218,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[219,223,228,232,237],{"title":220,"path":221,"stem":222,"icon":47},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture",{"title":224,"path":225,"stem":226,"icon":227},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":204,"path":229,"stem":230,"icon":231},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F3.configuration","i-lucide-settings-2",{"title":233,"path":234,"stem":235,"icon":236},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":238,"path":239,"stem":240,"icon":241},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":243,"icon":244,"path":245,"stem":246,"children":247,"page":44},"Kit","i-lucide-box","\u002Fen\u002Fkit","en\u002F3.kit",[248,251,256,261,266,270,275],{"title":52,"path":249,"stem":250,"icon":244},"\u002Fen\u002Fkit\u002Foverview","en\u002F3.kit\u002F1.overview",{"title":252,"path":253,"stem":254,"icon":255},"Application lifecycle","\u002Fen\u002Fkit\u002Fapp","en\u002F3.kit\u002F2.app","i-lucide-power",{"title":257,"path":258,"stem":259,"icon":260},"Server","\u002Fen\u002Fkit\u002Fserver","en\u002F3.kit\u002F3.server","i-lucide-server",{"title":262,"path":263,"stem":264,"icon":265},"Worker","\u002Fen\u002Fkit\u002Fworker","en\u002F3.kit\u002F4.worker","i-lucide-cog",{"title":267,"path":268,"stem":269,"icon":70},"Realtime","\u002Fen\u002Fkit\u002Frealtime","en\u002F3.kit\u002F5.realtime",{"title":271,"path":272,"stem":273,"icon":274},"Migrations","\u002Fen\u002Fkit\u002Fmigrations","en\u002F3.kit\u002F6.migrations","i-lucide-file-stack",{"title":276,"path":277,"stem":278,"icon":111},"Social login","\u002Fen\u002Fkit\u002Fsocial-login","en\u002F3.kit\u002F7.social-login",{"title":280,"icon":281,"path":282,"stem":283,"children":284,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F4.cli",[285,288,293,298,303,308,313,318,323,328,333,337,342,347,351],{"title":52,"path":286,"stem":287,"icon":281},"\u002Fen\u002Fcli\u002Foverview","en\u002F4.cli\u002F1.overview",{"title":289,"path":290,"stem":291,"icon":292},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F4.cli\u002F10.add-db","i-lucide-database-zap",{"title":294,"path":295,"stem":296,"icon":297},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F4.cli\u002F11.add-compose","i-lucide-container",{"title":299,"path":300,"stem":301,"icon":302},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F4.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":304,"path":305,"stem":306,"icon":307},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F4.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":309,"path":310,"stem":311,"icon":312},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F4.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":314,"path":315,"stem":316,"icon":317},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F4.cli\u002F15.add-seeder","i-lucide-sprout",{"title":319,"path":320,"stem":321,"icon":322},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F4.cli\u002F2.new-project","i-lucide-folder-plus",{"title":324,"path":325,"stem":326,"icon":327},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F4.cli\u002F3.new-module","i-lucide-blocks",{"title":329,"path":330,"stem":331,"icon":332},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F4.cli\u002F4.add-surface","i-lucide-layers-2",{"title":334,"path":335,"stem":336,"icon":244},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F4.cli\u002F5.add-core",{"title":338,"path":339,"stem":340,"icon":341},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F4.cli\u002F6.add-handler","i-lucide-webhook",{"title":343,"path":344,"stem":345,"icon":346},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F4.cli\u002F7.new-migration","i-lucide-file-plus",{"title":348,"path":349,"stem":350,"icon":265},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F4.cli\u002F8.worker-generators",{"title":352,"path":353,"stem":354,"icon":355},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F4.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"title":357,"icon":227,"path":358,"stem":359,"children":360,"page":44},"errs","\u002Fen\u002Ferrs","en\u002F5.errs",[361,364,368],{"title":52,"path":362,"stem":363,"icon":227},"\u002Fen\u002Ferrs\u002Foverview","en\u002F5.errs\u002F1.overview",{"title":365,"path":366,"stem":367},"API","\u002Fen\u002Ferrs\u002Fapi","en\u002F5.errs\u002F2.api",{"title":369,"path":370,"stem":371,"icon":227},"Integration","\u002Fen\u002Ferrs\u002Fintegration","en\u002F5.errs\u002F3.integration",{"title":373,"icon":231,"path":374,"stem":375,"children":376,"page":44},"envconf","\u002Fen\u002Fenvconf","en\u002F6.envconf",[377,380],{"title":52,"path":378,"stem":379,"icon":231},"\u002Fen\u002Fenvconf\u002Foverview","en\u002F6.envconf\u002F1.overview",{"title":381,"path":382,"stem":383},"Recipes","\u002Fen\u002Fenvconf\u002Frecipes","en\u002F6.envconf\u002F2.recipes",{"title":385,"icon":386,"path":387,"stem":388,"children":389,"page":44},"httperr","i-lucide-globe","\u002Fen\u002Fhttperr","en\u002F7.httperr",[390,393,398],{"title":52,"path":391,"stem":392,"icon":386},"\u002Fen\u002Fhttperr\u002Foverview","en\u002F7.httperr\u002F1.overview",{"title":394,"path":395,"stem":396,"icon":397},"Error responses","\u002Fen\u002Fhttperr\u002Ferror-responses","en\u002F7.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":399,"path":400,"stem":401,"icon":402},"Validation","\u002Fen\u002Fhttperr\u002Fvalidation","en\u002F7.httperr\u002F3.validation","i-lucide-badge-check",{"title":404,"icon":405,"path":406,"stem":407,"children":408,"page":44},"dbx","i-lucide-database","\u002Fen\u002Fdbx","en\u002F8.dbx",[409,412,416,420,425],{"title":52,"path":410,"stem":411,"icon":405},"\u002Fen\u002Fdbx\u002Foverview","en\u002F8.dbx\u002F1.overview",{"title":413,"path":414,"stem":415,"icon":106},"pgx","\u002Fen\u002Fdbx\u002Fpg","en\u002F8.dbx\u002F2.pg",{"title":417,"path":418,"stem":419,"icon":47},"bun","\u002Fen\u002Fdbx\u002Fbunx","en\u002F8.dbx\u002F3.bunx",{"title":421,"path":422,"stem":423,"icon":424},"Transactions","\u002Fen\u002Fdbx\u002Ftransactions","en\u002F8.dbx\u002F4.transactions","i-lucide-git-merge",{"title":426,"path":427,"stem":428,"icon":317},"Seeders","\u002Fen\u002Fdbx\u002Fseed","en\u002F8.dbx\u002F5.seed",{"title":430,"icon":55,"path":431,"stem":432,"children":433,"page":44},"paginate","\u002Fen\u002Fpaginate","en\u002F9.paginate",[434,437],{"title":52,"path":435,"stem":436,"icon":55},"\u002Fen\u002Fpaginate\u002Foverview","en\u002F9.paginate\u002F1.overview",{"title":438,"path":439,"stem":440,"icon":19},"Cursor pagination","\u002Fen\u002Fpaginate\u002Fcursor","en\u002F9.paginate\u002F2.cursor",{"id":442,"title":139,"body":443,"description":999,"extension":1000,"links":1001,"meta":1002,"navigation":1003,"path":140,"seo":1004,"stem":141,"__hash__":1005},"docs_en\u002Fen\u002F14.notify\u002F2.database.md",{"type":444,"value":445,"toc":992},"minimark",[446,454,487,492,516,610,614,623,744,775,819,840,855,859,883,905,909,942,946,988],[447,448,449,450,453],"p",{},"This subpackage gives ",[451,452,130],"code",{}," its durable, queryable channel: import it when a notification needs a persisted, readable history, not just a mail that went out or a live push.",[455,456,461],"pre",{"className":457,"code":458,"language":459,"meta":460,"style":460},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import notifydatabase \"github.com\u002Fgp-system\u002Fnotify\u002Fdatabase\"\n","go","",[451,462,463],{"__ignoreMap":460},[464,465,468,472,476,480,484],"span",{"class":466,"line":467},"line",1,[464,469,471],{"class":470},"s7zQu","import",[464,473,475],{"class":474},"sTEyZ"," notifydatabase ",[464,477,479],{"class":478},"sMK4o","\"",[464,481,483],{"class":482},"sBMFI","github.com\u002Fgp-system\u002Fnotify\u002Fdatabase",[464,485,486],{"class":478},"\"\n",[488,489,491],"h2",{"id":490},"database","Database",[447,493,494,497,498,501,502,505,506,509,510,515],{},[451,495,496],{},"notify\u002Fdatabase"," (+",[451,499,500],{},"notify\u002Fdatabase\u002Fbunx",") is the durable, queryable side of a notification: every ",[451,503,504],{},"Databasable"," notification lands in a ",[451,507,508],{},"notifications"," table, so a recipient gets a persisted, \"notification inbox\" pattern (the Laravel-notifications-esque part of the module) on top of whatever else fires. It builds on ",[511,512,513],"a",{"href":410},[451,514,404],{},", the same way the rest of the kit's persistence does.",[455,517,519],{"className":457,"code":518,"language":459,"meta":460,"style":460},"store := notifydatabase.NewStore(pg.NewDB(pool))       \u002F\u002F pgx\nstore := notifydatabasebunx.NewStore(bunDB)             \u002F\u002F bun, via notify\u002Fdatabase\u002Fbunx\nchannel := notifydatabase.NewChannel(store)\n",[451,520,521,562,587],{"__ignoreMap":460},[464,522,523,526,529,532,535,539,542,545,547,550,552,555,558],{"class":466,"line":467},[464,524,525],{"class":474},"store ",[464,527,528],{"class":478},":=",[464,530,531],{"class":474}," notifydatabase",[464,533,534],{"class":478},".",[464,536,538],{"class":537},"s2Zo4","NewStore",[464,540,541],{"class":478},"(",[464,543,544],{"class":474},"pg",[464,546,534],{"class":478},[464,548,549],{"class":537},"NewDB",[464,551,541],{"class":478},[464,553,554],{"class":474},"pool",[464,556,557],{"class":478},"))",[464,559,561],{"class":560},"sHwdD","       \u002F\u002F pgx\n",[464,563,565,567,569,572,574,576,578,581,584],{"class":466,"line":564},2,[464,566,525],{"class":474},[464,568,528],{"class":478},[464,570,571],{"class":474}," notifydatabasebunx",[464,573,534],{"class":478},[464,575,538],{"class":537},[464,577,541],{"class":478},[464,579,580],{"class":474},"bunDB",[464,582,583],{"class":478},")",[464,585,586],{"class":560},"             \u002F\u002F bun, via notify\u002Fdatabase\u002Fbunx\n",[464,588,590,593,595,597,599,602,604,607],{"class":466,"line":589},3,[464,591,592],{"class":474},"channel ",[464,594,528],{"class":478},[464,596,531],{"class":474},[464,598,534],{"class":478},[464,600,601],{"class":537},"NewChannel",[464,603,541],{"class":478},[464,605,606],{"class":474},"store",[464,608,609],{"class":478},")\n",[488,611,613],{"id":612},"record-and-store","Record and Store",[447,615,616,617,619,620,622],{},"Persists ",[451,618,504],{}," notifications into a ",[451,621,508],{}," table:",[455,624,628],{"className":625,"code":626,"language":627,"meta":460,"style":460},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE TABLE notifications (\n    id           uuid        PRIMARY KEY,\n    recipient_id text        NOT NULL,\n    name         text        NOT NULL,\n    payload      jsonb       NOT NULL DEFAULT '{}'::jsonb,\n    read_at      timestamptz,\n    created_at   timestamptz NOT NULL DEFAULT now()\n);\n","sql",[451,629,630,645,657,670,683,708,719,738],{"__ignoreMap":460},[464,631,632,636,639,642],{"class":466,"line":467},[464,633,635],{"class":634},"sbssI","CREATE",[464,637,638],{"class":634}," TABLE",[464,640,641],{"class":537}," notifications",[464,643,644],{"class":474}," (\n",[464,646,647,650,654],{"class":466,"line":564},[464,648,649],{"class":474},"    id           uuid        ",[464,651,653],{"class":652},"spNyl","PRIMARY KEY",[464,655,656],{"class":474},",\n",[464,658,659,662,665,668],{"class":466,"line":589},[464,660,661],{"class":474},"    recipient_id ",[464,663,664],{"class":652},"text",[464,666,667],{"class":634},"        NOT NULL",[464,669,656],{"class":474},[464,671,673,676,679,681],{"class":466,"line":672},4,[464,674,675],{"class":634},"    name",[464,677,678],{"class":652},"         text",[464,680,667],{"class":634},[464,682,656],{"class":474},[464,684,686,689,692,695,698,702,705],{"class":466,"line":685},5,[464,687,688],{"class":474},"    payload      jsonb       ",[464,690,691],{"class":634},"NOT NULL",[464,693,694],{"class":652}," DEFAULT",[464,696,697],{"class":478}," '",[464,699,701],{"class":700},"sfazB","{}",[464,703,704],{"class":478},"'",[464,706,707],{"class":474},"::jsonb,\n",[464,709,711,714,717],{"class":466,"line":710},6,[464,712,713],{"class":474},"    read_at      ",[464,715,716],{"class":652},"timestamptz",[464,718,656],{"class":474},[464,720,722,725,727,730,732,735],{"class":466,"line":721},7,[464,723,724],{"class":474},"    created_at   ",[464,726,716],{"class":652},[464,728,729],{"class":634}," NOT NULL",[464,731,694],{"class":652},[464,733,734],{"class":634}," now",[464,736,737],{"class":478},"()\n",[464,739,741],{"class":466,"line":740},8,[464,742,743],{"class":474},");\n",[447,745,746,747,750,751,754,755,758,759,762,763,766,767,770,771,774],{},"No ",[451,748,749],{},"notifiable_type"," column (the kit has no polymorphic user model, a recipient is just a ",[451,752,753],{},"string"," id), no ",[451,756,757],{},"updated_at"," (rows only ever gain ",[451,760,761],{},"read_at","). The channel requires ",[451,764,765],{},"Recipient.ID","; an on-demand send (no ID) errors on this channel: name only ",[451,768,769],{},"notify.ChannelMail"," in ",[451,772,773],{},"Via"," for those.",[447,776,777,778,781,782,785,786,789,790,793,794,785,797,785,800,803,804,807,808,811,812,814,815,818],{},"The ",[451,779,780],{},"Store"," interface covers the universal 90%: ",[451,783,784],{},"Insert",", ",[451,787,788],{},"List"," (",[451,791,792],{},"ListOptions{UnreadOnly, Limit, Offset}","), ",[451,795,796],{},"CountUnread",[451,798,799],{},"MarkRead",[451,801,802],{},"MarkAllRead",". Every read\u002Fupdate takes ",[451,805,806],{},"recipientID"," explicitly, so a handler built on top can never touch another recipient's rows by accident. Building the actual HTTP inbox (response DTOs, the ",[451,809,810],{},"rbac.Identity.Subject"," → ",[451,813,806],{}," guard) is your module's own territory: the kit stops at the Store, the same boundary the ",[511,816,817],{"href":73},"outbox"," draws around its own table.",[447,820,821,824,825,827,828,831,832,836,837,839],{},[451,822,823],{},"NewChannel(store)"," wraps a ",[451,826,780],{}," into the ",[451,829,830],{},"notify.Channel"," the ",[511,833,835],{"href":834},"\u002Fen\u002Fnotify\u002Foverview#the-hub","Hub"," dispatches to; it is what a ",[451,838,504],{}," notification's content routes through.",[447,841,842,843,846,847,851,852,854],{},"There is no ",[451,844,845],{},"NOTIFY_*"," env config: channel enablement ",[848,849,850],"em",{},"is"," the wiring; the ",[451,853,835],{}," contains exactly the channels the entry point constructs.",[488,856,858],{"id":857},"memorystore","MemoryStore",[455,860,862],{"className":457,"code":861,"language":459,"meta":460,"style":460},"store := notifydatabase.NewMemoryStore() \u002F\u002F implements the full Store, including the read side\n",[451,863,864],{"__ignoreMap":460},[464,865,866,868,870,872,874,877,880],{"class":466,"line":467},[464,867,525],{"class":474},[464,869,528],{"class":478},[464,871,531],{"class":474},[464,873,534],{"class":478},[464,875,876],{"class":537},"NewMemoryStore",[464,878,879],{"class":478},"()",[464,881,882],{"class":560}," \u002F\u002F implements the full Store, including the read side\n",[447,884,885,887,888,890,891,894,895,897,898,904],{},[451,886,858],{}," is a test double: it implements every ",[451,889,780],{}," method, so a product can test its inbox handlers (list, mark read, count unread) without Postgres. Pair it with ",[451,892,893],{},"notifydatabase.NewChannel(store)"," for content-rendering coverage in a ",[451,896,835],{},", the same way ",[511,899,901],{"href":900},"\u002Fen\u002Fmail\u002Foverview#dev-mailers-memory-log-and-discard",[451,902,903],{},"mail.NewMemory()"," stands in for a real mailer.",[488,906,908],{"id":907},"migration","Migration",[447,910,777,911,913,914,920,921,924,925,930,931,934,935,938,939,941],{},[451,912,508],{}," table arrives as a goose migration, the same pattern ",[511,915,917],{"href":916},"\u002Fen\u002Fevents\u002Foutbox#the-table-and-the-migration",[451,918,919],{},"outbox.MigrationSQL"," uses: ",[451,922,923],{},"notifydatabase.MigrationSQL"," is the schema's source of truth in the package, and ",[511,926,928],{"href":927},"\u002Fen\u002Fnotify\u002Foverview#add-notification",[451,929,304],{},"'s first run writes it into the project's ",[451,932,933],{},"migrations\u002F"," directory at the next available timestamp. Run it before starting the service that owns the inbox: ",[451,936,937],{},"go run .\u002Fcmd\u002Fmigrate up"," (see ",[511,940,271],{"href":272},").",[488,943,945],{"id":944},"related-pages","Related pages",[947,948,949,961,967],"ul",{},[950,951,952,954,955,785,957,960],"li",{},[511,953,52],{"href":136},": the ",[451,956,835],{},[451,958,959],{},"Notification",", and the mail channel.",[950,962,963,966],{},[511,964,965],{"href":144},"Broadcast",": the live-push companion to this durable channel.",[950,968,969,974,975,980,981,983,984,987],{},[511,970,971],{"href":414},[451,972,973],{},"dbx: pgx"," and ",[511,976,977],{"href":418},[451,978,979],{},"dbx: bunx",": the executors ",[451,982,538],{}," and the ",[451,985,986],{},"bunx"," adapter build on.",[989,990,991],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":460,"searchDepth":564,"depth":564,"links":993},[994,995,996,997,998],{"id":490,"depth":564,"text":491},{"id":612,"depth":564,"text":613},{"id":857,"depth":564,"text":858},{"id":907,"depth":564,"text":908},{"id":944,"depth":564,"text":945},"The durable database notification channel.","md",null,{},{"icon":131},{"title":139,"description":999},"hwN-Bz_ZCuqQxVquo24XMs8SsGk5yrA9_cfzZDgjCdg",[1007,1009],{"title":52,"path":136,"stem":137,"description":1008,"icon":131,"children":-1},"Multi-channel notifications: one payload, several channels (database, mail, broadcast), driven by a shared Hub.",{"title":143,"path":144,"stem":145,"description":1010,"icon":131,"children":-1},"The realtime broadcast notification channel.",1785445902605]