HappyView
-
+
diff --git a/assets/js/2df7fd65.045af8d0.js b/assets/js/2df7fd65.045af8d0.js
deleted file mode 100644
index d4613fe..0000000
--- a/assets/js/2df7fd65.045af8d0.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";(self.webpackChunk_happyview_docs=self.webpackChunk_happyview_docs||[]).push([[1977],{8941:(e,d,n)=>{n.r(d),n.d(d,{assets:()=>l,contentTitle:()=>c,default:()=>x,frontMatter:()=>i,metadata:()=>s,toc:()=>h});const s=JSON.parse('{"id":"guides/event-logs","title":"Event Logs","description":"HappyView maintains an internal event log that records system activity \u2014 lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the admin API.","source":"@site/docs/guides/event-logs.md","sourceDirName":"guides","slug":"/guides/event-logs","permalink":"/guides/event-logs","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Permissions","permalink":"/guides/permissions"},"next":{"title":"Database Setup","permalink":"/guides/database-setup"}}');var r=n(199),t=n(2560);const i={},c="Event Logs",l={},h=[{value:"Event types",id:"event-types",level:2},{value:"Lexicon events",id:"lexicon-events",level:3},{value:"Record events",id:"record-events",level:3},{value:"Script events",id:"script-events",level:3},{value:"User events",id:"user-events",level:3},{value:"Auth events",id:"auth-events",level:3},{value:"API Key events",id:"api-key-events",level:3},{value:"Script Variable events",id:"script-variable-events",level:3},{value:"Hook events",id:"hook-events",level:3},{value:"Backfill events",id:"backfill-events",level:3},{value:"Jetstream events",id:"jetstream-events",level:3},{value:"Querying events",id:"querying-events",level:2},{value:"Retention",id:"retention",level:2},{value:"Next steps",id:"next-steps",level:2}];function o(e){const d={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(d.header,{children:(0,r.jsx)(d.h1,{id:"event-logs",children:"Event Logs"})}),"\n",(0,r.jsxs)(d.p,{children:["HappyView maintains an internal event log that records system activity \u2014 lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the ",(0,r.jsx)(d.a,{href:"/reference/admin/events",children:"admin API"}),"."]}),"\n",(0,r.jsx)(d.h2,{id:"event-types",children:"Event types"}),"\n",(0,r.jsxs)(d.p,{children:["Events follow a ",(0,r.jsx)(d.code,{children:"category.action"})," naming convention. Each event has a severity level (",(0,r.jsx)(d.code,{children:"info"}),", ",(0,r.jsx)(d.code,{children:"warn"}),", or ",(0,r.jsx)(d.code,{children:"error"}),"), an optional ",(0,r.jsx)(d.code,{children:"actor_did"})," (the user who triggered it), an optional ",(0,r.jsx)(d.code,{children:"subject"})," (what was affected), and a ",(0,r.jsx)(d.code,{children:"detail"})," JSON object with event-specific data."]}),"\n",(0,r.jsx)(d.h3,{id:"lexicon-events",children:"Lexicon events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"lexicon.created"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Lexicon NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"revision"}),", ",(0,r.jsx)(d.code,{children:"has_script"}),", ",(0,r.jsx)(d.code,{children:"source"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"lexicon.updated"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Lexicon NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"revision"}),", ",(0,r.jsx)(d.code,{children:"has_script"}),", ",(0,r.jsx)(d.code,{children:"source"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"lexicon.deleted"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Lexicon NSID"}),(0,r.jsx)(d.td,{children:"\u2014"})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["Logged when lexicons are uploaded, updated, or deleted via the ",(0,r.jsx)(d.a,{href:"/reference/admin/lexicons",children:"admin API"}),". The ",(0,r.jsx)(d.code,{children:"actor_did"})," is the user who performed the action."]}),"\n",(0,r.jsx)(d.h3,{id:"record-events",children:"Record events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"record.created"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Record AT URI"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"collection"}),", ",(0,r.jsx)(d.code,{children:"did"}),", ",(0,r.jsx)(d.code,{children:"rkey"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"record.deleted"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Record AT URI"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"collection"}),", ",(0,r.jsx)(d.code,{children:"did"}),", ",(0,r.jsx)(d.code,{children:"rkey"})]})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["Logged when records are received from Jetstream and stored or removed from the local database. These are system-triggered events (",(0,r.jsx)(d.code,{children:"actor_did"})," is null). If a database error occurs during the operation, the same event type is logged with ",(0,r.jsx)(d.code,{children:"error"})," severity and the error message is included in the detail."]}),"\n",(0,r.jsx)(d.h3,{id:"script-events",children:"Script events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"script.executed"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Method NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"method"}),", ",(0,r.jsx)(d.code,{children:"caller_did"}),", ",(0,r.jsx)(d.code,{children:"duration_ms"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"script.error"})}),(0,r.jsx)(d.td,{children:"error"}),(0,r.jsx)(d.td,{children:"Method NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"error"}),", ",(0,r.jsx)(d.code,{children:"script_source"}),", ",(0,r.jsx)(d.code,{children:"input"}),", ",(0,r.jsx)(d.code,{children:"caller_did"}),", ",(0,r.jsx)(d.code,{children:"method"})]})]})]})]}),"\n",(0,r.jsx)(d.p,{children:"Logged when Lua scripts run for XRPC query or procedure endpoints. Script errors capture the full context needed to reproduce and debug the issue: the error message, the complete Lua script source, the input that triggered it, and the caller's DID."}),"\n",(0,r.jsx)(d.admonition,{type:"note",children:(0,r.jsxs)(d.p,{children:["For query scripts (unauthenticated), ",(0,r.jsx)(d.code,{children:"caller_did"})," and ",(0,r.jsx)(d.code,{children:"input"})," are omitted from the detail since queries don't have an authenticated user or request body."]})}),"\n",(0,r.jsx)(d.h3,{id:"user-events",children:"User events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"user.created"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"New user DID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"template"})," (if used)"]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"user.deleted"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Removed user ID"}),(0,r.jsx)(d.td,{children:"\u2014"})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"user.bootstrapped"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Bootstrapped user DID"}),(0,r.jsx)(d.td,{children:"\u2014"})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"user.permissions_updated"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"User ID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"granted"}),", ",(0,r.jsx)(d.code,{children:"revoked"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"user.super_transferred"})}),(0,r.jsx)(d.td,{children:"warn"}),(0,r.jsx)(d.td,{children:"New super user ID"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"from_user_id"})})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["The ",(0,r.jsx)(d.code,{children:"user.bootstrapped"})," event is logged when the first user is auto-promoted to super user (see ",(0,r.jsx)(d.a,{href:"/reference/admin-api#auth",children:"Auth - Auto-bootstrap"}),")."]}),"\n",(0,r.jsx)(d.h3,{id:"auth-events",children:"Auth events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsx)(d.tbody,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"auth.permission_denied"})}),(0,r.jsx)(d.td,{children:"error"}),(0,r.jsx)(d.td,{children:"Endpoint path"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"required_permission"}),", ",(0,r.jsx)(d.code,{children:"user_id"})]})]})})]}),"\n",(0,r.jsx)(d.p,{children:"Logged when a user attempts to access an endpoint they don't have permission for."}),"\n",(0,r.jsx)(d.h3,{id:"api-key-events",children:"API Key events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"api_key.created"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Key ID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"name"}),", ",(0,r.jsx)(d.code,{children:"permissions"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"api_key.revoked"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Key ID"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"name"})})]})]})]}),"\n",(0,r.jsx)(d.h3,{id:"script-variable-events",children:"Script Variable events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"script_variable.upserted"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Variable key"}),(0,r.jsx)(d.td,{children:"\u2014"})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"script_variable.deleted"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Variable key"}),(0,r.jsx)(d.td,{children:"\u2014"})]})]})]}),"\n",(0,r.jsx)(d.h3,{id:"hook-events",children:"Hook events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"hook.executed"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Record AT URI"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"lexicon_id"})})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"hook.dead_lettered"})}),(0,r.jsx)(d.td,{children:"error"}),(0,r.jsx)(d.td,{children:"Record AT URI"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"lexicon_id"}),", ",(0,r.jsx)(d.code,{children:"error"})]})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["Logged when ",(0,r.jsx)(d.a,{href:"/guides/index-hooks",children:"index hooks"})," run. Dead-lettered events indicate a hook failed all retry attempts."]}),"\n",(0,r.jsx)(d.h3,{id:"backfill-events",children:"Backfill events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"backfill.started"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Collection NSID"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"job_id"})})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"backfill.completed"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"Collection NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"job_id"}),", ",(0,r.jsx)(d.code,{children:"total_repos"})]})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"backfill.failed"})}),(0,r.jsx)(d.td,{children:"error"}),(0,r.jsx)(d.td,{children:"Collection NSID"}),(0,r.jsxs)(d.td,{children:[(0,r.jsx)(d.code,{children:"job_id"}),", ",(0,r.jsx)(d.code,{children:"error"})]})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["See ",(0,r.jsx)(d.a,{href:"/guides/backfill",children:"Backfill"})," for background on backfill jobs."]}),"\n",(0,r.jsx)(d.h3,{id:"jetstream-events",children:"Jetstream events"}),"\n",(0,r.jsxs)(d.table,{children:[(0,r.jsx)(d.thead,{children:(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.th,{children:"Event Type"}),(0,r.jsx)(d.th,{children:"Severity"}),(0,r.jsx)(d.th,{children:"Subject"}),(0,r.jsx)(d.th,{children:"Detail"})]})}),(0,r.jsxs)(d.tbody,{children:[(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"jetstream.connected"})}),(0,r.jsx)(d.td,{children:"info"}),(0,r.jsx)(d.td,{children:"\u2014"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"url"})})]}),(0,r.jsxs)(d.tr,{children:[(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"jetstream.disconnected"})}),(0,r.jsx)(d.td,{children:"warn"}),(0,r.jsx)(d.td,{children:"\u2014"}),(0,r.jsx)(d.td,{children:(0,r.jsx)(d.code,{children:"reason"})})]})]})]}),"\n",(0,r.jsxs)(d.p,{children:["Logged when the WebSocket connection to ",(0,r.jsx)(d.a,{href:"https://github.com/bluesky-social/jetstream",children:"Jetstream"})," is established or lost."]}),"\n",(0,r.jsx)(d.h2,{id:"querying-events",children:"Querying events"}),"\n",(0,r.jsx)(d.p,{children:"Use the admin API to query event logs with filters:"}),"\n",(0,r.jsx)(d.pre,{children:(0,r.jsx)(d.code,{className:"language-sh",children:'# Get all errors\ncurl "http://localhost:3000/admin/events?severity=error" -H "$AUTH"\n\n# Get script errors for a specific lexicon\ncurl "http://localhost:3000/admin/events?event_type=script.error&subject=com.example.feed.like" -H "$AUTH"\n\n# Get all lexicon-related events\ncurl "http://localhost:3000/admin/events?category=lexicon" -H "$AUTH"\n\n# Paginate through results\ncurl "http://localhost:3000/admin/events?limit=20&cursor=2026-03-01T11:59:00Z" -H "$AUTH"\n'})}),"\n",(0,r.jsxs)(d.p,{children:["See the ",(0,r.jsx)(d.a,{href:"/reference/admin/events#list-event-logs",children:"Admin API reference"})," for full parameter documentation."]}),"\n",(0,r.jsx)(d.h2,{id:"retention",children:"Retention"}),"\n",(0,r.jsxs)(d.p,{children:["Event logs are automatically cleaned up based on the ",(0,r.jsx)(d.code,{children:"EVENT_LOG_RETENTION_DAYS"})," environment variable (default: 30 days). A background task runs hourly to delete events older than the configured retention period."]}),"\n",(0,r.jsxs)(d.p,{children:["Set ",(0,r.jsx)(d.code,{children:"EVENT_LOG_RETENTION_DAYS=0"})," to disable automatic cleanup and keep logs indefinitely."]}),"\n",(0,r.jsxs)(d.p,{children:["See ",(0,r.jsx)(d.a,{href:"/getting-started/configuration",children:"Configuration"})," for all environment variables."]}),"\n",(0,r.jsx)(d.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,r.jsxs)(d.ul,{children:["\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.a,{href:"/reference/admin/events",children:"Admin API \u2014 Event Logs"})," \u2014 full query parameters and response format"]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.a,{href:"/guides/permissions",children:"Permissions"})," \u2014 control which users can read event logs"]}),"\n",(0,r.jsxs)(d.li,{children:[(0,r.jsx)(d.a,{href:"/reference/troubleshooting",children:"Troubleshooting"})," \u2014 using event logs to diagnose issues"]}),"\n"]})]})}function x(e={}){const{wrapper:d}={...(0,t.R)(),...e.components};return d?(0,r.jsx)(d,{...e,children:(0,r.jsx)(o,{...e})}):o(e)}},2560:(e,d,n)=>{n.d(d,{R:()=>i,x:()=>c});var s=n(63);const r={},t=s.createContext(r);function i(e){const d=s.useContext(t);return s.useMemo(function(){return"function"==typeof e?e(d):{...d,...e}},[d,e])}function c(e){let d;return d=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),s.createElement(t.Provider,{value:d},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/2df7fd65.2b0aab27.js b/assets/js/2df7fd65.2b0aab27.js
new file mode 100644
index 0000000..0ecca13
--- /dev/null
+++ b/assets/js/2df7fd65.2b0aab27.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunk_happyview_docs=self.webpackChunk_happyview_docs||[]).push([[1977],{8941:(e,d,r)=>{r.r(d),r.d(d,{assets:()=>l,contentTitle:()=>c,default:()=>a,frontMatter:()=>i,metadata:()=>n,toc:()=>h});const n=JSON.parse('{"id":"guides/event-logs","title":"Event Logs","description":"HappyView maintains an internal event log that records system activity \u2014 lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the admin API.","source":"@site/docs/guides/event-logs.md","sourceDirName":"guides","slug":"/guides/event-logs","permalink":"/guides/event-logs","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"Permissions","permalink":"/guides/permissions"},"next":{"title":"Database Setup","permalink":"/guides/database-setup"}}');var s=r(199),t=r(2560);const i={},c="Event Logs",l={},h=[{value:"Event types",id:"event-types",level:2},{value:"Lexicon events",id:"lexicon-events",level:3},{value:"Record events",id:"record-events",level:3},{value:"Script events",id:"script-events",level:3},{value:"User events",id:"user-events",level:3},{value:"Auth events",id:"auth-events",level:3},{value:"API Key events",id:"api-key-events",level:3},{value:"Script Variable events",id:"script-variable-events",level:3},{value:"Hook events",id:"hook-events",level:3},{value:"Backfill events",id:"backfill-events",level:3},{value:"Jetstream events",id:"jetstream-events",level:3},{value:"Querying events",id:"querying-events",level:2},{value:"Retention",id:"retention",level:2},{value:"Dead Letters",id:"dead-letters",level:2},{value:"Next steps",id:"next-steps",level:2}];function o(e){const d={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(d.header,{children:(0,s.jsx)(d.h1,{id:"event-logs",children:"Event Logs"})}),"\n",(0,s.jsxs)(d.p,{children:["HappyView maintains an internal event log that records system activity \u2014 lexicon changes, record operations, Lua script executions and errors, user actions, API key events, backfill jobs, and Jetstream connectivity. Events are stored in the database and queryable via the ",(0,s.jsx)(d.a,{href:"/reference/admin/events",children:"admin API"}),"."]}),"\n",(0,s.jsx)(d.h2,{id:"event-types",children:"Event types"}),"\n",(0,s.jsxs)(d.p,{children:["Events follow a ",(0,s.jsx)(d.code,{children:"category.action"})," naming convention. Each event has a severity level (",(0,s.jsx)(d.code,{children:"info"}),", ",(0,s.jsx)(d.code,{children:"warn"}),", or ",(0,s.jsx)(d.code,{children:"error"}),"), an optional ",(0,s.jsx)(d.code,{children:"actor_did"})," (the user who triggered it), an optional ",(0,s.jsx)(d.code,{children:"subject"})," (what was affected), and a ",(0,s.jsx)(d.code,{children:"detail"})," JSON object with event-specific data."]}),"\n",(0,s.jsx)(d.h3,{id:"lexicon-events",children:"Lexicon events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"lexicon.created"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Lexicon NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"revision"}),", ",(0,s.jsx)(d.code,{children:"has_script"}),", ",(0,s.jsx)(d.code,{children:"source"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"lexicon.updated"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Lexicon NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"revision"}),", ",(0,s.jsx)(d.code,{children:"has_script"}),", ",(0,s.jsx)(d.code,{children:"source"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"lexicon.deleted"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Lexicon NSID"}),(0,s.jsx)(d.td,{children:"\u2014"})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["Logged when lexicons are uploaded, updated, or deleted via the ",(0,s.jsx)(d.a,{href:"/reference/admin/lexicons",children:"admin API"}),". The ",(0,s.jsx)(d.code,{children:"actor_did"})," is the user who performed the action."]}),"\n",(0,s.jsx)(d.h3,{id:"record-events",children:"Record events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"record.created"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Record AT URI"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"collection"}),", ",(0,s.jsx)(d.code,{children:"did"}),", ",(0,s.jsx)(d.code,{children:"rkey"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"record.deleted"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Record AT URI"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"collection"}),", ",(0,s.jsx)(d.code,{children:"did"}),", ",(0,s.jsx)(d.code,{children:"rkey"})]})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["Logged when records are received from Jetstream and stored or removed from the local database. These are system-triggered events (",(0,s.jsx)(d.code,{children:"actor_did"})," is null). If a database error occurs during the operation, the same event type is logged with ",(0,s.jsx)(d.code,{children:"error"})," severity and the error message is included in the detail."]}),"\n",(0,s.jsx)(d.h3,{id:"script-events",children:"Script events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"script.executed"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Method NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"method"}),", ",(0,s.jsx)(d.code,{children:"caller_did"}),", ",(0,s.jsx)(d.code,{children:"duration_ms"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"script.error"})}),(0,s.jsx)(d.td,{children:"error"}),(0,s.jsx)(d.td,{children:"Method NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"error"}),", ",(0,s.jsx)(d.code,{children:"script_source"}),", ",(0,s.jsx)(d.code,{children:"input"}),", ",(0,s.jsx)(d.code,{children:"caller_did"}),", ",(0,s.jsx)(d.code,{children:"method"})]})]})]})]}),"\n",(0,s.jsx)(d.p,{children:"Logged when Lua scripts run for XRPC query or procedure endpoints. Script errors capture the full context needed to reproduce and debug the issue: the error message, the complete Lua script source, the input that triggered it, and the caller's DID."}),"\n",(0,s.jsx)(d.admonition,{type:"note",children:(0,s.jsxs)(d.p,{children:["For query scripts (unauthenticated), ",(0,s.jsx)(d.code,{children:"caller_did"})," and ",(0,s.jsx)(d.code,{children:"input"})," are omitted from the detail since queries don't have an authenticated user or request body."]})}),"\n",(0,s.jsx)(d.h3,{id:"user-events",children:"User events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"user.created"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"New user DID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"template"})," (if used)"]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"user.deleted"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Removed user ID"}),(0,s.jsx)(d.td,{children:"\u2014"})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"user.bootstrapped"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Bootstrapped user DID"}),(0,s.jsx)(d.td,{children:"\u2014"})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"user.permissions_updated"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"User ID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"granted"}),", ",(0,s.jsx)(d.code,{children:"revoked"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"user.super_transferred"})}),(0,s.jsx)(d.td,{children:"warn"}),(0,s.jsx)(d.td,{children:"New super user ID"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"from_user_id"})})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["The ",(0,s.jsx)(d.code,{children:"user.bootstrapped"})," event is logged when the first user is auto-promoted to super user (see ",(0,s.jsx)(d.a,{href:"/reference/admin-api#auth",children:"Auth - Auto-bootstrap"}),")."]}),"\n",(0,s.jsx)(d.h3,{id:"auth-events",children:"Auth events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsx)(d.tbody,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"auth.permission_denied"})}),(0,s.jsx)(d.td,{children:"error"}),(0,s.jsx)(d.td,{children:"Endpoint path"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"required_permission"}),", ",(0,s.jsx)(d.code,{children:"user_id"})]})]})})]}),"\n",(0,s.jsx)(d.p,{children:"Logged when a user attempts to access an endpoint they don't have permission for."}),"\n",(0,s.jsx)(d.h3,{id:"api-key-events",children:"API Key events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"api_key.created"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Key ID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"name"}),", ",(0,s.jsx)(d.code,{children:"permissions"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"api_key.revoked"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Key ID"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"name"})})]})]})]}),"\n",(0,s.jsx)(d.h3,{id:"script-variable-events",children:"Script Variable events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"script_variable.upserted"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Variable key"}),(0,s.jsx)(d.td,{children:"\u2014"})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"script_variable.deleted"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Variable key"}),(0,s.jsx)(d.td,{children:"\u2014"})]})]})]}),"\n",(0,s.jsx)(d.h3,{id:"hook-events",children:"Hook events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"hook.executed"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Record AT URI"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"lexicon_id"})})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"hook.dead_lettered"})}),(0,s.jsx)(d.td,{children:"error"}),(0,s.jsx)(d.td,{children:"Record AT URI"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"lexicon_id"}),", ",(0,s.jsx)(d.code,{children:"error"})]})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["Logged when ",(0,s.jsx)(d.a,{href:"/guides/index-hooks",children:"index hooks"})," run. Dead-lettered events indicate a hook failed all retry attempts. You can manage dead letters from the ",(0,s.jsx)(d.strong,{children:"Data > Dead Letters"})," page in the dashboard \u2014 see ",(0,s.jsx)(d.a,{href:"#dead-letters",children:"Dead Letters"})," below."]}),"\n",(0,s.jsx)(d.h3,{id:"backfill-events",children:"Backfill events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"backfill.started"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Collection NSID"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"job_id"})})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"backfill.completed"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"Collection NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"job_id"}),", ",(0,s.jsx)(d.code,{children:"total_repos"})]})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"backfill.failed"})}),(0,s.jsx)(d.td,{children:"error"}),(0,s.jsx)(d.td,{children:"Collection NSID"}),(0,s.jsxs)(d.td,{children:[(0,s.jsx)(d.code,{children:"job_id"}),", ",(0,s.jsx)(d.code,{children:"error"})]})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["See ",(0,s.jsx)(d.a,{href:"/guides/backfill",children:"Backfill"})," for background on backfill jobs."]}),"\n",(0,s.jsx)(d.h3,{id:"jetstream-events",children:"Jetstream events"}),"\n",(0,s.jsxs)(d.table,{children:[(0,s.jsx)(d.thead,{children:(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.th,{children:"Event Type"}),(0,s.jsx)(d.th,{children:"Severity"}),(0,s.jsx)(d.th,{children:"Subject"}),(0,s.jsx)(d.th,{children:"Detail"})]})}),(0,s.jsxs)(d.tbody,{children:[(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"jetstream.connected"})}),(0,s.jsx)(d.td,{children:"info"}),(0,s.jsx)(d.td,{children:"\u2014"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"url"})})]}),(0,s.jsxs)(d.tr,{children:[(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"jetstream.disconnected"})}),(0,s.jsx)(d.td,{children:"warn"}),(0,s.jsx)(d.td,{children:"\u2014"}),(0,s.jsx)(d.td,{children:(0,s.jsx)(d.code,{children:"reason"})})]})]})]}),"\n",(0,s.jsxs)(d.p,{children:["Logged when the WebSocket connection to ",(0,s.jsx)(d.a,{href:"https://github.com/bluesky-social/jetstream",children:"Jetstream"})," is established or lost."]}),"\n",(0,s.jsx)(d.h2,{id:"querying-events",children:"Querying events"}),"\n",(0,s.jsx)(d.p,{children:"Use the admin API to query event logs with filters:"}),"\n",(0,s.jsx)(d.pre,{children:(0,s.jsx)(d.code,{className:"language-sh",children:'# Get all errors\ncurl "http://localhost:3000/admin/events?severity=error" -H "$AUTH"\n\n# Get script errors for a specific lexicon\ncurl "http://localhost:3000/admin/events?event_type=script.error&subject=com.example.feed.like" -H "$AUTH"\n\n# Get all lexicon-related events\ncurl "http://localhost:3000/admin/events?category=lexicon" -H "$AUTH"\n\n# Paginate through results\ncurl "http://localhost:3000/admin/events?limit=20&cursor=2026-03-01T11:59:00Z" -H "$AUTH"\n'})}),"\n",(0,s.jsxs)(d.p,{children:["See the ",(0,s.jsx)(d.a,{href:"/reference/admin/events#list-event-logs",children:"Admin API reference"})," for full parameter documentation."]}),"\n",(0,s.jsx)(d.h2,{id:"retention",children:"Retention"}),"\n",(0,s.jsxs)(d.p,{children:["Event logs are automatically cleaned up based on the ",(0,s.jsx)(d.code,{children:"EVENT_LOG_RETENTION_DAYS"})," environment variable (default: 30 days). A background task runs hourly to delete events older than the configured retention period."]}),"\n",(0,s.jsxs)(d.p,{children:["Set ",(0,s.jsx)(d.code,{children:"EVENT_LOG_RETENTION_DAYS=0"})," to disable automatic cleanup and keep logs indefinitely."]}),"\n",(0,s.jsxs)(d.p,{children:["See ",(0,s.jsx)(d.a,{href:"/getting-started/configuration",children:"Configuration"})," for all environment variables."]}),"\n",(0,s.jsx)(d.h2,{id:"dead-letters",children:"Dead Letters"}),"\n",(0,s.jsxs)(d.p,{children:["When an index hook fails after all retry attempts, the event is stored in the dead letters queue. You can manage dead letters from the ",(0,s.jsx)(d.strong,{children:"Data > Dead Letters"})," page in the dashboard."]}),"\n",(0,s.jsx)(d.p,{children:"From the dead letters page you can:"}),"\n",(0,s.jsxs)(d.ul,{children:["\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"Retry Hook"})," \u2014 replay the stored record through the index hook (use after fixing a hook script)"]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"Re-index"})," \u2014 fetch the record fresh from the PDS and run it through the full indexing pipeline (use when the record may have changed)"]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.strong,{children:"Dismiss"})," \u2014 mark the dead letter as resolved without retrying"]}),"\n"]}),"\n",(0,s.jsx)(d.p,{children:"Bulk actions are available for selected rows or all entries matching the current filters."}),"\n",(0,s.jsx)(d.h2,{id:"next-steps",children:"Next steps"}),"\n",(0,s.jsxs)(d.ul,{children:["\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.a,{href:"/reference/admin/events",children:"Admin API \u2014 Event Logs"})," \u2014 full query parameters and response format"]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.a,{href:"/guides/permissions",children:"Permissions"})," \u2014 control which users can read event logs"]}),"\n",(0,s.jsxs)(d.li,{children:[(0,s.jsx)(d.a,{href:"/reference/troubleshooting",children:"Troubleshooting"})," \u2014 using event logs to diagnose issues"]}),"\n"]})]})}function a(e={}){const{wrapper:d}={...(0,t.R)(),...e.components};return d?(0,s.jsx)(d,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},2560:(e,d,r)=>{r.d(d,{R:()=>i,x:()=>c});var n=r(63);const s={},t=n.createContext(s);function i(e){const d=n.useContext(t);return n.useMemo(function(){return"function"==typeof e?e(d):{...d,...e}},[d,e])}function c(e){let d;return d=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),n.createElement(t.Provider,{value:d},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/runtime~main.4874316a.js b/assets/js/runtime~main.413aac68.js
similarity index 99%
rename from assets/js/runtime~main.4874316a.js
rename to assets/js/runtime~main.413aac68.js
index 95bb42f..093d23f 100644
--- a/assets/js/runtime~main.4874316a.js
+++ b/assets/js/runtime~main.413aac68.js
@@ -1 +1 @@
-(()=>{"use strict";var e,a,c,d,f,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var c=t[e]={exports:{}};return b[e].call(c.exports,c,c.exports,r),c.exports}r.m=b,e=[],r.O=(a,c,d,f)=>{if(!c){var b=1/0;for(i=0;i=f)&&Object.keys(r.O).every(e=>r.O[e](c[o]))?c.splice(o--,1):(t=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};a=a||[null,c({}),c([]),c(c)];for(var t=2&d&&e;"object"==typeof t&&!~a.indexOf(t);t=c(t))Object.getOwnPropertyNames(t).forEach(a=>b[a]=()=>e[a]);return b.default=()=>e,r.d(f,b),f},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((a,c)=>(r.f[c](e,a),a),[])),r.u=e=>"assets/js/"+({20:"919abb94",203:"9985d6d5",339:"2a23be56",787:"280f48ec",1361:"fbd7a87c",1567:"22dd74f7",1952:"2d1b556d",1977:"2df7fd65",2001:"5b2964ea",2007:"c985d368",2009:"8eefb1eb",2278:"23374ca6",2431:"bccc5e9b",2605:"4a041602",2618:"b27c7406",2863:"224113b7",3164:"80ccde35",3197:"5d3a5990",3334:"0510ba17",3961:"7680ac5f",3993:"d2e94323",4209:"43880f7a",4348:"5084391c",4440:"5fd2dbdb",5003:"cdc0cfc2",5011:"121e86a6",5080:"d1a0112a",5219:"3d80a749",5309:"0a7e20de",5563:"539fb2af",5594:"a42f7e02",5620:"e93ec707",5742:"aba21aa0",5953:"920ba7ef",5986:"fac68122",6087:"a77ba7fa",6277:"713f9d9e",6438:"bde15bec",6495:"6acefe75",6590:"09c1314d",6737:"85480c2f",6803:"33ec3d65",6922:"49330316",7098:"a7bd4aaa",7177:"f839662b",7194:"a4086a70",7520:"89877b86",7658:"bb350c59",7715:"009f1e98",8030:"c1dc14fc",8401:"17896441",8649:"c6f1ff95",8779:"111eee19",8856:"89d775e6",8865:"774696b9",8897:"a51dfc20",9048:"a94703ab",9097:"e7f37855",9178:"e8644baa",9281:"35de558a",9301:"d26b9010",9329:"0eda1588",9492:"846656e5",9556:"8468a657",9630:"32955cd4",9647:"5e95c892",9659:"ec125a10",9697:"f2031820",9715:"2ce38126",9819:"d81f4320",9957:"f142c65c"}[e]||e)+"."+{20:"354e4aca",125:"6690f5ff",156:"c3e6c79e",203:"3dd91ebe",339:"6aa8c0c8",401:"f53c1ac3",646:"e9971c6c",787:"233dc95f",866:"47e1c36a",1361:"9890fbc2",1485:"a2d3345d",1567:"e7d0ca31",1571:"216fe5d3",1952:"b658549a",1977:"045af8d0",2001:"142fbe85",2007:"52ae0993",2009:"cd8a45a8",2264:"ab183745",2278:"a8726fc2",2391:"383149c0",2431:"73f8e292",2605:"56376067",2613:"ac78cea0",2618:"938e6855",2712:"0002b7ed",2725:"454d74d5",2858:"ccd0540d",2863:"83e258f6",2913:"df9d075c",3164:"a9b4188c",3197:"05192a54",3334:"e5e327f0",3640:"ab87713a",3674:"68984e32",3718:"2a1cf4e7",3961:"43677969",3993:"f6aaf207",4209:"883fc571",4266:"90c963e9",4326:"ef82c4b3",4348:"61a5cbb3",4419:"f68c49e6",4440:"9494322b",4456:"d5a85b09",4541:"14cee742",4574:"095e876c",4640:"54289f4a",5003:"8866f544",5011:"7988cc8d",5043:"2bc13b96",5080:"021f365a",5105:"56948e52",5219:"b56095d6",5298:"dfe74fea",5309:"0ed755f3",5319:"33afc3dc",5428:"ed2bd8da",5471:"8c36f303",5537:"d669d0d1",5563:"bdd86b5a",5594:"ac92b70f",5613:"71ca5510",5620:"944cbd91",5725:"9f82ae1a",5742:"de0df825",5763:"3c4dfa82",5769:"004c2474",5905:"a482ad94",5953:"8db30372",5986:"ea1f1bd1",6076:"f916ec29",6087:"f9bd1afe",6101:"1225bb35",6194:"2e4ca43a",6277:"7a4c4e6b",6325:"2cd44d9a",6370:"8940c7dd",6438:"006959b8",6495:"365eee6d",6545:"d609905c",6590:"df6dc576",6621:"df644f70",6669:"e47e086b",6737:"61b9b3cf",6803:"4fb486eb",6895:"8e72dbe9",6922:"c05e31ae",7098:"b8087602",7177:"9ae0aa4c",7194:"2bc0519d",7508:"2bdb1473",7520:"d43afb4c",7658:"6c9f0db2",7715:"79c081e2",8030:"80693b03",8227:"1a854c60",8401:"278c1b8c",8649:"1c536871",8705:"d6a6d1e2",8779:"c36f8bff",8856:"ffddc2da",8865:"17d674a8",8897:"32412972",9048:"221a3d47",9097:"2ac5d28e",9115:"93100042",9178:"4c8d12f5",9281:"441a7f8b",9288:"d0db207e",9301:"e422b779",9314:"bd050d62",9329:"4f831c59",9332:"d43c2c03",9492:"ca9020b1",9556:"f4fcc9de",9630:"7f42c651",9647:"d8f9e391",9659:"56ce15ca",9697:"6d24a989",9715:"96bfbff8",9808:"710ea9f4",9819:"64443987",9911:"44547840",9957:"a2f59d47"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="@happyview/docs:",r.l=(e,a,c,b)=>{if(d[e])d[e].push(a);else{var t,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach(e=>e(c)),a)return a(c)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"8401",49330316:"6922","919abb94":"20","9985d6d5":"203","2a23be56":"339","280f48ec":"787",fbd7a87c:"1361","22dd74f7":"1567","2d1b556d":"1952","2df7fd65":"1977","5b2964ea":"2001",c985d368:"2007","8eefb1eb":"2009","23374ca6":"2278",bccc5e9b:"2431","4a041602":"2605",b27c7406:"2618","224113b7":"2863","80ccde35":"3164","5d3a5990":"3197","0510ba17":"3334","7680ac5f":"3961",d2e94323:"3993","43880f7a":"4209","5084391c":"4348","5fd2dbdb":"4440",cdc0cfc2:"5003","121e86a6":"5011",d1a0112a:"5080","3d80a749":"5219","0a7e20de":"5309","539fb2af":"5563",a42f7e02:"5594",e93ec707:"5620",aba21aa0:"5742","920ba7ef":"5953",fac68122:"5986",a77ba7fa:"6087","713f9d9e":"6277",bde15bec:"6438","6acefe75":"6495","09c1314d":"6590","85480c2f":"6737","33ec3d65":"6803",a7bd4aaa:"7098",f839662b:"7177",a4086a70:"7194","89877b86":"7520",bb350c59:"7658","009f1e98":"7715",c1dc14fc:"8030",c6f1ff95:"8649","111eee19":"8779","89d775e6":"8856","774696b9":"8865",a51dfc20:"8897",a94703ab:"9048",e7f37855:"9097",e8644baa:"9178","35de558a":"9281",d26b9010:"9301","0eda1588":"9329","846656e5":"9492","8468a657":"9556","32955cd4":"9630","5e95c892":"9647",ec125a10:"9659",f2031820:"9697","2ce38126":"9715",d81f4320:"9819",f142c65c:"9957"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(a,c)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var f=new Promise((c,f)=>d=e[a]=[c,f]);c.push(d[2]=f);var b=r.p+r.u(a),t=new Error;r.l(b,c=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;t.message="Loading chunk "+a+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,d[1](t)}},"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,[b,t,o]=c,n=0;if(b.some(a=>0!==e[a])){for(d in t)r.o(t,d)&&(r.m[d]=t[d]);if(o)var i=o(r)}for(a&&a(c);n{"use strict";var e,a,c,d,f,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var c=t[e]={exports:{}};return b[e].call(c.exports,c,c.exports,r),c.exports}r.m=b,e=[],r.O=(a,c,d,f)=>{if(!c){var b=1/0;for(i=0;i=f)&&Object.keys(r.O).every(e=>r.O[e](c[o]))?c.splice(o--,1):(t=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};a=a||[null,c({}),c([]),c(c)];for(var t=2&d&&e;"object"==typeof t&&!~a.indexOf(t);t=c(t))Object.getOwnPropertyNames(t).forEach(a=>b[a]=()=>e[a]);return b.default=()=>e,r.d(f,b),f},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((a,c)=>(r.f[c](e,a),a),[])),r.u=e=>"assets/js/"+({20:"919abb94",203:"9985d6d5",339:"2a23be56",787:"280f48ec",1361:"fbd7a87c",1567:"22dd74f7",1952:"2d1b556d",1977:"2df7fd65",2001:"5b2964ea",2007:"c985d368",2009:"8eefb1eb",2278:"23374ca6",2431:"bccc5e9b",2605:"4a041602",2618:"b27c7406",2863:"224113b7",3164:"80ccde35",3197:"5d3a5990",3334:"0510ba17",3961:"7680ac5f",3993:"d2e94323",4209:"43880f7a",4348:"5084391c",4440:"5fd2dbdb",5003:"cdc0cfc2",5011:"121e86a6",5080:"d1a0112a",5219:"3d80a749",5309:"0a7e20de",5563:"539fb2af",5594:"a42f7e02",5620:"e93ec707",5742:"aba21aa0",5953:"920ba7ef",5986:"fac68122",6087:"a77ba7fa",6277:"713f9d9e",6438:"bde15bec",6495:"6acefe75",6590:"09c1314d",6737:"85480c2f",6803:"33ec3d65",6922:"49330316",7098:"a7bd4aaa",7177:"f839662b",7194:"a4086a70",7520:"89877b86",7658:"bb350c59",7715:"009f1e98",8030:"c1dc14fc",8401:"17896441",8649:"c6f1ff95",8779:"111eee19",8856:"89d775e6",8865:"774696b9",8897:"a51dfc20",9048:"a94703ab",9097:"e7f37855",9178:"e8644baa",9281:"35de558a",9301:"d26b9010",9329:"0eda1588",9492:"846656e5",9556:"8468a657",9630:"32955cd4",9647:"5e95c892",9659:"ec125a10",9697:"f2031820",9715:"2ce38126",9819:"d81f4320",9957:"f142c65c"}[e]||e)+"."+{20:"354e4aca",125:"6690f5ff",156:"c3e6c79e",203:"3dd91ebe",339:"6aa8c0c8",401:"f53c1ac3",646:"e9971c6c",787:"233dc95f",866:"47e1c36a",1361:"9890fbc2",1485:"a2d3345d",1567:"e7d0ca31",1571:"216fe5d3",1952:"b658549a",1977:"2b0aab27",2001:"142fbe85",2007:"52ae0993",2009:"cd8a45a8",2264:"ab183745",2278:"a8726fc2",2391:"383149c0",2431:"73f8e292",2605:"56376067",2613:"ac78cea0",2618:"938e6855",2712:"0002b7ed",2725:"454d74d5",2858:"ccd0540d",2863:"83e258f6",2913:"df9d075c",3164:"a9b4188c",3197:"05192a54",3334:"e5e327f0",3640:"ab87713a",3674:"68984e32",3718:"2a1cf4e7",3961:"43677969",3993:"f6aaf207",4209:"883fc571",4266:"90c963e9",4326:"ef82c4b3",4348:"61a5cbb3",4419:"f68c49e6",4440:"9494322b",4456:"d5a85b09",4541:"14cee742",4574:"095e876c",4640:"54289f4a",5003:"8866f544",5011:"7988cc8d",5043:"2bc13b96",5080:"021f365a",5105:"56948e52",5219:"b56095d6",5298:"dfe74fea",5309:"0ed755f3",5319:"33afc3dc",5428:"ed2bd8da",5471:"8c36f303",5537:"d669d0d1",5563:"bdd86b5a",5594:"ac92b70f",5613:"71ca5510",5620:"944cbd91",5725:"9f82ae1a",5742:"de0df825",5763:"3c4dfa82",5769:"004c2474",5905:"a482ad94",5953:"8db30372",5986:"ea1f1bd1",6076:"f916ec29",6087:"f9bd1afe",6101:"1225bb35",6194:"2e4ca43a",6277:"7a4c4e6b",6325:"2cd44d9a",6370:"8940c7dd",6438:"006959b8",6495:"365eee6d",6545:"d609905c",6590:"df6dc576",6621:"df644f70",6669:"e47e086b",6737:"61b9b3cf",6803:"4fb486eb",6895:"8e72dbe9",6922:"c05e31ae",7098:"b8087602",7177:"9ae0aa4c",7194:"2bc0519d",7508:"2bdb1473",7520:"d43afb4c",7658:"6c9f0db2",7715:"79c081e2",8030:"80693b03",8227:"1a854c60",8401:"278c1b8c",8649:"1c536871",8705:"d6a6d1e2",8779:"c36f8bff",8856:"ffddc2da",8865:"17d674a8",8897:"32412972",9048:"221a3d47",9097:"2ac5d28e",9115:"93100042",9178:"4c8d12f5",9281:"441a7f8b",9288:"d0db207e",9301:"e422b779",9314:"bd050d62",9329:"4f831c59",9332:"d43c2c03",9492:"ca9020b1",9556:"f4fcc9de",9630:"7f42c651",9647:"d8f9e391",9659:"56ce15ca",9697:"6d24a989",9715:"96bfbff8",9808:"710ea9f4",9819:"64443987",9911:"44547840",9957:"a2f59d47"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="@happyview/docs:",r.l=(e,a,c,b)=>{if(d[e])d[e].push(a);else{var t,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach(e=>e(c)),a)return a(c)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"8401",49330316:"6922","919abb94":"20","9985d6d5":"203","2a23be56":"339","280f48ec":"787",fbd7a87c:"1361","22dd74f7":"1567","2d1b556d":"1952","2df7fd65":"1977","5b2964ea":"2001",c985d368:"2007","8eefb1eb":"2009","23374ca6":"2278",bccc5e9b:"2431","4a041602":"2605",b27c7406:"2618","224113b7":"2863","80ccde35":"3164","5d3a5990":"3197","0510ba17":"3334","7680ac5f":"3961",d2e94323:"3993","43880f7a":"4209","5084391c":"4348","5fd2dbdb":"4440",cdc0cfc2:"5003","121e86a6":"5011",d1a0112a:"5080","3d80a749":"5219","0a7e20de":"5309","539fb2af":"5563",a42f7e02:"5594",e93ec707:"5620",aba21aa0:"5742","920ba7ef":"5953",fac68122:"5986",a77ba7fa:"6087","713f9d9e":"6277",bde15bec:"6438","6acefe75":"6495","09c1314d":"6590","85480c2f":"6737","33ec3d65":"6803",a7bd4aaa:"7098",f839662b:"7177",a4086a70:"7194","89877b86":"7520",bb350c59:"7658","009f1e98":"7715",c1dc14fc:"8030",c6f1ff95:"8649","111eee19":"8779","89d775e6":"8856","774696b9":"8865",a51dfc20:"8897",a94703ab:"9048",e7f37855:"9097",e8644baa:"9178","35de558a":"9281",d26b9010:"9301","0eda1588":"9329","846656e5":"9492","8468a657":"9556","32955cd4":"9630","5e95c892":"9647",ec125a10:"9659",f2031820:"9697","2ce38126":"9715",d81f4320:"9819",f142c65c:"9957"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(a,c)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var f=new Promise((c,f)=>d=e[a]=[c,f]);c.push(d[2]=f);var b=r.p+r.u(a),t=new Error;r.l(b,c=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;t.message="Loading chunk "+a+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,d[1](t)}},"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,[b,t,o]=c,n=0;if(b.some(a=>0!==e[a])){for(d in t)r.o(t,d)&&(r.m[d]=t[d]);if(o)var i=o(r)}for(a&&a(c);nAuthentication | HappyView
-
+
diff --git a/getting-started/configuration/index.html b/getting-started/configuration/index.html
index ddec41f..efe7dd0 100644
--- a/getting-started/configuration/index.html
+++ b/getting-started/configuration/index.html
@@ -4,7 +4,7 @@
Configuration | HappyView
-
+
diff --git a/getting-started/dashboard/index.html b/getting-started/dashboard/index.html
index 380b2a2..4f02fbe 100644
--- a/getting-started/dashboard/index.html
+++ b/getting-started/dashboard/index.html
@@ -4,7 +4,7 @@
Dashboard | HappyView
-
+
diff --git a/getting-started/deployment/docker/index.html b/getting-started/deployment/docker/index.html
index fe7fa90..cf0760e 100644
--- a/getting-started/deployment/docker/index.html
+++ b/getting-started/deployment/docker/index.html
@@ -4,7 +4,7 @@
Local Development with Docker | HappyView
-
+
diff --git a/getting-started/deployment/other/index.html b/getting-started/deployment/other/index.html
index 2ee1577..6f32ac6 100644
--- a/getting-started/deployment/other/index.html
+++ b/getting-started/deployment/other/index.html
@@ -4,7 +4,7 @@
Local Development from Source | HappyView
-
+
diff --git a/getting-started/deployment/railway/index.html b/getting-started/deployment/railway/index.html
index a1f519b..92bf611 100644
--- a/getting-started/deployment/railway/index.html
+++ b/getting-started/deployment/railway/index.html
@@ -4,7 +4,7 @@
Deploy on Railway | HappyView
-
+
diff --git a/getting-started/quickstart/index.html b/getting-started/quickstart/index.html
index 897fa08..7ecf989 100644
--- a/getting-started/quickstart/index.html
+++ b/getting-started/quickstart/index.html
@@ -4,7 +4,7 @@
Quickstart | HappyView
-
+
diff --git a/guides/api-keys/index.html b/guides/api-keys/index.html
index a24691d..df57289 100644
--- a/guides/api-keys/index.html
+++ b/guides/api-keys/index.html
@@ -4,7 +4,7 @@
API Keys | HappyView
-
+
diff --git a/guides/backfill/index.html b/guides/backfill/index.html
index 49e6357..8996d9e 100644
--- a/guides/backfill/index.html
+++ b/guides/backfill/index.html
@@ -4,7 +4,7 @@
Backfill | HappyView
-
+
diff --git a/guides/database-setup/index.html b/guides/database-setup/index.html
index 4887a5d..90e5cc8 100644
--- a/guides/database-setup/index.html
+++ b/guides/database-setup/index.html
@@ -4,7 +4,7 @@
Database Setup | HappyView
-
+
diff --git a/guides/developing-plugins/index.html b/guides/developing-plugins/index.html
index 0f712f8..5354924 100644
--- a/guides/developing-plugins/index.html
+++ b/guides/developing-plugins/index.html
@@ -4,7 +4,7 @@
Developing Plugins | HappyView
-
+
diff --git a/guides/event-logs/index.html b/guides/event-logs/index.html
index 7c1e314..871e4f6 100644
--- a/guides/event-logs/index.html
+++ b/guides/event-logs/index.html
@@ -4,7 +4,7 @@
Event Logs | HappyView
-
+
@@ -37,7 +37,7 @@
Logged when index hooks run. Dead-lettered events indicate a hook failed all retry attempts.
+
Logged when index hooks run. Dead-lettered events indicate a hook failed all retry attempts. You can manage dead letters from the Data > Dead Letters page in the dashboard — see Dead Letters below.
Event logs are automatically cleaned up based on the EVENT_LOG_RETENTION_DAYS environment variable (default: 30 days). A background task runs hourly to delete events older than the configured retention period.
Set EVENT_LOG_RETENTION_DAYS=0 to disable automatic cleanup and keep logs indefinitely.
When an index hook fails after all retry attempts, the event is stored in the dead letters queue. You can manage dead letters from the Data > Dead Letters page in the dashboard.
+
From the dead letters page you can:
+
+
Retry Hook — replay the stored record through the index hook (use after fixing a hook script)
+
Re-index — fetch the record fresh from the PDS and run it through the full indexing pipeline (use when the record may have changed)
+
Dismiss — mark the dead letter as resolved without retrying
+
+
Bulk actions are available for selected rows or all entries matching the current filters.