[{"data":1,"prerenderedAt":1023},["ShallowReactive",2],{"repo-tree":3,"repo-\u002Fapps\u002Flearning-api\u002Freadme":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":77,"body":285,"description":385,"extension":1017,"lastReviewed":1018,"meta":1019,"navigation":636,"owner":1018,"path":89,"seo":1020,"status":1018,"stem":1021,"tags":1018,"__hash__":1022},"repo\u002Fapps\u002Flearning-api\u002FREADME.md",{"type":286,"value":287,"toc":1000},"minimark",[288,293,297,306,349,364,368,373,379,401,404,408,413,448,453,556,560,565,575,578,583,610,614,797,801,804,808,829,833,838,891,895,912,916,952,956,959,996],[289,290,292],"h2",{"id":291},"learningapi-v2","LearningAPI V2",[289,294,296],{"id":295},"codebase-structure","📁 Codebase Structure",[298,299,300,301,305],"p",{},"This is a ",[302,303,304],"strong",{},"monorepo"," with multiple UV projects:",[307,308,309,319,327],"ul",{},[310,311,312,318],"li",{},[302,313,314],{},[315,316,317],"code",{},"shared\u002F"," - Common interfaces, types, and utilities used by all services",[310,320,321,326],{},[302,322,323],{},[315,324,325],{},"api\u002F"," - FastAPI web service (depends on shared)",[310,328,329,334,335],{},[302,330,331],{},[315,332,333],{},"workers\u002F"," - Background processing services (depends on shared)\n",[307,336,337,343],{},[310,338,339,342],{},[315,340,341],{},"learning_agents\u002F"," - AI learning worker handling generation tasks",[310,344,345,348],{},[315,346,347],{},"parser\u002F"," - Document Parsing with Docling",[298,350,351,352,355,356,359,360,363],{},"Each directory is an independent ",[302,353,354],{},"UV project"," with its own ",[315,357,358],{},"pyproject.toml",", but all depend on the ",[315,361,362],{},"shared"," package.",[289,365,367],{"id":366},"getting-started","🚀 Getting Started",[369,370,372],"h3",{"id":371},"option-1-github-codespace-recommended","Option 1: GitHub Codespace (Recommended)",[298,374,375,378],{},[302,376,377],{},"No setup required!"," Just open in a codespace and run:",[380,381,386],"pre",{"className":382,"code":383,"language":384,"meta":385,"style":385},"language-bash shiki shiki-themes github-light github-dark","poe dev\n","bash","",[315,387,388],{"__ignoreMap":385},[389,390,393,397],"span",{"class":391,"line":392},"line",1,[389,394,396],{"class":395},"sScJk","poe",[389,398,400],{"class":399},"sZZnC"," dev\n",[298,402,403],{},"Everything is pre-configured and ready to go.",[369,405,407],{"id":406},"option-2-local-development","Option 2: Local Development",[298,409,410],{},[302,411,412],{},"Prerequisites:",[307,414,415,418,428,440],{},[310,416,417],{},"Docker & Docker Compose",[310,419,420,427],{},[421,422,426],"a",{"href":423,"rel":424},"https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002F",[425],"nofollow","UV"," (Python package manager)",[310,429,430,435,436,439],{},[421,431,434],{"href":432,"rel":433},"https:\u002F\u002Fpoethepoet.natn.io\u002F",[425],"Poe the Poet"," (",[315,437,438],{},"uv tool install poethepoet",")",[310,441,442,447],{},[421,443,446],{"href":444,"rel":445},"https:\u002F\u002Finfisical.com\u002Fdocs\u002Fcli\u002Foverview",[425],"Infisical CLI"," (for secret management)",[298,449,450],{},[302,451,452],{},"Setup:",[454,455,456,480,498,524,541],"ol",{},[310,457,458,461],{},[302,459,460],{},"Install Poe the Poet:",[380,462,464],{"className":382,"code":463,"language":384,"meta":385,"style":385},"uv tool install poethepoet\n",[315,465,466],{"__ignoreMap":385},[389,467,468,471,474,477],{"class":391,"line":392},[389,469,470],{"class":395},"uv",[389,472,473],{"class":399}," tool",[389,475,476],{"class":399}," install",[389,478,479],{"class":399}," poethepoet\n",[310,481,482,485],{},[302,483,484],{},"Login to Infisical:",[380,486,488],{"className":382,"code":487,"language":384,"meta":385,"style":385},"infisical login\n",[315,489,490],{"__ignoreMap":385},[389,491,492,495],{"class":391,"line":392},[389,493,494],{"class":395},"infisical",[389,496,497],{"class":399}," login\n",[310,499,500,503],{},[302,501,502],{},"Set your environment:",[380,504,506],{"className":382,"code":505,"language":384,"meta":385,"style":385},"export INFISICAL_ENV=dev\n",[315,507,508],{"__ignoreMap":385},[389,509,510,514,518,521],{"class":391,"line":392},[389,511,513],{"class":512},"szBVR","export",[389,515,517],{"class":516},"sVt8B"," INFISICAL_ENV",[389,519,520],{"class":512},"=",[389,522,523],{"class":516},"dev\n",[310,525,526,529],{},[302,527,528],{},"Verify secrets access:",[380,530,532],{"className":382,"code":531,"language":384,"meta":385,"style":385},"poe set-secrets\n",[315,533,534],{"__ignoreMap":385},[389,535,536,538],{"class":391,"line":392},[389,537,396],{"class":395},[389,539,540],{"class":399}," set-secrets\n",[310,542,543,546],{},[302,544,545],{},"Start development:",[380,547,548],{"className":382,"code":383,"language":384,"meta":385,"style":385},[315,549,550],{"__ignoreMap":385},[389,551,552,554],{"class":391,"line":392},[389,553,396],{"class":395},[389,555,400],{"class":399},[289,557,559],{"id":558},"️-development-commands","🛠️ Development Commands",[298,561,562],{},[302,563,564],{},"Local Development (Default - Recommended):",[380,566,567],{"className":382,"code":383,"language":384,"meta":385,"style":385},[315,568,569],{"__ignoreMap":385},[389,570,571,573],{"class":391,"line":392},[389,572,396],{"class":395},[389,574,400],{"class":399},[298,576,577],{},"Runs API and workers locally with Redis in Docker. All logs in one terminal with color coding and auto-reload on code changes.",[298,579,580],{},[302,581,582],{},"Full Docker Environment:",[380,584,586],{"className":382,"code":585,"language":384,"meta":385,"style":385},"poe dev-docker              # Slim CPU parser stack; requires TRITON_URL\npoe dev-docker-parser-gpu   # Legacy local GPU\u002FVLLM parser stack\n",[315,587,588,599],{"__ignoreMap":385},[389,589,590,592,595],{"class":391,"line":392},[389,591,396],{"class":395},[389,593,594],{"class":399}," dev-docker",[389,596,598],{"class":597},"sJ8bj","              # Slim CPU parser stack; requires TRITON_URL\n",[389,600,602,604,607],{"class":391,"line":601},2,[389,603,396],{"class":395},[389,605,606],{"class":399}," dev-docker-parser-gpu",[389,608,609],{"class":597},"   # Legacy local GPU\u002FVLLM parser stack\n",[369,611,613],{"id":612},"other-useful-commands","Other Useful Commands",[380,615,617],{"className":382,"code":616,"language":384,"meta":385,"style":385},"# Install dependencies for all projects\npoe install\n\n# Generate TS types (then copy manually to core-api)\npoe update-types \n\n# Run linting across all projects\npoe lint\n\n# Format code across all projects\npoe format\n\n# Run type checking\npoe typecheck\n\n# Run tests\npoe test              # Run all tests\npoe test-unit         # Run unit tests only\npoe test-integration  # Run integration tests only\n\n# Run tests with automatic service management (recommended)\npoe test-with-services  # Automatically starts test Docker services\n\n# Run CI pipeline (lint + typecheck)\npoe ci\n",[315,618,619,624,631,638,644,655,660,666,674,679,685,693,698,704,712,717,723,734,745,756,761,767,778,783,789],{"__ignoreMap":385},[389,620,621],{"class":391,"line":392},[389,622,623],{"class":597},"# Install dependencies for all projects\n",[389,625,626,628],{"class":391,"line":601},[389,627,396],{"class":395},[389,629,630],{"class":399}," install\n",[389,632,634],{"class":391,"line":633},3,[389,635,637],{"emptyLinePlaceholder":636},true,"\n",[389,639,641],{"class":391,"line":640},4,[389,642,643],{"class":597},"# Generate TS types (then copy manually to core-api)\n",[389,645,647,649,652],{"class":391,"line":646},5,[389,648,396],{"class":395},[389,650,651],{"class":399}," update-types",[389,653,654],{"class":516}," \n",[389,656,658],{"class":391,"line":657},6,[389,659,637],{"emptyLinePlaceholder":636},[389,661,663],{"class":391,"line":662},7,[389,664,665],{"class":597},"# Run linting across all projects\n",[389,667,669,671],{"class":391,"line":668},8,[389,670,396],{"class":395},[389,672,673],{"class":399}," lint\n",[389,675,677],{"class":391,"line":676},9,[389,678,637],{"emptyLinePlaceholder":636},[389,680,682],{"class":391,"line":681},10,[389,683,684],{"class":597},"# Format code across all projects\n",[389,686,688,690],{"class":391,"line":687},11,[389,689,396],{"class":395},[389,691,692],{"class":399}," format\n",[389,694,696],{"class":391,"line":695},12,[389,697,637],{"emptyLinePlaceholder":636},[389,699,701],{"class":391,"line":700},13,[389,702,703],{"class":597},"# Run type checking\n",[389,705,707,709],{"class":391,"line":706},14,[389,708,396],{"class":395},[389,710,711],{"class":399}," typecheck\n",[389,713,715],{"class":391,"line":714},15,[389,716,637],{"emptyLinePlaceholder":636},[389,718,720],{"class":391,"line":719},16,[389,721,722],{"class":597},"# Run tests\n",[389,724,726,728,731],{"class":391,"line":725},17,[389,727,396],{"class":395},[389,729,730],{"class":399}," test",[389,732,733],{"class":597},"              # Run all tests\n",[389,735,737,739,742],{"class":391,"line":736},18,[389,738,396],{"class":395},[389,740,741],{"class":399}," test-unit",[389,743,744],{"class":597},"         # Run unit tests only\n",[389,746,748,750,753],{"class":391,"line":747},19,[389,749,396],{"class":395},[389,751,752],{"class":399}," test-integration",[389,754,755],{"class":597},"  # Run integration tests only\n",[389,757,759],{"class":391,"line":758},20,[389,760,637],{"emptyLinePlaceholder":636},[389,762,764],{"class":391,"line":763},21,[389,765,766],{"class":597},"# Run tests with automatic service management (recommended)\n",[389,768,770,772,775],{"class":391,"line":769},22,[389,771,396],{"class":395},[389,773,774],{"class":399}," test-with-services",[389,776,777],{"class":597},"  # Automatically starts test Docker services\n",[389,779,781],{"class":391,"line":780},23,[389,782,637],{"emptyLinePlaceholder":636},[389,784,786],{"class":391,"line":785},24,[389,787,788],{"class":597},"# Run CI pipeline (lint + typecheck)\n",[389,790,792,794],{"class":391,"line":791},25,[389,793,396],{"class":395},[389,795,796],{"class":399}," ci\n",[289,798,800],{"id":799},"testing","🧪 Testing",[298,802,803],{},"The project includes comprehensive unit and integration tests:",[369,805,807],{"id":806},"test-structure","Test Structure",[307,809,810,820],{},[310,811,812,815,816,819],{},[302,813,814],{},"Unit Tests",": Located in ",[315,817,818],{},"api\u002Ftests\u002F"," - Fast, isolated tests for API endpoints",[310,821,822,815,825,828],{},[302,823,824],{},"Integration Tests",[315,826,827],{},"tests_integration\u002Ftest_integration.py"," - Service connectivity and end-to-end workflows",[369,830,832],{"id":831},"running-tests","Running Tests",[834,835,837],"h4",{"id":836},"quick-testing-requires-services-running","Quick Testing (requires services running)",[380,839,841],{"className":382,"code":840,"language":384,"meta":385,"style":385},"# Start services first\npoe dev  # In one terminal\n\n# Run tests in another terminal\npoe test              # Run all tests\npoe test-unit         # Run unit tests only\npoe test-integration  # Run integration tests only\n",[315,842,843,848,858,862,867,875,883],{"__ignoreMap":385},[389,844,845],{"class":391,"line":392},[389,846,847],{"class":597},"# Start services first\n",[389,849,850,852,855],{"class":391,"line":601},[389,851,396],{"class":395},[389,853,854],{"class":399}," dev",[389,856,857],{"class":597},"  # In one terminal\n",[389,859,860],{"class":391,"line":633},[389,861,637],{"emptyLinePlaceholder":636},[389,863,864],{"class":391,"line":640},[389,865,866],{"class":597},"# Run tests in another terminal\n",[389,868,869,871,873],{"class":391,"line":646},[389,870,396],{"class":395},[389,872,730],{"class":399},[389,874,733],{"class":597},[389,876,877,879,881],{"class":391,"line":657},[389,878,396],{"class":395},[389,880,741],{"class":399},[389,882,744],{"class":597},[389,884,885,887,889],{"class":391,"line":662},[389,886,396],{"class":395},[389,888,752],{"class":399},[389,890,755],{"class":597},[834,892,894],{"id":893},"automated-testing-recommended","Automated Testing (recommended)",[380,896,898],{"className":382,"code":897,"language":384,"meta":385,"style":385},"# This command handles all service management automatically\npoe test-with-services\n",[315,899,900,905],{"__ignoreMap":385},[389,901,902],{"class":391,"line":392},[389,903,904],{"class":597},"# This command handles all service management automatically\n",[389,906,907,909],{"class":391,"line":601},[389,908,396],{"class":395},[389,910,911],{"class":399}," test-with-services\n",[369,913,915],{"id":914},"when-to-run-tests","When to Run Tests",[307,917,918,928,937,946],{},[310,919,920,923,924,927],{},[302,921,922],{},"Before committing",": Run ",[315,925,926],{},"poe test-unit"," for quick validation",[310,929,930,923,933,936],{},[302,931,932],{},"Before pushing",[315,934,935],{},"poe test"," to ensure nothing is broken",[310,938,939,923,942,945],{},[302,940,941],{},"After major changes",[315,943,944],{},"poe test-with-services"," for comprehensive validation",[310,947,948,951],{},[302,949,950],{},"CI\u002FCD",": Tests run automatically on pull requests",[289,953,955],{"id":954},"optional-pre-commit-setup","🔧 Optional: Pre-commit Setup",[298,957,958],{},"For automatic code formatting on commits:",[380,960,962],{"className":382,"code":961,"language":384,"meta":385,"style":385},"# Install pre-commit\nuv tool install pre-commit\n\n# Install git hooks\npoe pre-commit-install\n",[315,963,964,969,980,984,989],{"__ignoreMap":385},[389,965,966],{"class":391,"line":392},[389,967,968],{"class":597},"# Install pre-commit\n",[389,970,971,973,975,977],{"class":391,"line":601},[389,972,470],{"class":395},[389,974,473],{"class":399},[389,976,476],{"class":399},[389,978,979],{"class":399}," pre-commit\n",[389,981,982],{"class":391,"line":633},[389,983,637],{"emptyLinePlaceholder":636},[389,985,986],{"class":391,"line":640},[389,987,988],{"class":597},"# Install git hooks\n",[389,990,991,993],{"class":391,"line":646},[389,992,396],{"class":395},[389,994,995],{"class":399}," pre-commit-install\n",[997,998,999],"style",{},"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 .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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":385,"searchDepth":601,"depth":601,"links":1001},[1002,1003,1004,1008,1011,1016],{"id":291,"depth":601,"text":292},{"id":295,"depth":601,"text":296},{"id":366,"depth":601,"text":367,"children":1005},[1006,1007],{"id":371,"depth":633,"text":372},{"id":406,"depth":633,"text":407},{"id":558,"depth":601,"text":559,"children":1009},[1010],{"id":612,"depth":633,"text":613},{"id":799,"depth":601,"text":800,"children":1012},[1013,1014,1015],{"id":806,"depth":633,"text":807},{"id":831,"depth":633,"text":832},{"id":914,"depth":633,"text":915},{"id":954,"depth":601,"text":955},"md",null,{},{"description":385},"apps\u002Flearning-api\u002FREADME","bwj5vVyKvXqqGU47o-fxGbHYE6vXwlLQGEPDMKAO6rE",1779007962948]