[{"data":1,"prerenderedAt":715},["ShallowReactive",2],{"navigation_docs_en":3,"-en-development-troubleshooting":191,"-en-development-troubleshooting-surround":710},[4,61,127,171],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":60},"Guide","i-lucide-book-open","\u002Fen\u002Fguide","en\u002F1.guide",[10,15,20,25,30,35,40,45,50,55],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fguide\u002Fintroduction","en\u002F1.guide\u002F01.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Install the App","\u002Fen\u002Fguide\u002Finstallation","en\u002F1.guide\u002F02.installation","i-lucide-smartphone",{"title":21,"path":22,"stem":23,"icon":24},"Authentication","\u002Fen\u002Fguide\u002Fauth","en\u002F1.guide\u002F03.auth","i-lucide-lock",{"title":26,"path":27,"stem":28,"icon":29},"Wallets","\u002Fen\u002Fguide\u002Fwallets","en\u002F1.guide\u002F04.wallets","i-lucide-wallet",{"title":31,"path":32,"stem":33,"icon":34},"Categories","\u002Fen\u002Fguide\u002Fcategories","en\u002F1.guide\u002F05.categories","i-lucide-tags",{"title":36,"path":37,"stem":38,"icon":39},"Transactions","\u002Fen\u002Fguide\u002Ftransactions","en\u002F1.guide\u002F06.transactions","i-lucide-receipt",{"title":41,"path":42,"stem":43,"icon":44},"Transfers","\u002Fen\u002Fguide\u002Ftransfers","en\u002F1.guide\u002F07.transfers","i-lucide-arrow-left-right",{"title":46,"path":47,"stem":48,"icon":49},"Statistics","\u002Fen\u002Fguide\u002Fstatistics","en\u002F1.guide\u002F08.statistics","i-lucide-bar-chart-3",{"title":51,"path":52,"stem":53,"icon":54},"Theme","\u002Fen\u002Fguide\u002Ftheme","en\u002F1.guide\u002F09.theme","i-lucide-palette",{"title":56,"path":57,"stem":58,"icon":59},"Settings","\u002Fen\u002Fguide\u002Fsettings","en\u002F1.guide\u002F10.settings","i-lucide-settings",false,{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":60},"Development","i-lucide-code","\u002Fen\u002Fdevelopment","en\u002F2.development",[67,72,77,82,87,92,97,102,122],{"title":68,"path":69,"stem":70,"icon":71},"Installation","\u002Fen\u002Fdevelopment\u002Finstallation","en\u002F2.development\u002F01.installation","i-lucide-download",{"title":73,"path":74,"stem":75,"icon":76},"Codebase Graph","\u002Fen\u002Fdevelopment\u002Funderstand-anything","en\u002F2.development\u002F02.understand-anything","i-lucide-network",{"title":78,"path":79,"stem":80,"icon":81},"Offline & PWA","\u002Fen\u002Fdevelopment\u002Foffline","en\u002F2.development\u002F03.offline","i-lucide-wifi-off",{"title":83,"path":84,"stem":85,"icon":86},"Data Migration History","\u002Fen\u002Fdevelopment\u002Fmigration","en\u002F2.development\u002F04.migration","i-lucide-database",{"title":88,"path":89,"stem":90,"icon":91},"Deployment","\u002Fen\u002Fdevelopment\u002Fdeployment","en\u002F2.development\u002F05.deployment","i-lucide-rocket",{"title":93,"path":94,"stem":95,"icon":96},"Testing","\u002Fen\u002Fdevelopment\u002Ftesting","en\u002F2.development\u002F06.testing","i-lucide-flask-conical",{"title":98,"path":99,"stem":100,"icon":101},"Date Utilities","\u002Fen\u002Fdevelopment\u002Fdate-utilities","en\u002F2.development\u002F07.date-utilities","i-lucide-calendar",{"title":103,"path":104,"stem":105,"children":106,"page":60},"Ai Workflow","\u002Fen\u002Fdevelopment\u002Fai-workflow","en\u002F2.development\u002F08.ai-workflow",[107,112,117],{"title":108,"path":109,"stem":110,"icon":111},"Overview","\u002Fen\u002Fdevelopment\u002Fai-workflow\u002Foverview","en\u002F2.development\u002F08.ai-workflow\u002F01.overview","i-lucide-bot",{"title":113,"path":114,"stem":115,"icon":116},"Agents","\u002Fen\u002Fdevelopment\u002Fai-workflow\u002Fagents","en\u002F2.development\u002F08.ai-workflow\u002F02.agents","i-lucide-users",{"title":118,"path":119,"stem":120,"icon":121},"Skills","\u002Fen\u002Fdevelopment\u002Fai-workflow\u002Fskills","en\u002F2.development\u002F08.ai-workflow\u002F03.skills","i-lucide-lightbulb",{"title":123,"path":124,"stem":125,"icon":126},"Troubleshooting","\u002Fen\u002Fdevelopment\u002Ftroubleshooting","en\u002F2.development\u002F09.troubleshooting","i-lucide-life-buoy",{"title":128,"icon":129,"path":130,"stem":131,"children":132,"page":60},"Reference","i-lucide-file-code","\u002Fen\u002Freference","en\u002F3.reference",[133,138,142,147,152,156,161,166],{"title":134,"path":135,"stem":136,"icon":137},"Architecture","\u002Fen\u002Freference\u002Farchitecture","en\u002F3.reference\u002F01.architecture","i-lucide-boxes",{"title":139,"path":140,"stem":141,"icon":44},"Transaction Types","\u002Fen\u002Freference\u002Ftransaction-types","en\u002F3.reference\u002F02.transaction-types",{"title":143,"path":144,"stem":145,"icon":146},"Sync","\u002Fen\u002Freference\u002Fsync","en\u002F3.reference\u002F03.sync","i-lucide-refresh-cw",{"title":148,"path":149,"stem":150,"icon":151},"Offline-first","\u002Fen\u002Freference\u002Foffline-first","en\u002F3.reference\u002F04.offline-first","i-lucide-list-ordered",{"title":153,"path":154,"stem":155,"icon":121},"Technical Decisions","\u002Fen\u002Freference\u002Ftech-decisions","en\u002F3.reference\u002F05.tech-decisions",{"title":157,"path":158,"stem":159,"icon":160},"Validation Strategy","\u002Fen\u002Freference\u002Fvalidation-strategy","en\u002F3.reference\u002F06.validation-strategy","i-lucide-shield-check",{"title":162,"path":163,"stem":164,"icon":165},"What Changed Since Firebase","\u002Fen\u002Freference\u002Ffirebase-migration","en\u002F3.reference\u002F07.firebase-migration","i-lucide-hamburger",{"title":167,"path":168,"stem":169,"icon":170},"Performance","\u002Fen\u002Freference\u002Fperformance","en\u002F3.reference\u002F08.performance","i-lucide-gauge",{"title":172,"icon":173,"path":174,"stem":175,"children":176,"page":60},"Premium","i-lucide-star","\u002Fen\u002Fpremium","en\u002F4.premium",[177,181,186],{"title":108,"path":178,"stem":179,"icon":180},"\u002Fen\u002Fpremium\u002Foverview","en\u002F4.premium\u002F01.overview","i-lucide-layers",{"title":182,"path":183,"stem":184,"icon":185},"Telegram Bot","\u002Fen\u002Fpremium\u002Ftelegram-bot","en\u002F4.premium\u002F02.telegram-bot","i-lucide-send",{"title":187,"path":188,"stem":189,"icon":190},"AI Chat","\u002Fen\u002Fpremium\u002Fai-chat","en\u002F4.premium\u002F03.ai-chat","i-lucide-sparkles",{"id":192,"title":123,"body":193,"description":702,"extension":703,"links":704,"meta":705,"navigation":706,"path":124,"seo":707,"stem":125,"__hash__":709},"docs_en\u002Fen\u002F2.development\u002F09.troubleshooting.md",{"type":194,"value":195,"toc":689},"minimark",[196,201,206,219,242,249,253,272,298,304,308,316,340,343,623,630,637,650,654,668,679,685],[197,198,200],"h2",{"id":199},"local-docker-supabase","Local Docker \u002F Supabase",[202,203,205],"h3",{"id":204},"colima-disable-supabase-analytics","Colima: disable Supabase analytics",[207,208,209,210,214,215,218],"p",{},"On Colima (macOS Docker alternative), the Supabase ",[211,212,213],"code",{},"vector"," (log analytics) container fails to start because it cannot bind-mount the Docker socket. Disable it in ",[211,216,217],{},"app\u002Fsupabase\u002Fconfig.toml",":",[220,221,226],"pre",{"className":222,"code":223,"filename":217,"language":224,"meta":225,"style":225},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[analytics]\nenabled = false\n","toml","",[211,227,228,236],{"__ignoreMap":225},[229,230,233],"span",{"class":231,"line":232},"line",1,[229,234,235],{},"[analytics]\n",[229,237,239],{"class":231,"line":238},2,[229,240,241],{},"enabled = false\n",[207,243,244,245,248],{},"Without this, ",[211,246,247],{},"supabase start"," hangs or errors on Colima environments.",[202,250,252],{"id":251},"postgres18-image-wrong-volume-mount-path","postgres:18 image - wrong volume mount path",[207,254,255,256,259,260,263,264,268,269,218],{},"If you use a ",[211,257,258],{},"postgres:18"," container (for example, for the PowerSync bucket-storage database), mount the data volume at ",[211,261,262],{},"\u002Fvar\u002Flib\u002Fpostgresql",", ",[265,266,267],"strong",{},"not"," ",[211,270,271],{},"\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata",[220,273,277],{"className":274,"code":275,"language":276,"meta":225,"style":225},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","volumes:\n  - pg_storage_data:\u002Fvar\u002Flib\u002Fpostgresql\n","yaml",[211,278,279,289],{"__ignoreMap":225},[229,280,281,285],{"class":231,"line":232},[229,282,284],{"class":283},"swJcz","volumes",[229,286,288],{"class":287},"sMK4o",":\n",[229,290,291,294],{"class":231,"line":238},[229,292,293],{"class":287},"  -",[229,295,297],{"class":296},"sfazB"," pg_storage_data:\u002Fvar\u002Flib\u002Fpostgresql\n",[207,299,300,301,303],{},"Mounting at ",[211,302,271],{}," causes the container to fail on startup because postgres:18 changed the default data directory.",[197,305,307],{"id":306},"powersync-client","PowerSync client",[202,309,311,312,315],{"id":310},"no-insert-on-conflict-on-powersync-tables","No ",[211,313,314],{},"INSERT ... ON CONFLICT"," on PowerSync tables",[207,317,318,319,322,323,263,326,329,330,333,334,268,336,339],{},"PowerSync client tables are SQLite ",[265,320,321],{},"views"," backed by INSTEAD OF triggers. They accept plain ",[211,324,325],{},"INSERT",[211,327,328],{},"UPDATE",", and ",[211,331,332],{},"DELETE"," statements, but ",[265,335,267],{},[211,337,338],{},"INSERT ... ON CONFLICT (upsert syntax)",".",[207,341,342],{},"Upsert logic must be done manually - check for row existence first, then INSERT or UPDATE:",[220,344,348],{"className":345,"code":346,"language":347,"meta":225,"style":225},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F from app\u002Fservices\u002Fpowersync\u002Fmutations.ts\nasync function upsertRow(table, id, row) {\n  await db.writeTransaction(async (tx) => {\n    const existing = await tx.getOptional(`SELECT id FROM ${table} WHERE id = ?`, [id])\n    if (existing) {\n      await tx.execute(`UPDATE ${table} SET ... WHERE id = ?`, [...values, id])\n    }\n    else {\n      await tx.execute(`INSERT INTO ${table} (id, ...) VALUES (?, ...)`, [id, ...values])\n    }\n  })\n}\n","ts",[211,349,350,356,393,426,481,498,545,551,559,603,608,617],{"__ignoreMap":225},[229,351,352],{"class":231,"line":232},[229,353,355],{"class":354},"sHwdD","\u002F\u002F from app\u002Fservices\u002Fpowersync\u002Fmutations.ts\n",[229,357,358,362,365,369,372,376,379,382,384,387,390],{"class":231,"line":238},[229,359,361],{"class":360},"spNyl","async",[229,363,364],{"class":360}," function",[229,366,368],{"class":367},"s2Zo4"," upsertRow",[229,370,371],{"class":287},"(",[229,373,375],{"class":374},"sHdIc","table",[229,377,378],{"class":287},",",[229,380,381],{"class":374}," id",[229,383,378],{"class":287},[229,385,386],{"class":374}," row",[229,388,389],{"class":287},")",[229,391,392],{"class":287}," {\n",[229,394,396,400,404,406,409,411,413,416,419,421,424],{"class":231,"line":395},3,[229,397,399],{"class":398},"s7zQu","  await",[229,401,403],{"class":402},"sTEyZ"," db",[229,405,339],{"class":287},[229,407,408],{"class":367},"writeTransaction",[229,410,371],{"class":283},[229,412,361],{"class":360},[229,414,415],{"class":287}," (",[229,417,418],{"class":374},"tx",[229,420,389],{"class":287},[229,422,423],{"class":360}," =>",[229,425,392],{"class":287},[229,427,429,432,435,438,441,444,446,449,451,454,457,460,462,465,468,470,472,475,478],{"class":231,"line":428},4,[229,430,431],{"class":360},"    const",[229,433,434],{"class":402}," existing",[229,436,437],{"class":287}," =",[229,439,440],{"class":398}," await",[229,442,443],{"class":402}," tx",[229,445,339],{"class":287},[229,447,448],{"class":367},"getOptional",[229,450,371],{"class":283},[229,452,453],{"class":287},"`",[229,455,456],{"class":296},"SELECT id FROM ",[229,458,459],{"class":287},"${",[229,461,375],{"class":402},[229,463,464],{"class":287},"}",[229,466,467],{"class":296}," WHERE id = ?",[229,469,453],{"class":287},[229,471,378],{"class":287},[229,473,474],{"class":283}," [",[229,476,477],{"class":402},"id",[229,479,480],{"class":283},"])\n",[229,482,484,487,489,492,495],{"class":231,"line":483},5,[229,485,486],{"class":398},"    if",[229,488,415],{"class":283},[229,490,491],{"class":402},"existing",[229,493,494],{"class":283},") ",[229,496,497],{"class":287},"{\n",[229,499,501,504,506,508,511,513,515,518,520,522,524,527,529,531,533,536,539,541,543],{"class":231,"line":500},6,[229,502,503],{"class":398},"      await",[229,505,443],{"class":402},[229,507,339],{"class":287},[229,509,510],{"class":367},"execute",[229,512,371],{"class":283},[229,514,453],{"class":287},[229,516,517],{"class":296},"UPDATE ",[229,519,459],{"class":287},[229,521,375],{"class":402},[229,523,464],{"class":287},[229,525,526],{"class":296}," SET ... WHERE id = ?",[229,528,453],{"class":287},[229,530,378],{"class":287},[229,532,474],{"class":283},[229,534,535],{"class":287},"...",[229,537,538],{"class":402},"values",[229,540,378],{"class":287},[229,542,381],{"class":402},[229,544,480],{"class":283},[229,546,548],{"class":231,"line":547},7,[229,549,550],{"class":287},"    }\n",[229,552,554,557],{"class":231,"line":553},8,[229,555,556],{"class":398},"    else",[229,558,392],{"class":287},[229,560,562,564,566,568,570,572,574,577,579,581,583,586,588,590,592,594,596,599,601],{"class":231,"line":561},9,[229,563,503],{"class":398},[229,565,443],{"class":402},[229,567,339],{"class":287},[229,569,510],{"class":367},[229,571,371],{"class":283},[229,573,453],{"class":287},[229,575,576],{"class":296},"INSERT INTO ",[229,578,459],{"class":287},[229,580,375],{"class":402},[229,582,464],{"class":287},[229,584,585],{"class":296}," (id, ...) VALUES (?, ...)",[229,587,453],{"class":287},[229,589,378],{"class":287},[229,591,474],{"class":283},[229,593,477],{"class":402},[229,595,378],{"class":287},[229,597,598],{"class":287}," ...",[229,600,538],{"class":402},[229,602,480],{"class":283},[229,604,606],{"class":231,"line":605},10,[229,607,550],{"class":287},[229,609,611,614],{"class":231,"line":610},11,[229,612,613],{"class":287},"  }",[229,615,616],{"class":283},")\n",[229,618,620],{"class":231,"line":619},12,[229,621,622],{"class":287},"}\n",[207,624,625,626,629],{},"See ",[211,627,628],{},"app\u002Fservices\u002Fpowersync\u002Fmutations.ts"," for the full implementation.",[202,631,633,634,636],{"id":632},"every-synced-table-must-have-an-id-pk","Every synced table must have an ",[211,635,477],{}," PK",[207,638,639,640,642,643,646,647,649],{},"PowerSync requires an ",[211,641,477],{}," primary key on every synced table. For ",[211,644,645],{},"user_settings",", the ",[211,648,477],{}," column holds the user's Supabase uid. This is how the table satisfies the requirement while having exactly one row per user.",[197,651,653],{"id":652},"synchronous-auth-gate","Synchronous auth gate",[207,655,656,657,660,661,263,664,667],{},"The route guard in ",[211,658,659],{},"app\u002Fapp\u002Fmiddleware\u002Fauth.global.ts"," is synchronous - it reads the persisted Supabase session from localStorage (",[211,662,663],{},"hasPersistedSession()",[211,665,666],{},"app\u002Fapp\u002Fcomposables\u002FuseAuthSession.ts",") with no network call, so it works offline. There is no auth cookie.",[207,669,670,671,674,675,678],{},"supabase-js persists the session to localStorage itself as part of sign-in, so by the time login code navigates, the gate already passes. The PowerSync plugin separately watches the reactive ",[211,672,673],{},"uid"," from ",[211,676,677],{},"useSupabaseAuth()"," and connects\u002Fdisconnects PowerSync as the session resolves - navigation does not wait for it.",[207,680,681,682,339],{},"If you move login flow logic around, navigate only after the sign-in promise resolves (session persisted) - otherwise the guard will redirect back to ",[211,683,684],{},"\u002Flogin",[686,687,688],"style",{},"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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":225,"searchDepth":238,"depth":238,"links":690},[691,695,701],{"id":199,"depth":238,"text":200,"children":692},[693,694],{"id":204,"depth":395,"text":205},{"id":251,"depth":395,"text":252},{"id":306,"depth":238,"text":307,"children":696},[697,699],{"id":310,"depth":395,"text":698},"No INSERT ... ON CONFLICT on PowerSync tables",{"id":632,"depth":395,"text":700},"Every synced table must have an id PK",{"id":652,"depth":238,"text":653},"Known gotchas for the local Supabase+PowerSync dev setup and offline-first data layer.","md",null,{},{"icon":126},{"title":123,"description":708},"Verified gotchas from the Supabase+PowerSync migration - Docker, PowerSync client tables, auth cookie timing, and more.","mJ0mYXh2W5A2ARGaDRvcV7rzOCOE4rExi9JM0kuddhA",[711,713],{"title":118,"path":119,"stem":120,"description":712,"icon":121,"children":-1},"On-demand guides for security review, TDD, Nuxt 4 patterns, and E2E testing.",{"title":134,"path":135,"stem":136,"description":714,"icon":137,"children":-1},"Initialization flow, project structure, store pattern, auth - Supabase + PowerSync.",1782114343837]