[{"data":1,"prerenderedAt":708},["ShallowReactive",2],{"repo-tree":3,"repo-\u002Finternal\u002Fsupport-bot\u002Fclaude":283},[4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,69,72,75,78,81,84,86,88,90,93,96,99,102,105,108,111,114,117,120,123,125,127,129,131,133,135,138,141,143,146,149,152,155,158,161,164,167,169,172,175,178,180,183,186,189,192,195,198,201,203,206,209,212,215,218,221,224,227,230,233,236,239,242,245,248,251,254,257,260,263,266,269,272,275,278,281],{"path":5,"title":6},"\u002Fagents\u002Fbackend-code-style","Backend Conventions",{"path":8,"title":9},"\u002Fagents\u002Fdatabase","Database",{"path":11,"title":12},"\u002Fagents\u002Fportal-code-style","Portal Conventions",{"path":14,"title":15},"\u002Fagents\u002Ftranslation","Translation",{"path":17,"title":18},"\u002Fconventions\u002Fbackend-coding","Backend coding conventions",{"path":20,"title":21},"\u002Fconventions\u002Ffrontend-coding","Frontend coding conventions",{"path":23,"title":24},"\u002Fdevelopment-process","Development process",{"path":26,"title":27},"\u002Flearning-api-preview-hetzner-setup","Learning API Preview on Hetzner + Cloudflare",{"path":29,"title":30},"\u002Flearning-api-preview-vm-plan","Learning API Preview VM Plan",{"path":32,"title":33},"\u002Fmonorepo-structure","Monorepo structure",{"path":35,"title":36},"\u002Foperations","Operations — bugs and support",{"path":38,"title":39},"\u002Fpostmortems\u002F2026-03-16_onboarding-currency-regression","Onboarding Zod transform silently broken — web signups assigned wrong checkout currency",{"path":41,"title":42},"\u002Fpostmortems\u002Freadme","Postmortems",{"path":44,"title":45},"\u002Fpostmortems\u002F_template","TEMPLATE",{"path":47,"title":48},"\u002Fpostmortems\u002Fposthog-comparison","Postmortem practice — comparison with PostHog",{"path":50,"title":51},"\u002Fpreview-environment-plan","Preview Environment Plan",{"path":53,"title":54},"\u002Fprinciples","Engineering principles",{"path":56,"title":57},"\u002Fworking-with-ai","Working with AI",{"path":59,"title":60},"\u002F.claude\u002Fskills\u002Feval-playground\u002Fskill","Eval Playground — Co-development Skill",{"path":62,"title":63},"\u002F.claude\u002Fskills\u002Ffigma-diff-section\u002Fskill","Figma Diff Section Pipeline",{"path":65,"title":66},"\u002Fagents","AGENTS.md",{"path":68,"title":66},"\u002Fclaude",{"path":70,"title":71},"\u002Freadme","Studyflash",{"path":73,"title":74},"\u002Fapps\u002Fcore-api\u002Fagents","Core API (apps\u002Fcore-api)",{"path":76,"title":77},"\u002Fapps\u002Fcore-api\u002Freadme","README",{"path":79,"title":80},"\u002Fapps\u002Femail-previews\u002Fagents","Email Previews (apps\u002Femail-previews)",{"path":82,"title":83},"\u002Fapps\u002Flanding-page\u002Fagents","Landing Page (apps\u002Flanding-page)",{"path":85,"title":83},"\u002Fapps\u002Flanding-page\u002Fclaude",{"path":87,"title":66},"\u002Fapps\u002Flearning-api\u002Fagents",{"path":89,"title":77},"\u002Fapps\u002Flearning-api\u002Freadme",{"path":91,"title":92},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Feval_metrics_design","Surface-Specific Eval Metrics Design",{"path":94,"title":95},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Ftest_set","Quiz Eval Test Set",{"path":97,"title":98},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Ffrontend\u002Freadme","React + TypeScript + Vite",{"path":100,"title":101},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Fknown-issues\u002Fcontent-pillar-shallow-coverage\u002Freadme","Content pillar misses subtopics in dense documents",{"path":103,"title":104},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Fknown-issues\u002Fdocling-empty-section-headers\u002Freadme","Empty section headers dropped by docling chunker",{"path":106,"title":107},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Fknown-issues\u002Fdocling-table-reading-order\u002Freadme","Table\u002Fbox layout causes wrong reading order",{"path":109,"title":110},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Fmetrics\u002Freadme","Quiz eval metrics — canonical rubrics",{"path":112,"title":113},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Freports\u002F2026-04-12-quiz-summary-feedback-current-state","Quiz and Summary Feedback Current State",{"path":115,"title":116},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Freports\u002F2026-04-24-quiz-eval-metrics","Quiz Evaluation Metrics",{"path":118,"title":119},"\u002Fapps\u002Flearning-api\u002Fevals-playground\u002Freports\u002F2026-05-01-quiz-eval-current-state","Quiz Eval Current State",{"path":121,"title":122},"\u002Fapps\u002Flearning-api\u002Fmonitoring\u002Freadme","Monitoring Stack",{"path":124,"title":77},"\u002Fapps\u002Flearning-api\u002Fshared\u002Freadme",{"path":126,"title":77},"\u002Fapps\u002Flearning-api\u002Fworkers\u002Flearning_agents\u002Fflashcard_agent\u002Freadme",{"path":128,"title":77},"\u002Fapps\u002Flearning-api\u002Fworkers\u002Flearning_agents\u002Fingestion_agent\u002Freadme",{"path":130,"title":77},"\u002Fapps\u002Flearning-api\u002Fworkers\u002Flearning_agents\u002Fquiz_agent\u002Freadme",{"path":132,"title":77},"\u002Fapps\u002Flearning-api\u002Fworkers\u002Flearning_agents\u002Fsummary_agent\u002Freadme",{"path":134,"title":77},"\u002Fapps\u002Flearning-api\u002Fworkers\u002Fparser\u002Freadme",{"path":136,"title":137},"\u002Fapps\u002Fmarketing-emails-preview\u002Fagents","Marketing Emails Preview (apps\u002Fmarketing-emails-preview)",{"path":139,"title":140},"\u002Fapps\u002Fmobile-app\u002Fagents","StudyFlash Mobile App - Claude Code Configuration",{"path":142,"title":140},"\u002Fapps\u002Fmobile-app\u002Fclaude",{"path":144,"title":145},"\u002Fapps\u002Fmountain-max\u002Fagents","Mountain Max (apps\u002Fmountain-max)",{"path":147,"title":148},"\u002Fapps\u002Fmountain-max\u002Fgame\u002Freadme","Mountain Max Game",{"path":150,"title":151},"\u002Fapps\u002Fportal\u002Fagents","Portal (apps\u002Fportal)",{"path":153,"title":154},"\u002Fapps\u002Fportal\u002Freadme","Nuxt Minimal Starter",{"path":156,"title":157},"\u002Fapps\u002Fportal\u002Fapp\u002Fcomposables\u002Ffiles\u002Freadme","File Upload Composables",{"path":159,"title":160},"\u002Fapps\u002Fportal\u002Fdocs\u002Flibrary-routing","Library Routing Documentation",{"path":162,"title":163},"\u002Fapps\u002Fsupabase\u002Fagents","Supabase (apps\u002Fsupabase)",{"path":165,"title":166},"\u002Fapps\u002Fwrapped\u002Fagents","Wrapped (apps\u002Fwrapped)",{"path":168,"title":98},"\u002Fapps\u002Fwrapped\u002Freadme",{"path":170,"title":171},"\u002Finfra\u002Freadme","infra\u002F",{"path":173,"title":174},"\u002Finfra\u002Fdns\u002Freadme","DNS Infrastructure",{"path":176,"title":177},"\u002Finfra\u002Fdokploy\u002Freadme","studyflash-dokploy",{"path":179,"title":77},"\u002Finfra\u002Fdokploy\u002Fsdk\u002Fnodejs\u002Freadme",{"path":181,"title":182},"\u002Finfra\u002Finfisical\u002Freadme","Infisical Infrastructure",{"path":184,"title":185},"\u002Finfra\u002Flearning-api\u002Freadme","Pulumi GCP TypeScript Template",{"path":187,"title":188},"\u002Finfra\u002Fopenreplay\u002Freadme","OpenReplay on Hetzner",{"path":190,"title":191},"\u002Finfra\u002Fscripts\u002Freadme","infra\u002Fscripts\u002F",{"path":193,"title":194},"\u002Finfra\u002Fturborepo-cache\u002Freadme","Turborepo Remote Cache Infrastructure",{"path":196,"title":197},"\u002Finternal\u002Fchatwoot\u002Freadme","Chatwoot Infrastructure",{"path":199,"title":200},"\u002Finternal\u002Fchatwoot\u002Fprovider\u002Freadme","studyflash-chatwoot-provider",{"path":202,"title":77},"\u002Finternal\u002Fchatwoot\u002Fprovider\u002Fsdk\u002Fnodejs\u002Freadme",{"path":204,"title":205},"\u002Finternal\u002Fdocs\u002Freadme","internal\u002Fdocs",{"path":207,"title":208},"\u002Finternal\u002Fsupport-bot\u002Fclaude","Support Bot (Maximilian)",{"path":210,"title":211},"\u002Finternal\u002Fsupport-bot\u002Freadme","Studyflash Customer Support Bot (Maximilian)",{"path":213,"title":214},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Faccount_issues","Account Issues",{"path":216,"title":217},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fbilling_invoice","Billing Invoice",{"path":219,"title":220},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fcontent_upload","Content Upload",{"path":222,"title":223},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fdata_loss","Data Loss",{"path":225,"title":226},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fflashcard_issues","Flashcard Issues",{"path":228,"title":229},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fgarbage","Garbage",{"path":231,"title":232},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fgeneral_how_to","General How To",{"path":234,"title":235},"\u002Finternal\u002Fsupport-bot\u002Fkb","Knowledge Base Index",{"path":237,"title":238},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Flanguage_issues","Language Issues",{"path":240,"title":241},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fmindmap_issues","Mindmap Issues",{"path":243,"title":244},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fmisunderstanding","Misunderstanding",{"path":246,"title":247},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fmock_exam_issues","Mock Exam Issues",{"path":249,"title":250},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fpodcast_issues","Podcast Issues",{"path":252,"title":253},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fquiz_issues","Quiz Issues",{"path":255,"title":256},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Frefund_request","Refund Request",{"path":258,"title":259},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fsubscription_cancellation","Subscription Cancellation",{"path":261,"title":262},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fsubscription_info","Subscription Info",{"path":264,"title":265},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fsummary_issues","Summary Issues",{"path":267,"title":268},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Ftechnical_errors","Technical Errors",{"path":270,"title":271},"\u002Finternal\u002Fsupport-bot\u002Fkb\u002Fvideo_issues","Video Issues",{"path":273,"title":274},"\u002Fpackages\u002Fcommon\u002Fdocs\u002Fearly-access-features","Declarative Early Access Features",{"path":276,"title":277},"\u002Fpackages\u002Fcommon\u002Fscripts\u002Freadme","Common Package Scripts",{"path":279,"title":280},"\u002Fpackages\u002Fdevtools\u002Ffigma-plugins\u002Freadme","Figma plugins",{"path":282,"title":77},"\u002Fpackages\u002Fpulumi-infisical\u002Freadme",{"id":284,"title":208,"body":285,"description":295,"extension":702,"lastReviewed":703,"meta":704,"navigation":346,"owner":703,"path":207,"seo":705,"status":703,"stem":706,"tags":703,"__hash__":707},"repo\u002Finternal\u002Fsupport-bot\u002FCLAUDE.md",{"type":286,"value":287,"toc":694},"minimark",[288,292,296,301,426,430,471,475,567,571,591,595,610,652,656,690],[289,290,208],"h1",{"id":291},"support-bot-maximilian",[293,294,295],"p",{},"Customer support automation for Studyflash using Gemini AI with KB-grounded responses.",[297,298,300],"h2",{"id":299},"quick-reference","Quick Reference",[302,303,308],"pre",{"className":304,"code":305,"language":306,"meta":307,"style":307},"language-bash shiki shiki-themes github-light github-dark","# Local dev\nuvicorn main:app --reload --port 8000\n\n# Deploy\n# Auto-deploys on push to `main` of studyflash-ai\u002Fstudyflash via Dokploy's\n# GitHub integration. No manual deploy step.\n\n# Adopt \u002F drift-check the Dokploy resources via Pulumi\npnpm preview   # pulumi preview --diff\npnpm run pulumi:up # pulumi up\n\n# Check logs\n# Open the Customer Support project in Dokploy UI → Customer Support Bot →\n# Logs tab. Same source-of-truth used by the Dokploy auto-deploy pipeline.\n","bash","",[309,310,311,320,341,348,354,360,366,371,377,389,403,408,414,420],"code",{"__ignoreMap":307},[312,313,316],"span",{"class":314,"line":315},"line",1,[312,317,319],{"class":318},"sJ8bj","# Local dev\n",[312,321,323,327,331,335,338],{"class":314,"line":322},2,[312,324,326],{"class":325},"sScJk","uvicorn",[312,328,330],{"class":329},"sZZnC"," main:app",[312,332,334],{"class":333},"sj4cs"," --reload",[312,336,337],{"class":333}," --port",[312,339,340],{"class":333}," 8000\n",[312,342,344],{"class":314,"line":343},3,[312,345,347],{"emptyLinePlaceholder":346},true,"\n",[312,349,351],{"class":314,"line":350},4,[312,352,353],{"class":318},"# Deploy\n",[312,355,357],{"class":314,"line":356},5,[312,358,359],{"class":318},"# Auto-deploys on push to `main` of studyflash-ai\u002Fstudyflash via Dokploy's\n",[312,361,363],{"class":314,"line":362},6,[312,364,365],{"class":318},"# GitHub integration. No manual deploy step.\n",[312,367,369],{"class":314,"line":368},7,[312,370,347],{"emptyLinePlaceholder":346},[312,372,374],{"class":314,"line":373},8,[312,375,376],{"class":318},"# Adopt \u002F drift-check the Dokploy resources via Pulumi\n",[312,378,380,383,386],{"class":314,"line":379},9,[312,381,382],{"class":325},"pnpm",[312,384,385],{"class":329}," preview",[312,387,388],{"class":318},"   # pulumi preview --diff\n",[312,390,392,394,397,400],{"class":314,"line":391},10,[312,393,382],{"class":325},[312,395,396],{"class":329}," run",[312,398,399],{"class":329}," pulumi:up",[312,401,402],{"class":318}," # pulumi up\n",[312,404,406],{"class":314,"line":405},11,[312,407,347],{"emptyLinePlaceholder":346},[312,409,411],{"class":314,"line":410},12,[312,412,413],{"class":318},"# Check logs\n",[312,415,417],{"class":314,"line":416},13,[312,418,419],{"class":318},"# Open the Customer Support project in Dokploy UI → Customer Support Bot →\n",[312,421,423],{"class":314,"line":422},14,[312,424,425],{"class":318},"# Logs tab. Same source-of-truth used by the Dokploy auto-deploy pipeline.\n",[297,427,429],{"id":428},"architecture","Architecture",[431,432,433,441,447,453],"ul",{},[434,435,436,440],"li",{},[437,438,439],"strong",{},"Context Stuffing",": Entire KB (~10 pages) fed to AI per request, no vector DB",[434,442,443,446],{},[437,444,445],{},"Gemini 3 Flash",": Used for classification and draft generation",[434,448,449,452],{},[437,450,451],{},"Chatwoot",": Ticket management integration",[434,454,455,458,459,465,466,470],{},[437,456,457],{},"Dokploy",": Deployed at ",[460,461,462],"a",{"href":462,"rel":463},"https:\u002F\u002Fdokploy.studyflash.ch",[464],"nofollow"," (project: Customer Support). Public at ",[460,467,468],{"href":468,"rel":469},"https:\u002F\u002Fsupport-bot.studyflash.dev",[464],".",[297,472,474],{"id":473},"key-files","Key Files",[476,477,478,491],"table",{},[479,480,481],"thead",{},[482,483,484,488],"tr",{},[485,486,487],"th",{},"File",[485,489,490],{},"Purpose",[492,493,494,509,519,529,543,557],"tbody",{},[482,495,496,502],{},[497,498,499],"td",{},[309,500,501],{},"main.py",[497,503,504,505,508],{},"FastAPI app, ",[309,506,507],{},"\u002Fask"," endpoint",[482,510,511,516],{},[497,512,513],{},[309,514,515],{},"services\u002Fdraft_agent_service.py",[497,517,518],{},"Gemini draft generation",[482,520,521,526],{},[497,522,523],{},[309,524,525],{},"services\u002Fcategory_classifier_service.py",[497,527,528],{},"Query classification",[482,530,531,536],{},[497,532,533],{},[309,534,535],{},"services\u002Fkb_service.py",[497,537,538,539,542],{},"KB loading from ",[309,540,541],{},"kb\u002F"," directory",[482,544,545,550],{},[497,546,547],{},[309,548,549],{},"models\u002Fdraft.py",[497,551,552,553,556],{},"Response schemas (no defaults in ",[309,554,555],{},"DraftResponseSchema"," - Gemini limitation)",[482,558,559,564],{},[497,560,561],{},[309,562,563],{},"kb\u002F*.md",[497,565,566],{},"Knowledge base articles by category",[297,568,570],{"id":569},"api-endpoints","API Endpoints",[431,572,573,579,585],{},[434,574,575,578],{},[309,576,577],{},"POST \u002Fask"," - Main support query endpoint",[434,580,581,584],{},[309,582,583],{},"POST \u002Fanalyze"," - Weekly gap analyzer",[434,586,587,590],{},[309,588,589],{},"POST \u002Flog-correction"," - Log human corrections",[297,592,594],{"id":593},"secrets","Secrets",[293,596,597,598,601,602,605,606,609],{},"Sourced from Infisical at ",[309,599,600],{},"\u002Finternal\u002Fsupport-bot\u002F"," (prod env), written to\nDokploy's native env at ",[309,603,604],{},"pulumi up"," time. Live keys (per ",[309,607,608],{},"application.one","):",[431,611,612,617,622,627,632,637,642,647],{},[434,613,614],{},[309,615,616],{},"AUTOMATIONS_ADMIN_KEY",[434,618,619],{},[309,620,621],{},"AUTO_REPLY_ENABLED",[434,623,624],{},[309,625,626],{},"CHATWOOT_ACCOUNT_ID",[434,628,629],{},[309,630,631],{},"CHATWOOT_API_TOKEN",[434,633,634],{},[309,635,636],{},"CHATWOOT_API_URL",[434,638,639],{},[309,640,641],{},"GEMINI_API_KEY",[434,643,644],{},[309,645,646],{},"METABASE_EMBEDDING_SECRET_KEY",[434,648,649],{},[309,650,651],{},"PORT",[297,653,655],{"id":654},"deployment-notes","Deployment Notes",[431,657,658,669,676],{},[434,659,660,661,664,665,668],{},"KB files must be in ",[309,662,663],{},".dockerignore"," whitelist (",[309,666,667],{},"!kb\u002F*.md",").",[434,670,671,672,675],{},"Public URL: ",[460,673,468],{"href":468,"rel":674},[464]," (port 8080 in-container, Let's Encrypt via Dokploy).",[434,677,678,679,682,683,682,686,689],{},"Pulumi adoption stack lives next to the source — ",[309,680,681],{},"index.ts",", ",[309,684,685],{},"Pulumi.yaml",[309,687,688],{},"package.json"," in this directory.",[691,692,693],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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":307,"searchDepth":322,"depth":322,"links":695},[696,697,698,699,700,701],{"id":299,"depth":322,"text":300},{"id":428,"depth":322,"text":429},{"id":473,"depth":322,"text":474},{"id":569,"depth":322,"text":570},{"id":593,"depth":322,"text":594},{"id":654,"depth":322,"text":655},"md",null,{},{"title":208,"description":295},"internal\u002Fsupport-bot\u002FCLAUDE","JwBxlc7r0MXRGFTPnjLQDuZHTsnQoC1rMn2GIzpqwyw",1779007964216]