[{"data":1,"prerenderedAt":293},["ShallowReactive",2],{"docs-nav-pkg":3,"docs-page-pkg-\u002Fpkg\u002Fdb":133},[4,8,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,121,124,127,130],{"path":5,"title":6,"section":7},"\u002Fpkg","Overview","Start",{"path":9,"title":10,"section":11},"\u002Fpkg\u002Faccordion","Accordion","Components",{"path":13,"title":14,"section":11},"\u002Fpkg\u002Falert-dialog","Alert Dialog",{"path":16,"title":17,"section":11},"\u002Fpkg\u002Fautocomplete","Autocomplete",{"path":19,"title":20,"section":11},"\u002Fpkg\u002Favatar","Avatar",{"path":22,"title":23,"section":11},"\u002Fpkg\u002Fbutton","Button",{"path":25,"title":26,"section":11},"\u002Fpkg\u002Fcheckbox","Checkbox",{"path":28,"title":29,"section":11},"\u002Fpkg\u002Fcheckbox-group","Checkbox Group",{"path":31,"title":32,"section":11},"\u002Fpkg\u002Fcollapsible","Collapsible",{"path":34,"title":35,"section":11},"\u002Fpkg\u002Fcombobox","Combobox",{"path":37,"title":38,"section":11},"\u002Fpkg\u002Fcontext-menu","Context Menu",{"path":40,"title":41,"section":11},"\u002Fpkg\u002Fdialog","Dialog",{"path":43,"title":44,"section":11},"\u002Fpkg\u002Fdrawer","Drawer",{"path":46,"title":47,"section":11},"\u002Fpkg\u002Ffield","Field",{"path":49,"title":50,"section":11},"\u002Fpkg\u002Ffieldset","Fieldset",{"path":52,"title":53,"section":11},"\u002Fpkg\u002Fform","Form",{"path":55,"title":56,"section":11},"\u002Fpkg\u002Ficon-picker","Icon picker",{"path":58,"title":59,"section":11},"\u002Fpkg\u002Finput","Input",{"path":61,"title":62,"section":11},"\u002Fpkg\u002Fmenu","Menu",{"path":64,"title":65,"section":11},"\u002Fpkg\u002Fmenubar","Menubar",{"path":67,"title":68,"section":11},"\u002Fpkg\u002Fmeter","Meter",{"path":70,"title":71,"section":11},"\u002Fpkg\u002Fnavigation-menu","Navigation Menu",{"path":73,"title":74,"section":11},"\u002Fpkg\u002Fnumber-field","Number Field",{"path":76,"title":77,"section":11},"\u002Fpkg\u002Fotp-field","OTP Field",{"path":79,"title":80,"section":11},"\u002Fpkg\u002Fplot","Plot",{"path":82,"title":83,"section":11},"\u002Fpkg\u002Fpopover","Popover",{"path":85,"title":86,"section":11},"\u002Fpkg\u002Fpreview-card","Preview Card",{"path":88,"title":89,"section":11},"\u002Fpkg\u002Fprogress","Progress",{"path":91,"title":92,"section":11},"\u002Fpkg\u002Fradio-group","Radio Group",{"path":94,"title":95,"section":11},"\u002Fpkg\u002Fscroll-area","Scroll Area",{"path":97,"title":98,"section":11},"\u002Fpkg\u002Fselect","Select",{"path":100,"title":101,"section":11},"\u002Fpkg\u002Fseparator","Separator",{"path":103,"title":104,"section":11},"\u002Fpkg\u002Fsidebar","Sidebar",{"path":106,"title":107,"section":11},"\u002Fpkg\u002Fslider","Slider",{"path":109,"title":110,"section":11},"\u002Fpkg\u002Fswitch","Switch",{"path":112,"title":113,"section":11},"\u002Fpkg\u002Ftabs","Tabs",{"path":115,"title":116,"section":11},"\u002Fpkg\u002Ftoast","Toast",{"path":118,"title":119,"section":120},"\u002Fpkg\u002Fapi","Api","Runtime",{"path":122,"title":123,"section":120},"\u002Fpkg\u002Fauth","Auth",{"path":125,"title":126,"section":120},"\u002Fpkg\u002Fblob","Blob",{"path":128,"title":129,"section":120},"\u002Fpkg\u002Fchannels","Channels",{"path":131,"title":132,"section":120},"\u002Fpkg\u002Fdb","Db",{"id":134,"title":132,"body":135,"description":286,"extension":287,"meta":288,"navigation":289,"path":131,"section":120,"seo":290,"stem":291,"__hash__":292},"pkg\u002Fpkg\u002Fdb.md",{"type":136,"value":137,"toc":281},"minimark",[138,166,182,196,214,219,234,249,253,277],[139,140,141,145,146,149,150,153,154,157,158,161,162,165],"p",{},[142,143,144],"code",{},"lib\u002Fdb"," (",[142,147,148],{},"kalt-db",") is the Postgres pool. Each service has its own database. ",[142,151,152],{},"{SERVICE}_DATABASE_URL"," selects it (",[142,155,156],{},"AUTH_DATABASE_URL",", ",[142,159,160],{},"PUBLICATIONS_DATABASE_URL",", …). ",[142,163,164],{},"DATABASE_URL"," is the fallback.",[167,168,173],"pre",{"className":169,"code":170,"language":171,"meta":172,"style":172},"language-rust shiki shiki-themes github-light github-dark","let db = kalt_db::connect(service, &kalt_db::url(service)?).await?;\n","rust","",[142,174,175],{"__ignoreMap":172},[176,177,180],"span",{"class":178,"line":179},"line",1,[176,181,170],{},[139,183,184,187,188,191,192,195],{},[142,185,186],{},"connect"," opens that URL and ensures ",[142,189,190],{},"gen_random_okid()",". The service runs ",[142,193,194],{},"migrations\u002F"," from its own crate. Add a numbered SQL file there to change that service's schema.",[139,197,198,201,202,205,206,209,210,213],{},[142,199,200],{},"pnpm dev"," starts one Postgres from ",[142,203,204],{},"platform\u002Ftables"," per service. A service opens it with ",[142,207,208],{},"kalt_db::open"," and then uses ",[142,211,212],{},"state.db",".",[215,216,218],"h2",{"id":217},"draft-and-live","Draft and live",[139,220,221,222,225,226,229,230,233],{},"Content tables come in pairs: a published snapshot and a ledger. Ledger rows are field deltas keyed by ",[142,223,224],{},"id"," and ",[142,227,228],{},"tz",". Live rows are the last published snapshot. ",[142,231,232],{},"GET …\u002Fledger\u002F:id"," is a server-built projection (latest non-null per field). PATCH appends a delta; it does not rewrite the live row.",[139,235,236,237,240,241,244,245,248],{},"Editor reads pass ",[142,238,239],{},"draft=1"," so ",[142,242,243],{},"pick_text"," \u002F ",[142,246,247],{},"pick_json"," prefer the ledger column.",[215,250,252],{"id":251},"auth-tables","Auth tables",[139,254,255,225,258,261,262,265,266,269,270,273,274,213],{},[142,256,257],{},"auth_users",[142,259,260],{},"auth_refresh_tokens"," live in the auth database (",[142,263,264],{},"svc\u002Fauth\u002Fmigrations","). ",[142,267,268],{},"auth_editors"," is the allow-list that becomes JWT ",[142,271,272],{},"role"," at approve time. See ",[275,276,123],"a",{"href":122},[278,279,280],"style",{},"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);}",{"title":172,"searchDepth":282,"depth":282,"links":283},2,[284,285],{"id":217,"depth":282,"text":218},{"id":251,"depth":282,"text":252},"Postgres pool and SQL migrations for every service","md",{},true,{"title":132,"description":286},"pkg\u002Fdb","dokjyU_X1anhHATFxkaLKwMj-lJB-0q1DgbYKHhSbUU",1791043754627]