javi-forge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/.gitignore.template +105 -0
  2. package/.releaserc +44 -0
  3. package/README.md +45 -0
  4. package/ai-config/.skillignore +15 -0
  5. package/ai-config/AUTO_INVOKE.md +300 -0
  6. package/ai-config/agents/_TEMPLATE.md +93 -0
  7. package/ai-config/agents/business/api-designer.md +1657 -0
  8. package/ai-config/agents/business/business-analyst.md +1331 -0
  9. package/ai-config/agents/business/product-strategist.md +206 -0
  10. package/ai-config/agents/business/project-manager.md +178 -0
  11. package/ai-config/agents/business/requirements-analyst.md +1277 -0
  12. package/ai-config/agents/business/technical-writer.md +1679 -0
  13. package/ai-config/agents/creative/ux-designer.md +205 -0
  14. package/ai-config/agents/data-ai/ai-engineer.md +487 -0
  15. package/ai-config/agents/data-ai/analytics-engineer.md +953 -0
  16. package/ai-config/agents/data-ai/data-engineer.md +173 -0
  17. package/ai-config/agents/data-ai/data-scientist.md +672 -0
  18. package/ai-config/agents/data-ai/mlops-engineer.md +814 -0
  19. package/ai-config/agents/data-ai/prompt-engineer.md +772 -0
  20. package/ai-config/agents/development/angular-expert.md +620 -0
  21. package/ai-config/agents/development/backend-architect.md +795 -0
  22. package/ai-config/agents/development/database-specialist.md +212 -0
  23. package/ai-config/agents/development/frontend-specialist.md +686 -0
  24. package/ai-config/agents/development/fullstack-engineer.md +668 -0
  25. package/ai-config/agents/development/golang-pro.md +338 -0
  26. package/ai-config/agents/development/java-enterprise.md +400 -0
  27. package/ai-config/agents/development/javascript-pro.md +422 -0
  28. package/ai-config/agents/development/nextjs-pro.md +474 -0
  29. package/ai-config/agents/development/python-pro.md +570 -0
  30. package/ai-config/agents/development/react-pro.md +487 -0
  31. package/ai-config/agents/development/rust-pro.md +246 -0
  32. package/ai-config/agents/development/spring-boot-4-expert.md +326 -0
  33. package/ai-config/agents/development/typescript-pro.md +336 -0
  34. package/ai-config/agents/development/vue-specialist.md +605 -0
  35. package/ai-config/agents/infrastructure/cloud-architect.md +472 -0
  36. package/ai-config/agents/infrastructure/deployment-manager.md +358 -0
  37. package/ai-config/agents/infrastructure/devops-engineer.md +455 -0
  38. package/ai-config/agents/infrastructure/incident-responder.md +519 -0
  39. package/ai-config/agents/infrastructure/kubernetes-expert.md +705 -0
  40. package/ai-config/agents/infrastructure/monitoring-specialist.md +674 -0
  41. package/ai-config/agents/infrastructure/performance-engineer.md +658 -0
  42. package/ai-config/agents/orchestrator.md +241 -0
  43. package/ai-config/agents/quality/accessibility-auditor.md +1204 -0
  44. package/ai-config/agents/quality/code-reviewer-compact.md +123 -0
  45. package/ai-config/agents/quality/code-reviewer.md +363 -0
  46. package/ai-config/agents/quality/dependency-manager.md +743 -0
  47. package/ai-config/agents/quality/e2e-test-specialist.md +1005 -0
  48. package/ai-config/agents/quality/performance-tester.md +1086 -0
  49. package/ai-config/agents/quality/security-auditor.md +133 -0
  50. package/ai-config/agents/quality/test-engineer.md +453 -0
  51. package/ai-config/agents/specialists/api-designer.md +87 -0
  52. package/ai-config/agents/specialists/backend-architect.md +73 -0
  53. package/ai-config/agents/specialists/code-reviewer.md +77 -0
  54. package/ai-config/agents/specialists/db-optimizer.md +75 -0
  55. package/ai-config/agents/specialists/devops-engineer.md +83 -0
  56. package/ai-config/agents/specialists/documentation-writer.md +78 -0
  57. package/ai-config/agents/specialists/frontend-developer.md +75 -0
  58. package/ai-config/agents/specialists/performance-analyst.md +82 -0
  59. package/ai-config/agents/specialists/refactor-specialist.md +74 -0
  60. package/ai-config/agents/specialists/security-auditor.md +74 -0
  61. package/ai-config/agents/specialists/test-engineer.md +81 -0
  62. package/ai-config/agents/specialists/ux-consultant.md +76 -0
  63. package/ai-config/agents/specialized/agent-generator.md +1190 -0
  64. package/ai-config/agents/specialized/blockchain-developer.md +149 -0
  65. package/ai-config/agents/specialized/code-migrator.md +892 -0
  66. package/ai-config/agents/specialized/context-manager.md +978 -0
  67. package/ai-config/agents/specialized/documentation-writer.md +1078 -0
  68. package/ai-config/agents/specialized/ecommerce-expert.md +1756 -0
  69. package/ai-config/agents/specialized/embedded-engineer.md +1714 -0
  70. package/ai-config/agents/specialized/error-detective.md +1034 -0
  71. package/ai-config/agents/specialized/fintech-specialist.md +1659 -0
  72. package/ai-config/agents/specialized/freelance-project-planner-v2.md +1988 -0
  73. package/ai-config/agents/specialized/freelance-project-planner-v3.md +2136 -0
  74. package/ai-config/agents/specialized/freelance-project-planner-v4.md +4503 -0
  75. package/ai-config/agents/specialized/freelance-project-planner.md +722 -0
  76. package/ai-config/agents/specialized/game-developer.md +1963 -0
  77. package/ai-config/agents/specialized/healthcare-dev.md +1620 -0
  78. package/ai-config/agents/specialized/mobile-developer.md +188 -0
  79. package/ai-config/agents/specialized/parallel-plan-executor.md +506 -0
  80. package/ai-config/agents/specialized/plan-executor.md +485 -0
  81. package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +485 -0
  82. package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +3493 -0
  83. package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +778 -0
  84. package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +918 -0
  85. package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +1537 -0
  86. package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +2633 -0
  87. package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +5610 -0
  88. package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +335 -0
  89. package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +215 -0
  90. package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +260 -0
  91. package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +379 -0
  92. package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +355 -0
  93. package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +279 -0
  94. package/ai-config/agents/specialized/template-writer.md +347 -0
  95. package/ai-config/agents/specialized/test-runner.md +99 -0
  96. package/ai-config/agents/specialized/vibekanban-smart-worker.md +244 -0
  97. package/ai-config/agents/specialized/wave-executor.md +138 -0
  98. package/ai-config/agents/specialized/workflow-optimizer.md +1114 -0
  99. package/ai-config/commands/git/changelog.md +32 -0
  100. package/ai-config/commands/git/ci-local.md +70 -0
  101. package/ai-config/commands/git/commit.md +35 -0
  102. package/ai-config/commands/git/fix-issue.md +23 -0
  103. package/ai-config/commands/git/pr-create.md +42 -0
  104. package/ai-config/commands/git/pr-review.md +50 -0
  105. package/ai-config/commands/git/worktree.md +39 -0
  106. package/ai-config/commands/refactoring/cleanup.md +24 -0
  107. package/ai-config/commands/refactoring/dead-code.md +40 -0
  108. package/ai-config/commands/refactoring/extract.md +31 -0
  109. package/ai-config/commands/testing/e2e.md +30 -0
  110. package/ai-config/commands/testing/tdd.md +36 -0
  111. package/ai-config/commands/testing/test-coverage.md +30 -0
  112. package/ai-config/commands/testing/test-fix.md +24 -0
  113. package/ai-config/commands/workflow/generate-agents-md.md +85 -0
  114. package/ai-config/commands/workflow/planning.md +47 -0
  115. package/ai-config/commands/workflows/compound.md +89 -0
  116. package/ai-config/commands/workflows/plan.md +77 -0
  117. package/ai-config/commands/workflows/review.md +78 -0
  118. package/ai-config/commands/workflows/work.md +75 -0
  119. package/ai-config/config.yaml +18 -0
  120. package/ai-config/hooks/_TEMPLATE.md +96 -0
  121. package/ai-config/hooks/block-dangerous-commands.md +75 -0
  122. package/ai-config/hooks/commit-guard.md +90 -0
  123. package/ai-config/hooks/context-loader.md +73 -0
  124. package/ai-config/hooks/improve-prompt.md +91 -0
  125. package/ai-config/hooks/learning-log.md +72 -0
  126. package/ai-config/hooks/model-router.md +86 -0
  127. package/ai-config/hooks/secret-scanner.md +64 -0
  128. package/ai-config/hooks/skill-validator.md +102 -0
  129. package/ai-config/hooks/task-artifact.md +114 -0
  130. package/ai-config/hooks/validate-workflow.md +100 -0
  131. package/ai-config/prompts/base.md +71 -0
  132. package/ai-config/prompts/modes/debug.md +34 -0
  133. package/ai-config/prompts/modes/deploy.md +40 -0
  134. package/ai-config/prompts/modes/research.md +32 -0
  135. package/ai-config/prompts/modes/review.md +33 -0
  136. package/ai-config/prompts/review-policy.md +79 -0
  137. package/ai-config/skills/_TEMPLATE.md +157 -0
  138. package/ai-config/skills/backend/api-gateway/SKILL.md +254 -0
  139. package/ai-config/skills/backend/bff-concepts/SKILL.md +239 -0
  140. package/ai-config/skills/backend/bff-spring/SKILL.md +364 -0
  141. package/ai-config/skills/backend/chi-router/SKILL.md +396 -0
  142. package/ai-config/skills/backend/error-handling/SKILL.md +255 -0
  143. package/ai-config/skills/backend/exceptions-spring/SKILL.md +323 -0
  144. package/ai-config/skills/backend/fastapi/SKILL.md +302 -0
  145. package/ai-config/skills/backend/gateway-spring/SKILL.md +390 -0
  146. package/ai-config/skills/backend/go-backend/SKILL.md +457 -0
  147. package/ai-config/skills/backend/gradle-multimodule/SKILL.md +274 -0
  148. package/ai-config/skills/backend/graphql-concepts/SKILL.md +352 -0
  149. package/ai-config/skills/backend/graphql-spring/SKILL.md +398 -0
  150. package/ai-config/skills/backend/grpc-concepts/SKILL.md +283 -0
  151. package/ai-config/skills/backend/grpc-spring/SKILL.md +445 -0
  152. package/ai-config/skills/backend/jwt-auth/SKILL.md +412 -0
  153. package/ai-config/skills/backend/notifications-concepts/SKILL.md +259 -0
  154. package/ai-config/skills/backend/recommendations-concepts/SKILL.md +261 -0
  155. package/ai-config/skills/backend/search-concepts/SKILL.md +263 -0
  156. package/ai-config/skills/backend/search-spring/SKILL.md +375 -0
  157. package/ai-config/skills/backend/spring-boot-4/SKILL.md +172 -0
  158. package/ai-config/skills/backend/websockets/SKILL.md +532 -0
  159. package/ai-config/skills/data-ai/ai-ml/SKILL.md +423 -0
  160. package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +195 -0
  161. package/ai-config/skills/data-ai/analytics-spring/SKILL.md +340 -0
  162. package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +440 -0
  163. package/ai-config/skills/data-ai/langchain/SKILL.md +238 -0
  164. package/ai-config/skills/data-ai/mlflow/SKILL.md +302 -0
  165. package/ai-config/skills/data-ai/onnx-inference/SKILL.md +290 -0
  166. package/ai-config/skills/data-ai/powerbi/SKILL.md +352 -0
  167. package/ai-config/skills/data-ai/pytorch/SKILL.md +274 -0
  168. package/ai-config/skills/data-ai/scikit-learn/SKILL.md +321 -0
  169. package/ai-config/skills/data-ai/vector-db/SKILL.md +301 -0
  170. package/ai-config/skills/database/graph-databases/SKILL.md +218 -0
  171. package/ai-config/skills/database/graph-spring/SKILL.md +361 -0
  172. package/ai-config/skills/database/pgx-postgres/SKILL.md +512 -0
  173. package/ai-config/skills/database/redis-cache/SKILL.md +343 -0
  174. package/ai-config/skills/database/sqlite-embedded/SKILL.md +388 -0
  175. package/ai-config/skills/database/timescaledb/SKILL.md +320 -0
  176. package/ai-config/skills/docs/api-documentation/SKILL.md +293 -0
  177. package/ai-config/skills/docs/docs-spring/SKILL.md +377 -0
  178. package/ai-config/skills/docs/mustache-templates/SKILL.md +190 -0
  179. package/ai-config/skills/docs/technical-docs/SKILL.md +447 -0
  180. package/ai-config/skills/frontend/astro-ssr/SKILL.md +441 -0
  181. package/ai-config/skills/frontend/frontend-design/SKILL.md +54 -0
  182. package/ai-config/skills/frontend/frontend-web/SKILL.md +368 -0
  183. package/ai-config/skills/frontend/mantine-ui/SKILL.md +396 -0
  184. package/ai-config/skills/frontend/tanstack-query/SKILL.md +439 -0
  185. package/ai-config/skills/frontend/zod-validation/SKILL.md +417 -0
  186. package/ai-config/skills/frontend/zustand-state/SKILL.md +350 -0
  187. package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +244 -0
  188. package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +378 -0
  189. package/ai-config/skills/infrastructure/devops-infra/SKILL.md +435 -0
  190. package/ai-config/skills/infrastructure/docker-containers/SKILL.md +420 -0
  191. package/ai-config/skills/infrastructure/kubernetes/SKILL.md +456 -0
  192. package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +546 -0
  193. package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +474 -0
  194. package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +315 -0
  195. package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +504 -0
  196. package/ai-config/skills/mobile/mobile-ionic/SKILL.md +448 -0
  197. package/ai-config/skills/prompt-improver/SKILL.md +125 -0
  198. package/ai-config/skills/quality/ghagga-review/SKILL.md +216 -0
  199. package/ai-config/skills/references/hooks-patterns/SKILL.md +238 -0
  200. package/ai-config/skills/references/mcp-servers/SKILL.md +275 -0
  201. package/ai-config/skills/references/plugins-reference/SKILL.md +110 -0
  202. package/ai-config/skills/references/skills-reference/SKILL.md +420 -0
  203. package/ai-config/skills/references/subagent-templates/SKILL.md +193 -0
  204. package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +410 -0
  205. package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +408 -0
  206. package/ai-config/skills/systems-iot/rust-systems/SKILL.md +386 -0
  207. package/ai-config/skills/systems-iot/tokio-async/SKILL.md +324 -0
  208. package/ai-config/skills/testing/playwright-e2e/SKILL.md +289 -0
  209. package/ai-config/skills/testing/testcontainers/SKILL.md +299 -0
  210. package/ai-config/skills/testing/vitest-testing/SKILL.md +381 -0
  211. package/ai-config/skills/workflow/ci-local-guide/SKILL.md +118 -0
  212. package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +299 -0
  213. package/ai-config/skills/workflow/claude-md-improver/SKILL.md +158 -0
  214. package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +117 -0
  215. package/ai-config/skills/workflow/git-github/SKILL.md +334 -0
  216. package/ai-config/skills/workflow/git-github/references/examples.md +160 -0
  217. package/ai-config/skills/workflow/git-workflow/SKILL.md +214 -0
  218. package/ai-config/skills/workflow/ide-plugins/SKILL.md +277 -0
  219. package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +401 -0
  220. package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +199 -0
  221. package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +100 -0
  222. package/ai-config/skills/workflow/verification-before-completion/SKILL.md +73 -0
  223. package/ai-config/skills/workflow/wave-workflow/SKILL.md +178 -0
  224. package/ci-local/README.md +170 -0
  225. package/ci-local/ci-local.sh +297 -0
  226. package/ci-local/hooks/commit-msg +74 -0
  227. package/ci-local/hooks/pre-commit +162 -0
  228. package/ci-local/hooks/pre-push +41 -0
  229. package/ci-local/install.sh +49 -0
  230. package/ci-local/semgrep.yml +214 -0
  231. package/dist/commands/analyze.d.ts +9 -0
  232. package/dist/commands/analyze.d.ts.map +1 -0
  233. package/dist/commands/analyze.js +55 -0
  234. package/dist/commands/analyze.js.map +1 -0
  235. package/dist/commands/analyze.test.d.ts +2 -0
  236. package/dist/commands/analyze.test.d.ts.map +1 -0
  237. package/dist/commands/analyze.test.js +145 -0
  238. package/dist/commands/analyze.test.js.map +1 -0
  239. package/dist/commands/doctor.d.ts +7 -0
  240. package/dist/commands/doctor.d.ts.map +1 -0
  241. package/dist/commands/doctor.js +158 -0
  242. package/dist/commands/doctor.js.map +1 -0
  243. package/dist/commands/doctor.test.d.ts +2 -0
  244. package/dist/commands/doctor.test.d.ts.map +1 -0
  245. package/dist/commands/doctor.test.js +200 -0
  246. package/dist/commands/doctor.test.js.map +1 -0
  247. package/dist/commands/init.d.ts +9 -0
  248. package/dist/commands/init.d.ts.map +1 -0
  249. package/dist/commands/init.js +283 -0
  250. package/dist/commands/init.js.map +1 -0
  251. package/dist/commands/init.test.d.ts +2 -0
  252. package/dist/commands/init.test.d.ts.map +1 -0
  253. package/dist/commands/init.test.js +271 -0
  254. package/dist/commands/init.test.js.map +1 -0
  255. package/dist/commands/sync.d.ts +8 -0
  256. package/dist/commands/sync.d.ts.map +1 -0
  257. package/dist/commands/sync.js +201 -0
  258. package/dist/commands/sync.js.map +1 -0
  259. package/dist/constants.d.ts +21 -0
  260. package/dist/constants.d.ts.map +1 -0
  261. package/dist/constants.js +57 -0
  262. package/dist/constants.js.map +1 -0
  263. package/dist/e2e/aggressive.e2e.test.d.ts +2 -0
  264. package/dist/e2e/aggressive.e2e.test.d.ts.map +1 -0
  265. package/dist/e2e/aggressive.e2e.test.js +350 -0
  266. package/dist/e2e/aggressive.e2e.test.js.map +1 -0
  267. package/dist/e2e/commands.e2e.test.d.ts +2 -0
  268. package/dist/e2e/commands.e2e.test.d.ts.map +1 -0
  269. package/dist/e2e/commands.e2e.test.js +213 -0
  270. package/dist/e2e/commands.e2e.test.js.map +1 -0
  271. package/dist/index.d.ts +3 -0
  272. package/dist/index.d.ts.map +1 -0
  273. package/dist/index.js +82 -0
  274. package/dist/index.js.map +1 -0
  275. package/dist/lib/common.d.ts +17 -0
  276. package/dist/lib/common.d.ts.map +1 -0
  277. package/dist/lib/common.js +111 -0
  278. package/dist/lib/common.js.map +1 -0
  279. package/dist/lib/common.test.d.ts +2 -0
  280. package/dist/lib/common.test.d.ts.map +1 -0
  281. package/dist/lib/common.test.js +316 -0
  282. package/dist/lib/common.test.js.map +1 -0
  283. package/dist/lib/frontmatter.d.ts +18 -0
  284. package/dist/lib/frontmatter.d.ts.map +1 -0
  285. package/dist/lib/frontmatter.js +61 -0
  286. package/dist/lib/frontmatter.js.map +1 -0
  287. package/dist/lib/frontmatter.test.d.ts +2 -0
  288. package/dist/lib/frontmatter.test.d.ts.map +1 -0
  289. package/dist/lib/frontmatter.test.js +257 -0
  290. package/dist/lib/frontmatter.test.js.map +1 -0
  291. package/dist/lib/template.d.ts +24 -0
  292. package/dist/lib/template.d.ts.map +1 -0
  293. package/dist/lib/template.js +78 -0
  294. package/dist/lib/template.js.map +1 -0
  295. package/dist/lib/template.test.d.ts +2 -0
  296. package/dist/lib/template.test.d.ts.map +1 -0
  297. package/dist/lib/template.test.js +201 -0
  298. package/dist/lib/template.test.js.map +1 -0
  299. package/dist/types/index.d.ts +48 -0
  300. package/dist/types/index.d.ts.map +1 -0
  301. package/dist/types/index.js +2 -0
  302. package/dist/types/index.js.map +1 -0
  303. package/dist/ui/AnalyzeUI.d.ts +7 -0
  304. package/dist/ui/AnalyzeUI.d.ts.map +1 -0
  305. package/dist/ui/AnalyzeUI.js +100 -0
  306. package/dist/ui/AnalyzeUI.js.map +1 -0
  307. package/dist/ui/App.d.ts +13 -0
  308. package/dist/ui/App.d.ts.map +1 -0
  309. package/dist/ui/App.js +100 -0
  310. package/dist/ui/App.js.map +1 -0
  311. package/dist/ui/CIContext.d.ts +9 -0
  312. package/dist/ui/CIContext.d.ts.map +1 -0
  313. package/dist/ui/CIContext.js +9 -0
  314. package/dist/ui/CIContext.js.map +1 -0
  315. package/dist/ui/CISelector.d.ts +8 -0
  316. package/dist/ui/CISelector.d.ts.map +1 -0
  317. package/dist/ui/CISelector.js +45 -0
  318. package/dist/ui/CISelector.js.map +1 -0
  319. package/dist/ui/Doctor.d.ts +3 -0
  320. package/dist/ui/Doctor.d.ts.map +1 -0
  321. package/dist/ui/Doctor.js +89 -0
  322. package/dist/ui/Doctor.js.map +1 -0
  323. package/dist/ui/Header.d.ts +8 -0
  324. package/dist/ui/Header.d.ts.map +1 -0
  325. package/dist/ui/Header.js +30 -0
  326. package/dist/ui/Header.js.map +1 -0
  327. package/dist/ui/MemorySelector.d.ts +8 -0
  328. package/dist/ui/MemorySelector.d.ts.map +1 -0
  329. package/dist/ui/MemorySelector.js +46 -0
  330. package/dist/ui/MemorySelector.js.map +1 -0
  331. package/dist/ui/NameInput.d.ts +8 -0
  332. package/dist/ui/NameInput.d.ts.map +1 -0
  333. package/dist/ui/NameInput.js +69 -0
  334. package/dist/ui/NameInput.js.map +1 -0
  335. package/dist/ui/OptionSelector.d.ts +12 -0
  336. package/dist/ui/OptionSelector.d.ts.map +1 -0
  337. package/dist/ui/OptionSelector.js +69 -0
  338. package/dist/ui/OptionSelector.js.map +1 -0
  339. package/dist/ui/Progress.d.ts +11 -0
  340. package/dist/ui/Progress.d.ts.map +1 -0
  341. package/dist/ui/Progress.js +58 -0
  342. package/dist/ui/Progress.js.map +1 -0
  343. package/dist/ui/StackSelector.d.ts +9 -0
  344. package/dist/ui/StackSelector.d.ts.map +1 -0
  345. package/dist/ui/StackSelector.js +65 -0
  346. package/dist/ui/StackSelector.js.map +1 -0
  347. package/dist/ui/Summary.d.ts +12 -0
  348. package/dist/ui/Summary.d.ts.map +1 -0
  349. package/dist/ui/Summary.js +114 -0
  350. package/dist/ui/Summary.js.map +1 -0
  351. package/dist/ui/SyncUI.d.ts +10 -0
  352. package/dist/ui/SyncUI.d.ts.map +1 -0
  353. package/dist/ui/SyncUI.js +64 -0
  354. package/dist/ui/SyncUI.js.map +1 -0
  355. package/dist/ui/Welcome.d.ts +7 -0
  356. package/dist/ui/Welcome.d.ts.map +1 -0
  357. package/dist/ui/Welcome.js +45 -0
  358. package/dist/ui/Welcome.js.map +1 -0
  359. package/dist/ui/theme.d.ts +10 -0
  360. package/dist/ui/theme.d.ts.map +1 -0
  361. package/dist/ui/theme.js +9 -0
  362. package/dist/ui/theme.js.map +1 -0
  363. package/modules/engram/.gitignore-snippet.txt +6 -0
  364. package/modules/engram/.mcp-config-snippet.json +11 -0
  365. package/modules/engram/README.md +146 -0
  366. package/modules/engram/install-engram.sh +216 -0
  367. package/modules/ghagga/.env.example +43 -0
  368. package/modules/ghagga/README.md +153 -0
  369. package/modules/ghagga/docker-compose.yml +80 -0
  370. package/modules/ghagga/setup-ghagga.sh +139 -0
  371. package/modules/memory-simple/.project/NOTES.md +22 -0
  372. package/modules/memory-simple/README.md +23 -0
  373. package/modules/obsidian-brain/.obsidian/app.json +23 -0
  374. package/modules/obsidian-brain/.obsidian/appearance.json +5 -0
  375. package/modules/obsidian-brain/.obsidian/bookmarks.json +34 -0
  376. package/modules/obsidian-brain/.obsidian/community-plugins.json +1 -0
  377. package/modules/obsidian-brain/.obsidian/core-plugins-migration.json +21 -0
  378. package/modules/obsidian-brain/.obsidian/core-plugins.json +18 -0
  379. package/modules/obsidian-brain/.obsidian/daily-notes.json +5 -0
  380. package/modules/obsidian-brain/.obsidian/graph.json +37 -0
  381. package/modules/obsidian-brain/.obsidian/hotkeys.json +14 -0
  382. package/modules/obsidian-brain/.obsidian/plugins/dataview/data.json +25 -0
  383. package/modules/obsidian-brain/.obsidian/plugins/obsidian-kanban/data.json +29 -0
  384. package/modules/obsidian-brain/.obsidian/plugins/templater-obsidian/data.json +18 -0
  385. package/modules/obsidian-brain/.obsidian/snippets/project-memory.css +71 -0
  386. package/modules/obsidian-brain/.obsidian-gitignore-snippet.txt +8 -0
  387. package/modules/obsidian-brain/.project/Attachments/.gitkeep +0 -0
  388. package/modules/obsidian-brain/.project/Memory/BLOCKERS.md +78 -0
  389. package/modules/obsidian-brain/.project/Memory/CONTEXT.md +102 -0
  390. package/modules/obsidian-brain/.project/Memory/DASHBOARD.md +73 -0
  391. package/modules/obsidian-brain/.project/Memory/DECISIONS.md +87 -0
  392. package/modules/obsidian-brain/.project/Memory/KANBAN.md +15 -0
  393. package/modules/obsidian-brain/.project/Memory/README.md +61 -0
  394. package/modules/obsidian-brain/.project/Memory/WAVES.md +78 -0
  395. package/modules/obsidian-brain/.project/Sessions/TEMPLATE.md +99 -0
  396. package/modules/obsidian-brain/.project/Templates/ADR.md +33 -0
  397. package/modules/obsidian-brain/.project/Templates/Blocker.md +21 -0
  398. package/modules/obsidian-brain/.project/Templates/Session.md +88 -0
  399. package/modules/obsidian-brain/README.md +268 -0
  400. package/modules/obsidian-brain/new-wave.sh +182 -0
  401. package/package.json +51 -0
  402. package/schemas/agent.schema.json +34 -0
  403. package/schemas/ai-config.schema.json +28 -0
  404. package/schemas/skill.schema.json +44 -0
  405. package/src/commands/analyze.test.ts +145 -0
  406. package/src/commands/analyze.ts +69 -0
  407. package/src/commands/doctor.test.ts +208 -0
  408. package/src/commands/doctor.ts +163 -0
  409. package/src/commands/init.test.ts +298 -0
  410. package/src/commands/init.ts +285 -0
  411. package/src/constants.ts +69 -0
  412. package/src/e2e/aggressive.e2e.test.ts +557 -0
  413. package/src/e2e/commands.e2e.test.ts +298 -0
  414. package/src/index.tsx +106 -0
  415. package/src/lib/common.test.ts +318 -0
  416. package/src/lib/common.ts +127 -0
  417. package/src/lib/frontmatter.test.ts +291 -0
  418. package/src/lib/frontmatter.ts +77 -0
  419. package/src/lib/template.test.ts +226 -0
  420. package/src/lib/template.ts +99 -0
  421. package/src/types/index.ts +53 -0
  422. package/src/ui/AnalyzeUI.tsx +133 -0
  423. package/src/ui/App.tsx +175 -0
  424. package/src/ui/CIContext.tsx +25 -0
  425. package/src/ui/CISelector.tsx +72 -0
  426. package/src/ui/Doctor.tsx +122 -0
  427. package/src/ui/Header.tsx +48 -0
  428. package/src/ui/MemorySelector.tsx +73 -0
  429. package/src/ui/NameInput.tsx +82 -0
  430. package/src/ui/OptionSelector.tsx +100 -0
  431. package/src/ui/Progress.tsx +88 -0
  432. package/src/ui/StackSelector.tsx +101 -0
  433. package/src/ui/Summary.tsx +134 -0
  434. package/src/ui/Welcome.tsx +54 -0
  435. package/src/ui/theme.ts +10 -0
  436. package/stryker.config.json +19 -0
  437. package/tasks/_TEMPLATE/files-edited.md +3 -0
  438. package/tasks/_TEMPLATE/plan.md +3 -0
  439. package/tasks/_TEMPLATE/research.md +3 -0
  440. package/tasks/_TEMPLATE/verification.md +5 -0
  441. package/templates/common/dependabot/cargo.yml +11 -0
  442. package/templates/common/dependabot/github-actions.yml +16 -0
  443. package/templates/common/dependabot/gomod.yml +15 -0
  444. package/templates/common/dependabot/gradle.yml +15 -0
  445. package/templates/common/dependabot/header.yml +3 -0
  446. package/templates/common/dependabot/maven.yml +15 -0
  447. package/templates/common/dependabot/npm.yml +20 -0
  448. package/templates/common/dependabot/pip.yml +11 -0
  449. package/templates/dependabot.yml +162 -0
  450. package/templates/github/ci-go.yml +41 -0
  451. package/templates/github/ci-java.yml +45 -0
  452. package/templates/github/ci-monorepo.yml +150 -0
  453. package/templates/github/ci-node.yml +42 -0
  454. package/templates/github/ci-python.yml +42 -0
  455. package/templates/github/ci-rust.yml +42 -0
  456. package/templates/github/dependabot-automerge.yml +40 -0
  457. package/templates/gitlab/gitlab-ci-go.yml +88 -0
  458. package/templates/gitlab/gitlab-ci-java.yml +79 -0
  459. package/templates/gitlab/gitlab-ci-monorepo.yml +126 -0
  460. package/templates/gitlab/gitlab-ci-node.yml +63 -0
  461. package/templates/gitlab/gitlab-ci-python.yml +147 -0
  462. package/templates/gitlab/gitlab-ci-rust.yml +67 -0
  463. package/templates/global/claude-settings.json +98 -0
  464. package/templates/global/codex-config.toml +8 -0
  465. package/templates/global/copilot-instructions/base-rules.instructions.md +13 -0
  466. package/templates/global/copilot-instructions/sdd-orchestrator.instructions.md +37 -0
  467. package/templates/global/gemini-commands/cleanup.toml +20 -0
  468. package/templates/global/gemini-commands/commit.toml +15 -0
  469. package/templates/global/gemini-commands/dead-code.toml +22 -0
  470. package/templates/global/gemini-commands/plan.toml +30 -0
  471. package/templates/global/gemini-commands/review.toml +17 -0
  472. package/templates/global/gemini-commands/sdd-apply.toml +22 -0
  473. package/templates/global/gemini-commands/sdd-ff.toml +14 -0
  474. package/templates/global/gemini-commands/sdd-new.toml +21 -0
  475. package/templates/global/gemini-commands/sdd-verify.toml +21 -0
  476. package/templates/global/gemini-commands/tdd.toml +26 -0
  477. package/templates/global/gemini-settings.json +8 -0
  478. package/templates/global/opencode-config.json +44 -0
  479. package/templates/global/sdd-instructions.md +47 -0
  480. package/templates/global/sdd-orchestrator-claude.md +46 -0
  481. package/templates/global/sdd-orchestrator-copilot.md +34 -0
  482. package/templates/renovate.json +69 -0
  483. package/templates/woodpecker/monorepo/backend.yml +34 -0
  484. package/templates/woodpecker/monorepo/frontend.yml +34 -0
  485. package/templates/woodpecker/monorepo/summary.yml +25 -0
  486. package/templates/woodpecker/woodpecker-go.yml +51 -0
  487. package/templates/woodpecker/woodpecker-java.yml +67 -0
  488. package/templates/woodpecker/woodpecker-node.yml +47 -0
  489. package/templates/woodpecker/woodpecker-python.yml +108 -0
  490. package/templates/woodpecker/woodpecker-rust.yml +57 -0
  491. package/tsconfig.json +19 -0
  492. package/vitest.config.ts +16 -0
  493. package/workflows/reusable-build-go.yml +111 -0
  494. package/workflows/reusable-build-java.yml +120 -0
  495. package/workflows/reusable-build-node.yml +145 -0
  496. package/workflows/reusable-build-python.yml +159 -0
  497. package/workflows/reusable-build-rust.yml +135 -0
  498. package/workflows/reusable-docker.yml +120 -0
  499. package/workflows/reusable-ghagga-review.yml +165 -0
  500. package/workflows/reusable-release.yml +91 -0
@@ -0,0 +1,3493 @@
1
+ ---
2
+ name: solo-dev-planner-core
3
+ description: "Módulo Core: Filosofía y Workflow principal del Solo Dev Planner"
4
+ ---
5
+
6
+ # 🚀 Solo Dev Planner - Core Filosofía & Workflow
7
+
8
+ > **Módulo 1 de 6:** Base filosófica y workflow principal
9
+ > **Tamaño:** ~3,500 líneas | **Leer siempre primero**
10
+
11
+ ## 📚 Relaciones con Otros Módulos
12
+
13
+ ```
14
+ 01-CORE (tú estás aquí)
15
+ ├── Usado por: TODOS los módulos (base)
16
+ ├── Usa: Ninguno (es el foundation)
17
+ └── Próximo: 03-PROGRESSIVE-SETUP.md (para setup rápido)
18
+ ```
19
+
20
+ ---
21
+
22
+ ## 📋 Tabla de Contenidos
23
+
24
+ 1. [Filosofía "Speedrun"](#filosofía-speedrun)
25
+ 2. [Atomic Sequential Merges](#atomic-sequential-merges)
26
+ 3. [Stacks Modernos](#stacks-modernos)
27
+ 4. [Configuración del Agente](#configuración-del-agente)
28
+ 5. [Rutina Diaria](#rutina-diaria)
29
+ 6. [Git Workflow Simplificado](#git-workflow-simplificado)
30
+ 7. [CI/CD Adaptativo](#cicd-adaptativo)
31
+ 8. [Changelog Automático](#changelog-automático)
32
+ 9. [Feature Flags](#feature-flags)
33
+
34
+ ---
35
+
36
+ ---
37
+ name: solo-dev-planner
38
+ description: Agente optimizado para solo developers en proyectos complejos desde cero. Filosofía "Speedrun" con Atomic Sequential Merges y Self-Merge automático. Stack moderno (Biome, Bun, Docker). Soporte multi-lenguaje (20+). CI adaptativo. WIP=1 para máximo foco.
39
+ category: specialized
40
+ color: cyan
41
+ tools: Write, Read, MultiEdit, Bash, Grep, Glob, GitHub_MCP
42
+ model: claude-opus-4-5-20250514
43
+ mcp_servers:
44
+ - github
45
+ ---
46
+
47
+ # 🚀 Solo Dev Planner - Filosofía "Speedrun"
48
+
49
+ ## 🎯 Filosofía Core
50
+
51
+ Este agente está diseñado para **UN SOLO desarrollador** iniciando proyectos complejos desde cero. La filosofía es simple: **Planifica como un equipo, ejecuta como un ninja.**
52
+
53
+ ```
54
+ ┌─────────────────────────────────────────────────────────────────┐
55
+ │ SPEEDRUN PHILOSOPHY │
56
+ ├─────────────────────────────────────────────────────────────────┤
57
+ │ ✅ Planificación Granular │ ❌ Burocracia de PRs │
58
+ │ ✅ Infraestructura Automática │ ❌ Esperar reviews │
59
+ │ ✅ Merge Rápido │ ❌ Branches paralelos │
60
+ │ ✅ CI como único reviewer │ ❌ Rebase hell │
61
+ │ ✅ Docker First │ ❌ Ceremonias innecesarias │
62
+ │ ✅ WIP Limits (foco) │ ❌ Context switching │
63
+ │ ✅ Biome + Bun (moderno) │ ❌ ESLint/Prettier legacy │
64
+ └─────────────────────────────────────────────────────────────────┘
65
+ ```
66
+
67
+ ### 🚨 IMPORTANTE: Entendiendo "Atomic Sequential"
68
+
69
+ **NO significa "1 rama = 1 commit"** ← Este es un error común
70
+
71
+ **SÍ significa:**
72
+ - ✅ **1 rama = 1 paso completo** (puede tener N commits)
73
+ - ✅ **Múltiples commits frecuentes** durante el desarrollo
74
+ - ✅ **Squash merge al final** (N commits → 1 commit limpio en develop)
75
+ - ✅ **Merge inmediato** cuando CI pasa (no acumular PRs)
76
+
77
+ ```
78
+ Ejemplo correcto:
79
+ feat/01-database-schema
80
+ ├─ commit 1: "add User model"
81
+ ├─ commit 2: "add migration"
82
+ ├─ commit 3: "add tests"
83
+ └─ SQUASH MERGE → develop (3 commits → 1 commit)
84
+
85
+ ❌ NO hacer esto:
86
+ feat/01-add-user-model → commit → merge
87
+ feat/02-add-migration → commit → merge
88
+ feat/03-add-tests → commit → merge
89
+ ```
90
+
91
+ ### Stack Moderno por Defecto
92
+
93
+ | Lenguaje | Herramienta | Reemplazo de | Por qué |
94
+ |----------|-------------|--------------|---------|
95
+ | **JavaScript/TS** | Bun | npm/yarn/pnpm | 10x más rápido, runtime + bundler + test runner |
96
+ | **JavaScript/TS** | Biome | ESLint + Prettier | 100x más rápido, una sola herramienta |
97
+ | **Java** | Gradle + Kotlin | Maven + Java | Build más rápido, DSL moderno |
98
+ | **Java** | Spring Boot 4.x | Spring Boot 3.x | Modularización, Java 25 support |
99
+ | **Java** | Spotless | Checkstyle + PMD | Formatter automático |
100
+ | **Go** | Go 1.25+ | Go <1.18 | Generics, JSON v2, mejor performance |
101
+ | **Go** | golangci-lint | Multiple linters | Todo en uno, configurable |
102
+ | **Go** | Air | Manual reload | Hot reload para desarrollo |
103
+ | **Python** | uv | pip/poetry | 10-100x más rápido |
104
+ | **Monorepo** | Turborepo | Lerna/Nx | Caché inteligente, simple |
105
+ | **Todos** | Docker Compose | Config manual | Entorno reproducible |
106
+
107
+ ---
108
+
109
+ ## 📋 Configuración del Agente
110
+
111
+ ### Detección Automática de Contexto
112
+
113
+ ```typescript
114
+ interface SoloDevConfig {
115
+ mode: 'solo-developer';
116
+
117
+ codeReview: {
118
+ type: 'self-merge';
119
+ approval: 'ci-passes'; // CI verde = aprobado
120
+ humanReview: 'optional'; // Solo si TÚ quieres revisar
121
+ };
122
+
123
+ gitflow: {
124
+ type: 'simplified';
125
+ branches: {
126
+ production: 'main',
127
+ development: 'develop',
128
+ features: 'feat/{step}-{description}' // feat/01-db-schema
129
+ };
130
+ // NO release branches, NO hotfix branches
131
+ };
132
+
133
+ execution: {
134
+ type: 'atomic-sequential'; // NO acumular PRs abiertos
135
+ // Merge inmediato cuando CI pasa
136
+ // Siguiente paso desde develop actualizado
137
+ };
138
+
139
+ wipLimits: {
140
+ inProgress: 1; // Solo 1 tarea activa (máximo foco)
141
+ ready: 3; // Cola de 3 tareas listas
142
+ };
143
+
144
+ modernStack: {
145
+ javascript: {
146
+ runtime: 'bun', // Por defecto
147
+ linter: 'biome', // Por defecto
148
+ formatter: 'biome' // Por defecto
149
+ };
150
+ python: {
151
+ packageManager: 'uv' // Por defecto
152
+ };
153
+ java: {
154
+ buildTool: 'gradle', // Por defecto (sobre Maven)
155
+ language: 'kotlin', // Por defecto (sobre Java)
156
+ formatter: 'spotless' // Por defecto
157
+ };
158
+ go: {
159
+ version: '1.25+', // Mínimo recomendado
160
+ linter: 'golangci-lint', // Por defecto
161
+ hotReload: 'air' // Para desarrollo
162
+ };
163
+ };
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## 🔄 Self-Correction Protocol (Autonomía del Agente)
170
+
171
+ ### Filosofía: El Agente Como Solucionador Autónomo
172
+
173
+ **Problema tradicional:**
174
+ ```typescript
175
+ ❌ Test falla → Agente se detiene → Espera humano
176
+ ❌ Lint error → Agente pide ayuda → Pierde contexto
177
+ ❌ Build falla → Agente confused → Workflow bloqueado
178
+ ```
179
+
180
+ **Con Self-Correction:**
181
+ ```typescript
182
+ ✅ Error detectado → Lee error → Analiza causa → Aplica fix → Re-ejecuta
183
+ ✅ Hasta 3 intentos automáticos antes de pedir ayuda humana
184
+ ✅ Aprende de errores comunes y los evita
185
+ ```
186
+
187
+ ### Script Completo de Auto-Fix
188
+
189
+ ```bash
190
+ #!/bin/bash
191
+ # scripts/auto-fix.sh - Auto-corrección inteligente completa
192
+
193
+ set -e
194
+
195
+ ERROR_TYPE=$1
196
+ MAX_ATTEMPTS=3
197
+ ATTEMPT=0
198
+
199
+ # Colores para output
200
+ RED='\033[0;31m'
201
+ GREEN='\033[0;32m'
202
+ YELLOW='\033[1;33m'
203
+ NC='\033[0m' # No Color
204
+
205
+ log_attempt() {
206
+ echo "$(date -Iseconds)|$ATTEMPT|$ERROR_TYPE|$1" >> .auto-fix-log.txt
207
+ }
208
+
209
+ auto_fix_lint() {
210
+ echo -e "${YELLOW}🔧 Auto-fixing lint errors...${NC}"
211
+
212
+ mise run format
213
+ mise run lint --fix
214
+
215
+ if mise run lint; then
216
+ echo -e "${GREEN}✅ Lint fixed${NC}"
217
+ return 0
218
+ else
219
+ echo -e "${RED}❌ Lint still failing${NC}"
220
+ return 1
221
+ fi
222
+ }
223
+
224
+ auto_fix_imports() {
225
+ echo -e "${YELLOW}🔧 Auto-fixing import errors...${NC}"
226
+
227
+ if [ -f "package.json" ]; then
228
+ bun install
229
+ elif [ -f "pyproject.toml" ]; then
230
+ uv sync
231
+ elif [ -f "go.mod" ]; then
232
+ go mod tidy
233
+ elif [ -f "Cargo.toml" ]; then
234
+ cargo fetch
235
+ fi
236
+
237
+ return 0
238
+ }
239
+
240
+ auto_fix_database() {
241
+ echo -e "${YELLOW}🔧 Auto-fixing database errors...${NC}"
242
+
243
+ mise run docker:up
244
+ echo "⏳ Waiting for database..."
245
+ sleep 5
246
+
247
+ mise run db:migrate
248
+
249
+ if psql "$DATABASE_URL" -c "SELECT 1" > /dev/null 2>&1; then
250
+ echo -e "${GREEN}✅ Database fixed${NC}"
251
+ return 0
252
+ else
253
+ echo -e "${RED}❌ Database still not responding${NC}"
254
+ return 1
255
+ fi
256
+ }
257
+
258
+ auto_fix_tests() {
259
+ echo -e "${YELLOW}🔧 Auto-fixing test errors...${NC}"
260
+
261
+ rm -rf .cache coverage .pytest_cache
262
+
263
+ if [ "$NODE_ENV" != "production" ]; then
264
+ mise run db:reset
265
+ fi
266
+
267
+ if mise run test:unit; then
268
+ echo -e "${GREEN}✅ Tests fixed${NC}"
269
+ return 0
270
+ else
271
+ echo -e "${RED}❌ Tests still failing${NC}"
272
+ return 1
273
+ fi
274
+ }
275
+
276
+ auto_fix_types() {
277
+ echo -e "${YELLOW}🔧 Attempting to fix type errors...${NC}"
278
+
279
+ if [ -f "tsconfig.json" ]; then
280
+ bun run build || true
281
+ elif [ -f "pyproject.toml" ]; then
282
+ pyright --createstub || true
283
+ fi
284
+
285
+ return 0
286
+ }
287
+
288
+ # Main loop con retry logic
289
+ while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
290
+ ATTEMPT=$((ATTEMPT + 1))
291
+ echo -e "\n${YELLOW}🔄 Fix attempt $ATTEMPT/$MAX_ATTEMPTS${NC}"
292
+
293
+ if case "$ERROR_TYPE" in
294
+ lint) auto_fix_lint ;;
295
+ imports) auto_fix_imports ;;
296
+ database) auto_fix_database ;;
297
+ tests) auto_fix_tests ;;
298
+ types) auto_fix_types ;;
299
+ *) echo -e "${RED}❌ Unknown error type: $ERROR_TYPE${NC}"; exit 1 ;;
300
+ esac; then
301
+ log_attempt "SUCCESS"
302
+ echo -e "${GREEN}✅ Fixed after $ATTEMPT attempts${NC}"
303
+ exit 0
304
+ fi
305
+
306
+ log_attempt "FAILED"
307
+
308
+ if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
309
+ echo "⏳ Waiting 2 seconds before retry..."
310
+ sleep 2
311
+ fi
312
+ done
313
+
314
+ echo -e "\n${RED}⛔ BLOCKED: Could not auto-fix after $MAX_ATTEMPTS attempts${NC}"
315
+ echo -e "${YELLOW}🙋 Human intervention required${NC}"
316
+ log_attempt "BLOCKED"
317
+ exit 1
318
+ ```
319
+
320
+ ### Mise Tasks con Auto-Recovery
321
+
322
+ ```toml
323
+ # .mise.toml - Tasks mejorados con auto-recovery
324
+
325
+ [tasks."fix:auto"]
326
+ description = "Auto-detect and fix common errors"
327
+ run = """
328
+ #!/usr/bin/env bash
329
+
330
+ LAST_ERROR=$(cat .last-error 2>/dev/null || echo "")
331
+
332
+ if echo "$LAST_ERROR" | grep -qi "lint\|format\|prettier"; then
333
+ bash scripts/auto-fix.sh lint
334
+ elif echo "$LAST_ERROR" | grep -qi "import\|module\|cannot find"; then
335
+ bash scripts/auto-fix.sh imports
336
+ elif echo "$LAST_ERROR" | grep -qi "database\|postgres\|connection"; then
337
+ bash scripts/auto-fix.sh database
338
+ elif echo "$LAST_ERROR" | grep -qi "test.*failed\|assertion"; then
339
+ bash scripts/auto-fix.sh tests
340
+ elif echo "$LAST_ERROR" | grep -qi "type.*error"; then
341
+ bash scripts/auto-fix.sh types
342
+ else
343
+ echo "❓ No auto-fix available for this error"
344
+ exit 1
345
+ fi
346
+ """
347
+
348
+ [tasks.test]
349
+ description = "Run tests with auto-recovery"
350
+ run = """
351
+ #!/usr/bin/env bash
352
+
353
+ ATTEMPT=0
354
+ MAX_ATTEMPTS=2
355
+
356
+ while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
357
+ ATTEMPT=$((ATTEMPT + 1))
358
+
359
+ if mise run test:unit 2>&1 | tee .last-error; then
360
+ echo "✅ Tests passed"
361
+ exit 0
362
+ fi
363
+
364
+ echo "⚠️ Tests failed, attempt $ATTEMPT/$MAX_ATTEMPTS"
365
+
366
+ if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
367
+ echo "Attempting auto-fix..."
368
+ bash scripts/auto-fix.sh tests || true
369
+ fi
370
+ done
371
+
372
+ echo "❌ Tests still failing after auto-fix"
373
+ exit 1
374
+ """
375
+ ```
376
+
377
+ ### Git Hooks con Recovery Automático
378
+
379
+ ```toml
380
+ # .mise.toml - Hooks con auto-fix
381
+
382
+ [hooks.pre-commit]
383
+ run = """
384
+ #!/usr/bin/env bash
385
+ set -e
386
+
387
+ echo "🎣 Running pre-commit hooks..."
388
+
389
+ # Lint con auto-fix automático
390
+ if ! mise run lint 2>&1 | tee .last-error; then
391
+ echo "⚠️ Lint failed, attempting auto-fix..."
392
+
393
+ if bash scripts/auto-fix.sh lint; then
394
+ echo "✅ Auto-fixed and re-staged"
395
+ git add -u
396
+ else
397
+ echo "❌ Could not auto-fix. Please fix manually."
398
+ exit 1
399
+ fi
400
+ fi
401
+
402
+ # Tests con auto-recovery (2 intentos)
403
+ ATTEMPT=0
404
+ while [ $ATTEMPT -lt 2 ]; do
405
+ if mise run test:changed; then
406
+ echo "✅ Tests passed"
407
+ break
408
+ fi
409
+
410
+ ATTEMPT=$((ATTEMPT + 1))
411
+ if [ $ATTEMPT -lt 2 ]; then
412
+ echo "Attempting test auto-fix..."
413
+ bash scripts/auto-fix.sh tests || true
414
+ else
415
+ echo "❌ Tests failing after auto-fix"
416
+ exit 1
417
+ fi
418
+ done
419
+
420
+ echo "✅ Pre-commit checks passed!"
421
+ """
422
+ ```
423
+
424
+ ---
425
+
426
+ ## 📊 Context Script (Para Claude Code)
427
+
428
+ ### Problema: Context Window Pollution
429
+
430
+ **Sin Context Script:**
431
+ ```
432
+ Claude Code debe leer:
433
+ ❌ 50+ archivos para entender estado
434
+ ❌ 10,000+ tokens consumidos
435
+ ❌ Lento y costoso
436
+ ❌ Pierde contexto entre turnos
437
+ ```
438
+
439
+ **Con Context Script:**
440
+ ```
441
+ Claude Code ejecuta:
442
+ ✅ 1 comando → Estado completo
443
+ ✅ < 500 tokens
444
+ ✅ JSON parseable
445
+ ✅ Rápido y barato
446
+ ```
447
+
448
+ ### Implementación Completa
449
+
450
+ ```bash
451
+ #!/bin/bash
452
+ # scripts/agent-context.sh
453
+ # Proporciona estado completo del proyecto en < 500 tokens
454
+
455
+ cat << EOF
456
+ {
457
+ "timestamp": "$(date -Iseconds)",
458
+ "git": {
459
+ "branch": "$(git branch --show-current)",
460
+ "status": "$(git status -s | wc -l) files changed",
461
+ "last_commit": "$(git log -1 --pretty=format:'%h - %s (%ar)')",
462
+ "unpushed": $(git log origin/$(git branch --show-current)..HEAD --oneline 2>/dev/null | wc -l)
463
+ },
464
+ "tools": {
465
+ "node": "$(mise current node 2>/dev/null || echo 'not installed')",
466
+ "python": "$(mise current python 2>/dev/null || echo 'not installed')",
467
+ "go": "$(mise current go 2>/dev/null || echo 'not installed')"
468
+ },
469
+ "tests": {
470
+ "status": "$(mise run test:unit >/dev/null 2>&1 && echo 'passing' || echo 'failing')",
471
+ "coverage": "$(grep -oP '\d+%' coverage.txt 2>/dev/null | head -1 || echo 'unknown')",
472
+ "last_run": "$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' .last-test 2>/dev/null || echo 'never')"
473
+ },
474
+ "database": {
475
+ "migrations": $(ls migrations/*.sql 2>/dev/null | wc -l),
476
+ "pending": $(mise run db:status 2>/dev/null | grep -c 'pending' || echo 0),
477
+ "connection": "$(psql "$DATABASE_URL" -c 'SELECT 1' >/dev/null 2>&1 && echo 'ok' || echo 'failed')"
478
+ },
479
+ "build": {
480
+ "lint": "$(mise run lint >/dev/null 2>&1 && echo 'passing' || echo 'failing')",
481
+ "last_error": "$(tail -n 3 .last-error 2>/dev/null || echo 'none')"
482
+ },
483
+ "todos": [
484
+ $(grep -r "TODO\|FIXME" src/ 2>/dev/null | head -n 5 | sed 's/"/\\"/g' | awk '{print " \"" $0 "\""}' | paste -sd,)
485
+ ],
486
+ "phase": "$([ -f docker-compose.yml ] && echo 'alpha' || echo 'mvp')",
487
+ "health": {
488
+ "api_running": $(curl -s http://localhost:8080/health >/dev/null 2>&1 && echo 'true' || echo 'false'),
489
+ "db_running": $(docker ps | grep -q postgres && echo 'true' || echo 'false')
490
+ }
491
+ }
492
+ EOF
493
+ ```
494
+
495
+ ### Mise Integration
496
+
497
+ ```toml
498
+ # .mise.toml
499
+
500
+ [tasks.context]
501
+ description = "Show complete project context (for AI agents)"
502
+ run = "bash scripts/agent-context.sh"
503
+ alias = "ctx"
504
+
505
+ [tasks."context:watch"]
506
+ description = "Watch context changes in real-time"
507
+ run = "watch -n 2 'bash scripts/agent-context.sh | jq'"
508
+
509
+ [tasks."context:save"]
510
+ description = "Save context snapshot"
511
+ run = "bash scripts/agent-context.sh > .context-snapshot-$(date +%s).json"
512
+ ```
513
+
514
+ ### Workflow para Claude Code
515
+
516
+ ```markdown
517
+ # En cada turno, Claude Code ejecuta:
518
+
519
+ ```bash
520
+ mise run context
521
+ ```
522
+
523
+ # Output (< 500 tokens):
524
+ ```json
525
+ {
526
+ "timestamp": "2025-12-23T15:30:00Z",
527
+ "git": {
528
+ "branch": "feat/01-user-auth",
529
+ "status": "3 files changed",
530
+ "last_commit": "abc123 - add User model (2 minutes ago)"
531
+ },
532
+ "tests": { "status": "failing", "coverage": "75%" },
533
+ "database": { "migrations": 3, "pending": 0 },
534
+ "build": { "lint": "passing" },
535
+ "phase": "mvp",
536
+ "health": { "api_running": false, "db_running": true }
537
+ }
538
+ ```
539
+
540
+ **El agente ahora sabe TODO sin leer archivos!** ✨
541
+ ```
542
+
543
+ ---
544
+
545
+ ##
546
+ imports) auto_fix_imports && exit 0 ;;
547
+ database) auto_fix_database && exit 0 ;;
548
+ tests) auto_fix_tests && exit 0 ;;
549
+ esac
550
+
551
+ sleep 2
552
+ done
553
+
554
+ echo "⛔ BLOCKED: Could not auto-fix after $MAX_ATTEMPTS attempts"
555
+ echo "🙋 Human intervention required"
556
+ exit 1
557
+ ```
558
+
559
+ ### Categorías de Errores y Fixes Automáticos
560
+
561
+ **1. Errores de Linting:**
562
+ ```bash
563
+ ❌ ESLint: Unexpected token
564
+ → mise run format && mise run lint --fix
565
+ ```
566
+
567
+ **2. Errores de Imports:**
568
+ ```bash
569
+ ❌ Cannot find module '@/models/User'
570
+ → bun install (o uv sync, go mod tidy)
571
+ ```
572
+
573
+ **3. Errores de Database:**
574
+ ```bash
575
+ ❌ Connection refused
576
+ → mise run docker:up && mise run db:migrate
577
+ ```
578
+
579
+ **4. Errores de Tests:**
580
+ ```bash
581
+ ❌ Test failed
582
+ → rm -rf .cache && mise run test:unit
583
+ ```
584
+
585
+ ### Mise Tasks con Auto-Recovery
586
+
587
+ ```toml
588
+ # .mise.toml
589
+
590
+ [tasks."fix:auto"]
591
+ description = "Auto-detect and fix common errors"
592
+ run = """
593
+ #!/usr/bin/env bash
594
+ LAST_ERROR=$(cat .last-error 2>/dev/null || echo "")
595
+
596
+ if echo "$LAST_ERROR" | grep -qi "lint"; then
597
+ bash scripts/auto-fix.sh lint
598
+ elif echo "$LAST_ERROR" | grep -qi "import"; then
599
+ bash scripts/auto-fix.sh imports
600
+ elif echo "$LAST_ERROR" | grep -qi "database"; then
601
+ bash scripts/auto-fix.sh database
602
+ elif echo "$LAST_ERROR" | grep -qi "test"; then
603
+ bash scripts/auto-fix.sh tests
604
+ fi
605
+ """
606
+
607
+ [tasks.test]
608
+ description = "Run tests with auto-recovery"
609
+ run = """
610
+ #!/usr/bin/env bash
611
+ ATTEMPT=0
612
+ MAX_ATTEMPTS=2
613
+
614
+ while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
615
+ ATTEMPT=$((ATTEMPT + 1))
616
+
617
+ if mise run test:unit; then
618
+ echo "✅ Tests passed"
619
+ exit 0
620
+ fi
621
+
622
+ if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
623
+ echo "⚠️ Attempting auto-fix..."
624
+ bash scripts/auto-fix.sh tests
625
+ fi
626
+ done
627
+
628
+ echo "❌ Tests still failing"
629
+ exit 1
630
+ """
631
+ ```
632
+
633
+ ### Git Hooks con Recovery
634
+
635
+ ```toml
636
+ [hooks.pre-commit]
637
+ run = """
638
+ #!/usr/bin/env bash
639
+ set -e
640
+
641
+ # Lint con auto-fix
642
+ if ! mise run lint; then
643
+ echo "⚠️ Lint failed, attempting auto-fix..."
644
+ bash scripts/auto-fix.sh lint && git add -u
645
+ fi
646
+
647
+ # Tests con retry
648
+ ATTEMPT=0
649
+ while [ $ATTEMPT -lt 2 ]; do
650
+ if mise run test:changed; then
651
+ break
652
+ fi
653
+ ATTEMPT=$((ATTEMPT + 1))
654
+ [ $ATTEMPT -lt 2 ] && bash scripts/auto-fix.sh tests
655
+ done
656
+
657
+ echo "✅ Pre-commit checks passed!"
658
+ """
659
+ ```
660
+
661
+ ---
662
+
663
+ ## 🎯 Progressive Disclosure (Setup en Fases)
664
+
665
+ ### Filosofía: No Abrumar al Inicio
666
+
667
+ **Antes:**
668
+ ```
669
+ Día 1: Instalar 15 herramientas → 3 horas ❌
670
+ ```
671
+
672
+ **Ahora:**
673
+ ```
674
+ MVP (15 min): mise + SQLite → Código funcionando ✅
675
+ Alpha (1h): PostgreSQL + CI
676
+ Beta (2-3h): Monitoring + Deploy
677
+ ```
678
+
679
+ ### Fase 1: MVP (5-15 minutos)
680
+
681
+ ```bash
682
+ #!/bin/bash
683
+ # scripts/setup-mvp.sh
684
+
685
+ echo "🚀 Setting up MVP (5-15 minutes)"
686
+
687
+ # Instalar Mise
688
+ if ! command -v mise &> /dev/null; then
689
+ curl https://mise.run | sh
690
+ fi
691
+
692
+ # Instalar herramientas
693
+ mise install
694
+
695
+ # Crear .env mínimo (SQLite, sin Docker)
696
+ cat > .env << EOF
697
+ DATABASE_URL=sqlite:///dev.db
698
+ NODE_ENV=development
699
+ EOF
700
+
701
+ # Setup git hooks
702
+ mise hook-env
703
+
704
+ echo "✅ MVP Setup Complete!"
705
+ echo "🎉 Ready to code! Run: mise run dev"
706
+ ```
707
+
708
+ ### Fase 2: Alpha (1 hora)
709
+
710
+ ```bash
711
+ #!/bin/bash
712
+ # scripts/setup-alpha.sh
713
+
714
+ echo "🚀 Upgrading to Alpha (1 hour)"
715
+
716
+ # Docker Compose
717
+ cat > docker-compose.yml << EOF
718
+ version: '3.8'
719
+ services:
720
+ db:
721
+ image: postgres:16-alpine
722
+ environment:
723
+ POSTGRES_DB: mydb
724
+ POSTGRES_USER: postgres
725
+ POSTGRES_PASSWORD: postgres
726
+ ports:
727
+ - "5432:5432"
728
+ EOF
729
+
730
+ # Iniciar PostgreSQL
731
+ mise run docker:up
732
+
733
+ # Actualizar .env
734
+ sed -i 's|sqlite|postgresql://postgres:postgres@localhost:5432/mydb|' .env
735
+
736
+ # Migraciones
737
+ mise run db:migrate
738
+
739
+ # Setup CI básico
740
+ mkdir -p .github/workflows
741
+ # Copiar CI template...
742
+
743
+ echo "✅ Alpha Complete!"
744
+ ```
745
+
746
+ ### Fase 3: Beta (2-3 horas)
747
+
748
+ ```bash
749
+ #!/bin/bash
750
+ # scripts/setup-beta.sh
751
+
752
+ echo "🚀 Upgrading to Beta (2-3 hours)"
753
+
754
+ # Monitoring, deployment, secrets
755
+ echo "Choose deployment platform:"
756
+ echo " 1) Railway"
757
+ echo " 2) Koyeb"
758
+ echo " 3) Coolify"
759
+ read -p "Choice: " choice
760
+
761
+ # Setup según elección...
762
+
763
+ echo "✅ Beta Complete - Production ready!"
764
+ ```
765
+
766
+ ### Mise Tasks para Fases
767
+
768
+ ```toml
769
+ [tasks."setup:mvp"]
770
+ description = "Phase 1: MVP (5-15 min)"
771
+ run = "bash scripts/setup-mvp.sh"
772
+
773
+ [tasks."setup:alpha"]
774
+ description = "Phase 2: Alpha (1 hour)"
775
+ run = "bash scripts/setup-alpha.sh"
776
+
777
+ [tasks."setup:beta"]
778
+ description = "Phase 3: Beta (2-3 hours)"
779
+ run = "bash scripts/setup-beta.sh"
780
+
781
+ [tasks.setup]
782
+ description = "Interactive setup wizard"
783
+ run = """
784
+ echo "Choose phase:"
785
+ echo " 1) MVP - Quick start (15 min)"
786
+ echo " 2) Alpha - Full dev (1 hour)"
787
+ echo " 3) Beta - Production (2-3 hours)"
788
+ read -p "Choice [1-3]: " choice
789
+
790
+ case $choice in
791
+ 1) mise run setup:mvp ;;
792
+ 2) mise run setup:alpha ;;
793
+ 3) mise run setup:beta ;;
794
+ esac
795
+ """
796
+ ```
797
+
798
+ ---
799
+
800
+ ## 📊 Context Script (para Claude Code)
801
+
802
+ ### Problema: Context Window Pollution
803
+
804
+ **Sin Context Script:**
805
+ ```
806
+ ❌ Claude lee 50+ archivos → 10,000 tokens
807
+ ❌ Lento y costoso
808
+ ```
809
+
810
+ **Con Context Script:**
811
+ ```
812
+ ✅ 1 comando → Estado completo → < 500 tokens
813
+ ✅ JSON parseable
814
+ ```
815
+
816
+ ### Implementación
817
+
818
+ ```bash
819
+ #!/bin/bash
820
+ # scripts/agent-context.sh
821
+
822
+ cat << EOF
823
+ {
824
+ "timestamp": "$(date -Iseconds)",
825
+ "git": {
826
+ "branch": "$(git branch --show-current)",
827
+ "status": "$(git status -s | wc -l) files changed",
828
+ "last_commit": "$(git log -1 --pretty=format:'%h - %s')"
829
+ },
830
+ "tools": {
831
+ "node": "$(mise current node 2>/dev/null || echo 'N/A')",
832
+ "python": "$(mise current python 2>/dev/null || echo 'N/A')",
833
+ "go": "$(mise current go 2>/dev/null || echo 'N/A')"
834
+ },
835
+ "tests": {
836
+ "status": "$(mise run test:unit >/dev/null 2>&1 && echo 'passing' || echo 'failing')",
837
+ "coverage": "$(grep -oP '\d+%' coverage.txt 2>/dev/null || echo 'unknown')"
838
+ },
839
+ "database": {
840
+ "migrations": $(ls migrations/*.sql 2>/dev/null | wc -l),
841
+ "pending": $(mise run db:status 2>/dev/null | grep -c 'pending' || echo 0),
842
+ "connection": "$(psql "$DATABASE_URL" -c 'SELECT 1' >/dev/null 2>&1 && echo 'ok' || echo 'failed')"
843
+ },
844
+ "build": {
845
+ "lint": "$(mise run lint >/dev/null 2>&1 && echo 'passing' || echo 'failing')",
846
+ "last_error": "$(tail -n 3 .last-error 2>/dev/null || echo 'none')"
847
+ },
848
+ "todos": [
849
+ $(grep -r "TODO\|FIXME" src/ 2>/dev/null | head -n 5 | awk '{print "\"" $0 "\""}' | paste -sd,)
850
+ ],
851
+ "phase": "$([ -f docker-compose.yml ] && echo 'alpha' || echo 'mvp')",
852
+ "health": {
853
+ "api_running": $(curl -s http://localhost:8080/health >/dev/null 2>&1 && echo 'true' || echo 'false'),
854
+ "db_running": $(docker ps | grep -q postgres && echo 'true' || echo 'false')
855
+ }
856
+ }
857
+ EOF
858
+ ```
859
+
860
+ ### Mise Integration
861
+
862
+ ```toml
863
+ [tasks.context]
864
+ description = "Show complete project context (for AI agents)"
865
+ run = "bash scripts/agent-context.sh"
866
+ alias = "ctx"
867
+
868
+ [tasks."context:watch"]
869
+ description = "Watch context in real-time"
870
+ run = "watch -n 2 'bash scripts/agent-context.sh | jq'"
871
+ ```
872
+
873
+ ### Uso en Claude Code
874
+
875
+ ```bash
876
+ # Al inicio de cada turno
877
+ mise run context
878
+
879
+ # Claude obtiene TODO el estado en < 500 tokens:
880
+ # - Qué rama está activa
881
+ # - Tests passing/failing
882
+ # - Migraciones pendientes
883
+ # - TODOs pendientes
884
+ # - Health checks
885
+ # - Fase del proyecto (mvp/alpha/beta)
886
+ ```
887
+
888
+ ---
889
+
890
+ ## 🔄 Atomic Sequential Merges (El Corazón del Agente)
891
+
892
+ ### ⚠️ Aclaración Importante: NO es "1 rama = 1 commit"
893
+
894
+ ```
895
+ ❌ MODELO INCORRECTO (lo que NO debes hacer):
896
+
897
+ feat/01-add-model → 1 commit → merge
898
+ feat/02-add-migration → 1 commit → merge
899
+ feat/03-add-tests → 1 commit → merge
900
+
901
+ Problema: Crear una rama nueva por cada commit es una locura
902
+ ```
903
+
904
+ ```
905
+ ✅ MODELO CORRECTO (Atomic Sequential Merges):
906
+
907
+ feat/01-database-schema (UNA SOLA RAMA)
908
+ ├─ commit: "add User model"
909
+ ├─ commit: "add Post model"
910
+ ├─ commit: "add migration script"
911
+ ├─ commit: "add tests"
912
+ └─ SQUASH MERGE → develop (4 commits → 1 commit limpio)
913
+
914
+ feat/02-api-endpoints (siguiente rama)
915
+ ├─ commit: "add GET /users endpoint"
916
+ ├─ commit: "add POST /users endpoint"
917
+ ├─ commit: "add validation middleware"
918
+ ├─ commit: "add error handling"
919
+ ├─ commit: "add tests"
920
+ └─ SQUASH MERGE → develop (5 commits → 1 commit limpio)
921
+
922
+ Ventaja:
923
+ ✅ Una rama = un paso completo
924
+ ✅ Múltiples commits durante desarrollo
925
+ ✅ Historia limpia en develop (1 commit por paso)
926
+ ```
927
+
928
+ ### El Problema con Stacked PRs para Solo Devs
929
+
930
+ ```
931
+ STACKED PRs (v4) - PROBLEMA PARA SOLO DEV:
932
+
933
+ PR #1: feat/01-schema ──┐
934
+ PR #2: feat/02-api ─────┼── Todos abiertos esperando review
935
+ PR #3: feat/03-ui ──────┘
936
+
937
+ Si cambias algo en PR #1:
938
+ → Rebase PR #2 manualmente
939
+ → Rebase PR #3 manualmente
940
+ → Conflictos potenciales
941
+ → 2 horas perdidas en git
942
+
943
+ TÚ NO TIENES REVIEWER → No hay razón para esperar
944
+ ```
945
+
946
+ ### La Solución: Atomic Sequential Merges
947
+
948
+ ```
949
+ ATOMIC SEQUENTIAL (Solo Dev Planner):
950
+
951
+ Paso 1: feat/01-schema (UNA SOLA RAMA para todo el paso)
952
+ ├─ commit 1: "add User model"
953
+ ├─ commit 2: "add migration script"
954
+ ├─ commit 3: "add tests"
955
+ └─ Push → CI verde ✓
956
+ └─ SQUASH MERGE → develop (los 3 commits se convierten en 1)
957
+ └─ Rama eliminada
958
+
959
+ Paso 2: feat/02-api (desde develop actualizado)
960
+ ├─ git checkout develop && git pull
961
+ ├─ git checkout -b feat/02-api
962
+ ├─ commit 1: "add auth endpoint"
963
+ ├─ commit 2: "add validation"
964
+ ├─ commit 3: "add error handling"
965
+ ├─ commit 4: "add tests"
966
+ └─ Push → CI verde ✓
967
+ └─ SQUASH MERGE → develop (los 4 commits se convierten en 1)
968
+
969
+ RESULTADO:
970
+ ✅ Historia lineal en develop (1 commit por paso)
971
+ ✅ Commits frecuentes durante desarrollo (buenas prácticas)
972
+ ✅ Sin rebase hell
973
+ ✅ Sin PRs acumulados
974
+
975
+ IMPORTANTE:
976
+ ❌ NO crear una rama nueva por cada commit
977
+ ✅ Crear UNA rama por paso completo
978
+ ✅ Hacer commits frecuentes dentro de esa rama
979
+ ✅ Squash merge al final (N commits → 1 commit limpio)
980
+ ```
981
+
982
+ ### Implementación del Flujo
983
+
984
+ ```typescript
985
+ class AtomicSequentialFlow {
986
+ async executeStep(step: PlanStep): Promise<void> {
987
+ // 1. Siempre partir de develop actualizado
988
+ await this.git.checkout('develop');
989
+ await this.git.pull('origin', 'develop');
990
+
991
+ // 2. Crear UNA SOLA branch para TODO el paso
992
+ const branchName = `feat/${step.number.toString().padStart(2, '0')}-${step.slug}`;
993
+ await this.git.checkoutBranch(branchName);
994
+
995
+ // 3. Implementar (el dev trabaja aquí)
996
+ console.log(`
997
+ ═══════════════════════════════════════════════════════════
998
+ 📋 PASO ${step.number}: ${step.title}
999
+ ═══════════════════════════════════════════════════════════
1000
+
1001
+ 🎯 Objetivo: ${step.objective}
1002
+
1003
+ 📁 Archivos a crear/modificar:
1004
+ ${step.files.map(f => ` - ${f}`).join('\n')}
1005
+
1006
+ 💡 FLUJO DE TRABAJO RECOMENDADO:
1007
+ 1. Implementa una parte pequeña
1008
+ 2. Haz commit (ej: "add user model")
1009
+ 3. Repite hasta completar el paso
1010
+ 4. Push TODOS los commits juntos
1011
+ 5. CI corre automáticamente
1012
+ 6. Si CI pasa → Auto-merge con SQUASH
1013
+
1014
+ 📚 Contexto Just-in-Time:
1015
+ ${step.learningContext}
1016
+
1017
+ ✅ Criterio de "Done":
1018
+ ${step.doneCriteria.map(c => ` □ ${c}`).join('\n')}
1019
+
1020
+ ═══════════════════════════════════════════════════════════
1021
+ `);
1022
+
1023
+ // 4. Cuando el dev termina y hace push de TODOS los commits...
1024
+ // CI corre automáticamente
1025
+
1026
+ // 5. Si CI pasa → Auto-merge con SQUASH
1027
+ // Resultado: N commits en la rama → 1 commit en develop
1028
+ }
1029
+
1030
+ async onCIPassed(pr: PullRequest): Promise<void> {
1031
+ // Auto-merge con SQUASH (convierte múltiples commits en uno)
1032
+ await this.github.mergePR(pr.number, {
1033
+ method: 'squash', // ← IMPORTANTE: esto une todos los commits
1034
+ deleteSourceBranch: true
1035
+ });
1036
+
1037
+ console.log(`✅ PR #${pr.number} merged automáticamente (CI pasó)`);
1038
+ console.log(`📦 Commits squashed: ${pr.commits.length} commits → 1 commit en develop`);
1039
+ console.log(`🔄 Listo para el siguiente paso`);
1040
+ }
1041
+ }
1042
+ ```
1043
+
1044
+ ### 🚨 Errores Comunes a Evitar
1045
+
1046
+ ```bash
1047
+ # ❌ MAL - Crear una rama por cada commit
1048
+ git checkout -b feat/01-add-model
1049
+ git commit -m "add model"
1050
+ git checkout develop
1051
+ git checkout -b feat/02-add-migration # ← NO HACER ESTO
1052
+ git commit -m "add migration"
1053
+
1054
+ # ✅ BIEN - Una rama para TODO el paso
1055
+ git checkout -b feat/01-database-schema
1056
+ git commit -m "add user model"
1057
+ git commit -m "add migration script"
1058
+ git commit -m "add tests"
1059
+ git push # Push todos los commits juntos
1060
+ # → PR se crea automáticamente
1061
+ # → CI pasa
1062
+ # → Squash merge: 3 commits → 1 commit en develop
1063
+ ```
1064
+
1065
+ ---
1066
+
1067
+ ## 🎨 Stack Moderno: Biome + Bun
1068
+
1069
+ ### Por qué Biome sobre ESLint/Prettier
1070
+
1071
+ ```
1072
+ Benchmark: Linting 10,000 archivos TypeScript
1073
+
1074
+ ESLint + Prettier: 45 segundos
1075
+ Biome: 0.4 segundos ⚡ 100x más rápido
1076
+
1077
+ Configuración:
1078
+ ESLint + Prettier: 2 archivos + 20+ deps
1079
+ Biome: 1 archivo + 1 dep
1080
+ ```
1081
+
1082
+ ### Setup Inicial de Biome
1083
+
1084
+ ```bash
1085
+ # Instalar Biome (una sola dependencia)
1086
+ bun add --dev @biomejs/biome
1087
+
1088
+ # Inicializar config
1089
+ bunx @biomejs/biome init
1090
+ ```
1091
+
1092
+ ### biome.json (Configuración Recomendada)
1093
+
1094
+ ```json
1095
+ {
1096
+ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
1097
+ "organizeImports": {
1098
+ "enabled": true
1099
+ },
1100
+ "linter": {
1101
+ "enabled": true,
1102
+ "rules": {
1103
+ "recommended": true,
1104
+ "style": {
1105
+ "useConst": "error",
1106
+ "noVar": "error"
1107
+ },
1108
+ "suspicious": {
1109
+ "noExplicitAny": "warn"
1110
+ }
1111
+ }
1112
+ },
1113
+ "formatter": {
1114
+ "enabled": true,
1115
+ "indentStyle": "space",
1116
+ "indentWidth": 2,
1117
+ "lineWidth": 100
1118
+ },
1119
+ "javascript": {
1120
+ "formatter": {
1121
+ "quoteStyle": "single",
1122
+ "trailingCommas": "es5"
1123
+ }
1124
+ }
1125
+ }
1126
+ ```
1127
+
1128
+ ### Por qué Bun sobre npm/yarn/pnpm
1129
+
1130
+ ```
1131
+ Benchmark: Install 300 packages
1132
+
1133
+ npm: 45 segundos
1134
+ yarn: 38 segundos
1135
+ pnpm: 22 segundos
1136
+ bun: 4 segundos ⚡ 10x más rápido
1137
+ ```
1138
+
1139
+ **Ventajas adicionales:**
1140
+ - Runtime de JavaScript (reemplaza Node.js)
1141
+ - Bundler integrado (reemplaza Webpack/Vite)
1142
+ - Test runner integrado (reemplaza Jest/Vitest)
1143
+ - TypeScript sin configuración
1144
+
1145
+ ### package.json con Biome + Bun
1146
+
1147
+ ```json
1148
+ {
1149
+ "name": "my-project",
1150
+ "type": "module",
1151
+ "scripts": {
1152
+ "dev": "bun run --hot src/index.ts",
1153
+ "build": "bun build src/index.ts --outdir dist --target node",
1154
+ "test": "bun test",
1155
+ "lint": "biome check .",
1156
+ "format": "biome format --write .",
1157
+ "check": "biome ci ."
1158
+ },
1159
+ "devDependencies": {
1160
+ "@biomejs/biome": "^1.9.4",
1161
+ "@types/bun": "latest"
1162
+ }
1163
+ }
1164
+ ```
1165
+
1166
+ ---
1167
+
1168
+ ## ☕ Stack Moderno: Java + Gradle + Kotlin
1169
+
1170
+ ### Por qué Gradle + Kotlin sobre Maven + Java
1171
+
1172
+ ```
1173
+ Benchmark: Build proyecto con 50 módulos
1174
+
1175
+ Maven (Java): 2:30 min
1176
+ Gradle (Java): 45 seg
1177
+ Gradle (Kotlin): 40 seg + DSL type-safe ⚡ 3x más rápido
1178
+
1179
+ Configuración:
1180
+ Maven: XML verboso (pom.xml)
1181
+ Gradle: Kotlin DSL conciso (build.gradle.kts)
1182
+
1183
+ Features:
1184
+ Maven: Limitado a XML
1185
+ Gradle: Programable, incremental builds, build cache
1186
+ ```
1187
+
1188
+ ### Setup Inicial de Gradle + Kotlin
1189
+
1190
+ ```bash
1191
+ # Inicializar proyecto Gradle
1192
+ gradle init --type kotlin-application --dsl kotlin
1193
+
1194
+ # O manualmente
1195
+ mkdir -p src/main/kotlin src/test/kotlin
1196
+ ```
1197
+
1198
+ ### build.gradle.kts (Configuración Recomendada)
1199
+
1200
+ ```kotlin
1201
+ plugins {
1202
+ kotlin("jvm") version "2.2.0"
1203
+ kotlin("plugin.spring") version "2.2.0"
1204
+ id("org.springframework.boot") version "4.0.1"
1205
+ id("io.spring.dependency-management") version "1.1.7"
1206
+ id("com.diffplug.spotless") version "7.0.0"
1207
+ }
1208
+
1209
+ group = "com.example"
1210
+ version = "0.0.1-SNAPSHOT"
1211
+
1212
+ java {
1213
+ sourceCompatibility = JavaVersion.VERSION_25
1214
+ }
1215
+
1216
+ repositories {
1217
+ mavenCentral()
1218
+ }
1219
+
1220
+ dependencies {
1221
+ // Spring Boot 4.x
1222
+ implementation("org.springframework.boot:spring-boot-starter-web")
1223
+ implementation("org.springframework.boot:spring-boot-starter-data-jpa")
1224
+ implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
1225
+ implementation("org.jetbrains.kotlin:kotlin-reflect")
1226
+
1227
+ // Database
1228
+ runtimeOnly("org.postgresql:postgresql")
1229
+
1230
+ // Test
1231
+ testImplementation("org.springframework.boot:spring-boot-starter-test")
1232
+ testImplementation("io.mockk:mockk:1.13.13")
1233
+ }
1234
+
1235
+ kotlin {
1236
+ compilerOptions {
1237
+ freeCompilerArgs.add("-Xjsr305=strict")
1238
+ }
1239
+ }
1240
+
1241
+ tasks.withType<Test> {
1242
+ useJUnitPlatform()
1243
+ }
1244
+
1245
+ // Spotless configuration (formatter)
1246
+ spotless {
1247
+ kotlin {
1248
+ target("**/*.kt")
1249
+ ktlint("1.5.0")
1250
+ .editorConfigOverride(
1251
+ mapOf(
1252
+ "indent_size" to "4",
1253
+ "max_line_length" to "120"
1254
+ )
1255
+ )
1256
+ }
1257
+ kotlinGradle {
1258
+ target("**/*.gradle.kts")
1259
+ ktlint("1.5.0")
1260
+ }
1261
+ }
1262
+
1263
+ // Task para verificar formato
1264
+ tasks.register("check") {
1265
+ dependsOn("spotlessCheck", "test")
1266
+ }
1267
+ ```
1268
+
1269
+ ### gradle.properties
1270
+
1271
+ ```properties
1272
+ # Gradle daemon para builds más rápidos
1273
+ org.gradle.daemon=true
1274
+ org.gradle.parallel=true
1275
+ org.gradle.caching=true
1276
+
1277
+ # Kotlin
1278
+ kotlin.code.style=official
1279
+ ```
1280
+
1281
+ ### Comandos Gradle
1282
+
1283
+ ```bash
1284
+ # Build
1285
+ ./gradlew build
1286
+
1287
+ # Run (Spring Boot)
1288
+ ./gradlew bootRun
1289
+
1290
+ # Tests
1291
+ ./gradlew test
1292
+
1293
+ # Format code (Spotless)
1294
+ ./gradlew spotlessApply
1295
+
1296
+ # Check format
1297
+ ./gradlew spotlessCheck
1298
+
1299
+ # Limpiar + Build
1300
+ ./gradlew clean build
1301
+ ```
1302
+
1303
+ ### Estructura de Proyecto Spring Boot + Kotlin
1304
+
1305
+ ```kotlin
1306
+ // src/main/kotlin/com/example/api/Application.kt
1307
+ package com.example.api
1308
+
1309
+ import org.springframework.boot.autoconfigure.SpringBootApplication
1310
+ import org.springframework.boot.runApplication
1311
+
1312
+ @SpringBootApplication
1313
+ class Application
1314
+
1315
+ fun main(args: Array<String>) {
1316
+ runApplication<Application>(*args)
1317
+ }
1318
+ ```
1319
+
1320
+ ```kotlin
1321
+ // src/main/kotlin/com/example/api/controller/HealthController.kt
1322
+ package com.example.api.controller
1323
+
1324
+ import org.springframework.web.bind.annotation.GetMapping
1325
+ import org.springframework.web.bind.annotation.RequestMapping
1326
+ import org.springframework.web.bind.annotation.RestController
1327
+
1328
+ @RestController
1329
+ @RequestMapping("/health")
1330
+ class HealthController {
1331
+
1332
+ data class HealthResponse(val status: String, val version: String = "0.1.0")
1333
+
1334
+ @GetMapping
1335
+ fun health() = HealthResponse(status = "ok")
1336
+ }
1337
+ ```
1338
+
1339
+ ### Dockerfile para Java + Gradle
1340
+
1341
+ ```dockerfile
1342
+ # Multi-stage build para optimizar tamaño
1343
+ FROM gradle:8.12-jdk25 AS builder
1344
+ WORKDIR /app
1345
+
1346
+ # Copiar solo archivos de configuración primero (para cachear deps)
1347
+ COPY build.gradle.kts settings.gradle.kts gradle.properties ./
1348
+ COPY gradle ./gradle
1349
+
1350
+ # Descargar dependencias (se cachea si no cambian)
1351
+ RUN gradle dependencies --no-daemon
1352
+
1353
+ # Copiar código fuente
1354
+ COPY src ./src
1355
+
1356
+ # Build (sin tests para acelerar)
1357
+ RUN gradle build -x test --no-daemon
1358
+
1359
+ # Stage final - solo runtime
1360
+ FROM eclipse-temurin:25-jre-alpine
1361
+ WORKDIR /app
1362
+
1363
+ # Copiar jar construido
1364
+ COPY --from=builder /app/build/libs/*.jar app.jar
1365
+
1366
+ # Usuario no-root
1367
+ RUN addgroup -S appgroup && adduser -S appuser -G appgroup
1368
+ USER appuser
1369
+
1370
+ # Exponer puerto
1371
+ EXPOSE 8080
1372
+
1373
+ # Comando de inicio
1374
+ ENTRYPOINT ["java", "-jar", "app.jar"]
1375
+ ```
1376
+
1377
+ ---
1378
+
1379
+ ## 🐹 Stack Moderno: Go + Air + golangci-lint
1380
+
1381
+ ### Por qué Go 1.25+ con Herramientas Modernas
1382
+
1383
+ ```
1384
+ Ventajas de Go 1.25+:
1385
+ ✅ Generics nativos (desde 1.18)
1386
+ ✅ JSON v2 experimental (encoding/json/v2)
1387
+ ✅ DWARF 5 debug info (binarios más pequeños)
1388
+ ✅ Mejor manejo de errores
1389
+ ✅ Performance optimizado (2-3% más rápido que 1.24)
1390
+ ✅ Tooling mejorado (go doc -http, tool directives)
1391
+
1392
+ golangci-lint vs linters individuales:
1393
+ - Incluye 50+ linters en uno
1394
+ - Configurable por proyecto
1395
+ - 5x más rápido que correr linters separados
1396
+ ```
1397
+
1398
+ ### Setup Inicial de Go Project
1399
+
1400
+ ```bash
1401
+ # Inicializar módulo Go
1402
+ go mod init github.com/usuario/mi-api
1403
+
1404
+ # Instalar Air (hot reload)
1405
+ go install github.com/cosmtrek/air@latest
1406
+
1407
+ # Instalar golangci-lint
1408
+ # macOS/Linux
1409
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
1410
+
1411
+ # O con Homebrew
1412
+ brew install golangci-lint
1413
+ ```
1414
+
1415
+ ### go.mod
1416
+
1417
+ ```go
1418
+ module github.com/usuario/mi-api
1419
+
1420
+ go 1.25
1421
+
1422
+ require (
1423
+ github.com/gin-gonic/gin v1.10.0
1424
+ github.com/lib/pq v1.10.9
1425
+ github.com/golang-jwt/jwt/v5 v5.2.1
1426
+ )
1427
+ ```
1428
+
1429
+ ### .golangci.yml (Configuración de Linter)
1430
+
1431
+ ```yaml
1432
+ run:
1433
+ timeout: 5m
1434
+ modules-download-mode: readonly
1435
+
1436
+ linters:
1437
+ enable:
1438
+ - errcheck # Verifica errores no manejados
1439
+ - gosimple # Simplificaciones de código
1440
+ - govet # Análisis estático
1441
+ - ineffassign # Asignaciones ineficientes
1442
+ - staticcheck # Análisis avanzado
1443
+ - unused # Código no usado
1444
+ - gofmt # Formato
1445
+ - goimports # Imports organizados
1446
+ - revive # Reemplazo rápido de golint
1447
+ - misspell # Errores de ortografía
1448
+ - gocritic # Sugerencias de mejora
1449
+
1450
+ linters-settings:
1451
+ gofmt:
1452
+ simplify: true
1453
+ goimports:
1454
+ local-prefixes: github.com/usuario/mi-api
1455
+ revive:
1456
+ rules:
1457
+ - name: exported
1458
+ severity: warning
1459
+ - name: var-naming
1460
+ severity: warning
1461
+
1462
+ issues:
1463
+ exclude-rules:
1464
+ - path: _test\.go
1465
+ linters:
1466
+ - errcheck
1467
+ ```
1468
+
1469
+ ### .air.toml (Hot Reload Configuration)
1470
+
1471
+ ```toml
1472
+ root = "."
1473
+ testdata_dir = "testdata"
1474
+ tmp_dir = "tmp"
1475
+
1476
+ [build]
1477
+ args_bin = []
1478
+ bin = "./tmp/main"
1479
+ cmd = "go build -o ./tmp/main ."
1480
+ delay = 1000
1481
+ exclude_dir = ["assets", "tmp", "vendor", "testdata"]
1482
+ exclude_file = []
1483
+ exclude_regex = ["_test.go"]
1484
+ exclude_unchanged = false
1485
+ follow_symlink = false
1486
+ full_bin = ""
1487
+ include_dir = []
1488
+ include_ext = ["go", "tpl", "tmpl", "html"]
1489
+ include_file = []
1490
+ kill_delay = "0s"
1491
+ log = "build-errors.log"
1492
+ poll = false
1493
+ poll_interval = 0
1494
+ rerun = false
1495
+ rerun_delay = 500
1496
+ send_interrupt = false
1497
+ stop_on_error = false
1498
+
1499
+ [color]
1500
+ app = ""
1501
+ build = "yellow"
1502
+ main = "magenta"
1503
+ runner = "green"
1504
+ watcher = "cyan"
1505
+
1506
+ [log]
1507
+ main_only = false
1508
+ time = false
1509
+
1510
+ [misc]
1511
+ clean_on_exit = false
1512
+
1513
+ [screen]
1514
+ clear_on_rebuild = false
1515
+ keep_scroll = true
1516
+ ```
1517
+
1518
+ ### Estructura de Proyecto Go con Gin
1519
+
1520
+ ```
1521
+ my-api/
1522
+ ├── cmd/
1523
+ │ └── api/
1524
+ │ └── main.go # Entry point
1525
+ ├── internal/
1526
+ │ ├── handlers/ # HTTP handlers
1527
+ │ │ └── health.go
1528
+ │ ├── models/ # Data models
1529
+ │ └── middleware/ # Middlewares
1530
+ ├── pkg/ # Código reutilizable
1531
+ ├── go.mod
1532
+ ├── go.sum
1533
+ ├── .air.toml
1534
+ ├── .golangci.yml
1535
+ ├── Dockerfile
1536
+ └── docker-compose.yml
1537
+ ```
1538
+
1539
+ ### main.go (Gin Framework)
1540
+
1541
+ ```go
1542
+ // cmd/api/main.go
1543
+ package main
1544
+
1545
+ import (
1546
+ "log"
1547
+ "github.com/gin-gonic/gin"
1548
+ "github.com/usuario/mi-api/internal/handlers"
1549
+ )
1550
+
1551
+ func main() {
1552
+ r := gin.Default()
1553
+
1554
+ // Health endpoint
1555
+ r.GET("/health", handlers.Health)
1556
+
1557
+ // Iniciar servidor
1558
+ if err := r.Run(":8080"); err != nil {
1559
+ log.Fatal("Failed to start server:", err)
1560
+ }
1561
+ }
1562
+ ```
1563
+
1564
+ ```go
1565
+ // internal/handlers/health.go
1566
+ package handlers
1567
+
1568
+ import (
1569
+ "net/http"
1570
+ "github.com/gin-gonic/gin"
1571
+ )
1572
+
1573
+ type HealthResponse struct {
1574
+ Status string `json:"status"`
1575
+ Version string `json:"version"`
1576
+ }
1577
+
1578
+ func Health(c *gin.Context) {
1579
+ c.JSON(http.StatusOK, HealthResponse{
1580
+ Status: "ok",
1581
+ Version: "0.1.0",
1582
+ })
1583
+ }
1584
+ ```
1585
+
1586
+ ### Comandos Go
1587
+
1588
+ ```bash
1589
+ # Desarrollo con hot reload
1590
+ air
1591
+
1592
+ # O sin air
1593
+ go run cmd/api/main.go
1594
+
1595
+ # Tests
1596
+ go test ./...
1597
+
1598
+ # Tests con cobertura
1599
+ go test -cover ./...
1600
+
1601
+ # Build
1602
+ go build -o bin/api cmd/api/main.go
1603
+
1604
+ # Lint
1605
+ golangci-lint run
1606
+
1607
+ # Format
1608
+ go fmt ./...
1609
+
1610
+ # Organizar imports
1611
+ goimports -w .
1612
+
1613
+ # Ver dependencias
1614
+ go mod tidy
1615
+ go mod vendor # opcional: para vendor/ local
1616
+ ```
1617
+
1618
+ ### Dockerfile para Go (Multi-stage)
1619
+
1620
+ ```dockerfile
1621
+ # Builder stage
1622
+ FROM golang:1.25-alpine AS builder
1623
+
1624
+ # Instalar dependencias de build
1625
+ RUN apk add --no-cache git
1626
+
1627
+ WORKDIR /app
1628
+
1629
+ # Copiar go.mod y go.sum primero (para cachear deps)
1630
+ COPY go.mod go.sum ./
1631
+ RUN go mod download
1632
+
1633
+ # Copiar código fuente
1634
+ COPY . .
1635
+
1636
+ # Build (static binary)
1637
+ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/api
1638
+
1639
+ # Final stage - solo el binario
1640
+ FROM alpine:3.21
1641
+
1642
+ # Certificados SSL para requests HTTPS
1643
+ RUN apk --no-cache add ca-certificates
1644
+
1645
+ WORKDIR /root/
1646
+
1647
+ # Copiar binario
1648
+ COPY --from=builder /app/main .
1649
+
1650
+ # Usuario no-root
1651
+ RUN adduser -D appuser
1652
+ USER appuser
1653
+
1654
+ # Exponer puerto
1655
+ EXPOSE 8080
1656
+
1657
+ # Comando
1658
+ CMD ["./main"]
1659
+ ```
1660
+
1661
+ ---
1662
+
1663
+ ## 📦 Templates de Proyecto Desde Cero (Actualizados)
1664
+
1665
+ ### 1. API REST con TypeScript + Bun + Biome
1666
+
1667
+ [Mantener el template existente de Bun]
1668
+
1669
+ ---
1670
+
1671
+ ### 2. API REST con Java + Gradle + Kotlin
1672
+
1673
+ ```bash
1674
+ my-api-java/
1675
+ ├── src/
1676
+ │ ├── main/
1677
+ │ │ ├── kotlin/
1678
+ │ │ │ └── com/example/api/
1679
+ │ │ │ ├── Application.kt
1680
+ │ │ │ ├── controller/
1681
+ │ │ │ │ └── HealthController.kt
1682
+ │ │ │ └── config/
1683
+ │ │ └── resources/
1684
+ │ │ └── application.yml
1685
+ │ └── test/
1686
+ │ └── kotlin/
1687
+ │ └── com/example/api/
1688
+ │ └── HealthControllerTest.kt
1689
+ ├── build.gradle.kts
1690
+ ├── settings.gradle.kts
1691
+ ├── gradle.properties
1692
+ ├── Dockerfile
1693
+ └── docker-compose.yml
1694
+ ```
1695
+
1696
+ #### settings.gradle.kts
1697
+
1698
+ ```kotlin
1699
+ rootProject.name = "my-api"
1700
+ ```
1701
+
1702
+ #### application.yml
1703
+
1704
+ ```yaml
1705
+ spring:
1706
+ application:
1707
+ name: my-api
1708
+ datasource:
1709
+ url: jdbc:postgresql://localhost:5432/mydb
1710
+ username: user
1711
+ password: pass
1712
+ jpa:
1713
+ hibernate:
1714
+ ddl-auto: validate
1715
+ show-sql: true
1716
+ properties:
1717
+ hibernate:
1718
+ dialect: org.hibernate.dialect.PostgreSQLDialect
1719
+
1720
+ server:
1721
+ port: 8080
1722
+
1723
+ logging:
1724
+ level:
1725
+ root: INFO
1726
+ com.example.api: DEBUG
1727
+ ```
1728
+
1729
+ #### HealthControllerTest.kt
1730
+
1731
+ ```kotlin
1732
+ package com.example.api
1733
+
1734
+ import org.junit.jupiter.api.Test
1735
+ import org.springframework.beans.factory.annotation.Autowired
1736
+ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
1737
+ import org.springframework.boot.test.context.SpringBootTest
1738
+ import org.springframework.test.web.servlet.MockMvc
1739
+ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
1740
+ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
1741
+ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
1742
+
1743
+ @SpringBootTest
1744
+ @AutoConfigureMockMvc
1745
+ class HealthControllerTest {
1746
+
1747
+ @Autowired
1748
+ private lateinit var mockMvc: MockMvc
1749
+
1750
+ @Test
1751
+ fun `health endpoint should return ok`() {
1752
+ mockMvc.perform(get("/health"))
1753
+ .andExpect(status().isOk)
1754
+ .andExpect(jsonPath("$.status").value("ok"))
1755
+ }
1756
+ }
1757
+ ```
1758
+
1759
+ #### docker-compose.yml
1760
+
1761
+ ```yaml
1762
+ version: '3.8'
1763
+
1764
+ services:
1765
+ api:
1766
+ build:
1767
+ context: .
1768
+ dockerfile: Dockerfile
1769
+ ports:
1770
+ - "8080:8080"
1771
+ environment:
1772
+ - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
1773
+ - SPRING_DATASOURCE_USERNAME=user
1774
+ - SPRING_DATASOURCE_PASSWORD=pass
1775
+ depends_on:
1776
+ - db
1777
+
1778
+ db:
1779
+ image: postgres:16-alpine
1780
+ ports:
1781
+ - "5432:5432"
1782
+ volumes:
1783
+ - postgres-data:/var/lib/postgresql/data
1784
+ environment:
1785
+ - POSTGRES_USER=user
1786
+ - POSTGRES_PASSWORD=pass
1787
+ - POSTGRES_DB=mydb
1788
+
1789
+ volumes:
1790
+ postgres-data:
1791
+ ```
1792
+
1793
+ ---
1794
+
1795
+ ### 3. API REST con Go + Gin + Air
1796
+
1797
+ ```bash
1798
+ my-api-go/
1799
+ ├── cmd/
1800
+ │ └── api/
1801
+ │ └── main.go
1802
+ ├── internal/
1803
+ │ ├── handlers/
1804
+ │ │ ├── health.go
1805
+ │ │ └── health_test.go
1806
+ │ ├── models/
1807
+ │ └── middleware/
1808
+ ├── pkg/
1809
+ ├── go.mod
1810
+ ├── go.sum
1811
+ ├── .air.toml
1812
+ ├── .golangci.yml
1813
+ ├── Dockerfile
1814
+ └── docker-compose.yml
1815
+ ```
1816
+
1817
+ #### go.mod (completo)
1818
+
1819
+ ```go
1820
+ module github.com/usuario/mi-api
1821
+
1822
+ go 1.22
1823
+
1824
+ require (
1825
+ github.com/gin-gonic/gin v1.9.1
1826
+ github.com/lib/pq v1.10.9
1827
+ github.com/stretchr/testify v1.8.4
1828
+ )
1829
+ ```
1830
+
1831
+ #### cmd/api/main.go (con database)
1832
+
1833
+ ```go
1834
+ package main
1835
+
1836
+ import (
1837
+ "database/sql"
1838
+ "log"
1839
+ "os"
1840
+
1841
+ "github.com/gin-gonic/gin"
1842
+ _ "github.com/lib/pq"
1843
+
1844
+ "github.com/usuario/mi-api/internal/handlers"
1845
+ )
1846
+
1847
+ func main() {
1848
+ // Database connection
1849
+ dbURL := os.Getenv("DATABASE_URL")
1850
+ if dbURL == "" {
1851
+ dbURL = "postgres://user:pass@localhost:5432/mydb?sslmode=disable"
1852
+ }
1853
+
1854
+ db, err := sql.Open("postgres", dbURL)
1855
+ if err != nil {
1856
+ log.Fatal("Failed to connect to database:", err)
1857
+ }
1858
+ defer db.Close()
1859
+
1860
+ // Verificar conexión
1861
+ if err := db.Ping(); err != nil {
1862
+ log.Fatal("Failed to ping database:", err)
1863
+ }
1864
+
1865
+ log.Println("Connected to database")
1866
+
1867
+ // Gin router
1868
+ r := gin.Default()
1869
+
1870
+ // Health endpoint
1871
+ r.GET("/health", handlers.Health)
1872
+
1873
+ // Iniciar servidor
1874
+ port := os.Getenv("PORT")
1875
+ if port == "" {
1876
+ port = "8080"
1877
+ }
1878
+
1879
+ if err := r.Run(":" + port); err != nil {
1880
+ log.Fatal("Failed to start server:", err)
1881
+ }
1882
+ }
1883
+ ```
1884
+
1885
+ #### internal/handlers/health_test.go
1886
+
1887
+ ```go
1888
+ package handlers
1889
+
1890
+ import (
1891
+ "net/http"
1892
+ "net/http/httptest"
1893
+ "testing"
1894
+
1895
+ "github.com/gin-gonic/gin"
1896
+ "github.com/stretchr/testify/assert"
1897
+ )
1898
+
1899
+ func TestHealth(t *testing.T) {
1900
+ gin.SetMode(gin.TestMode)
1901
+
1902
+ w := httptest.NewRecorder()
1903
+ c, _ := gin.CreateTestContext(w)
1904
+
1905
+ Health(c)
1906
+
1907
+ assert.Equal(t, http.StatusOK, w.Code)
1908
+ assert.Contains(t, w.Body.String(), `"status":"ok"`)
1909
+ }
1910
+ ```
1911
+
1912
+ #### docker-compose.yml
1913
+
1914
+ ```yaml
1915
+ version: '3.8'
1916
+
1917
+ services:
1918
+ api:
1919
+ build:
1920
+ context: .
1921
+ dockerfile: Dockerfile
1922
+ target: development # Para dev con Air
1923
+ ports:
1924
+ - "8080:8080"
1925
+ volumes:
1926
+ - .:/app
1927
+ - go-modules:/go/pkg/mod
1928
+ environment:
1929
+ - DATABASE_URL=postgres://user:pass@db:5432/mydb?sslmode=disable
1930
+ depends_on:
1931
+ - db
1932
+
1933
+ db:
1934
+ image: postgres:16-alpine
1935
+ ports:
1936
+ - "5432:5432"
1937
+ volumes:
1938
+ - postgres-data:/var/lib/postgresql/data
1939
+ environment:
1940
+ - POSTGRES_USER=user
1941
+ - POSTGRES_PASSWORD=pass
1942
+ - POSTGRES_DB=mydb
1943
+
1944
+ volumes:
1945
+ postgres-data:
1946
+ go-modules:
1947
+ ```
1948
+
1949
+ #### Dockerfile (Go con Air para dev)
1950
+
1951
+ ```dockerfile
1952
+ # Development stage con Air
1953
+ FROM golang:1.25-alpine AS development
1954
+
1955
+ RUN apk add --no-cache git
1956
+
1957
+ # Instalar Air
1958
+ RUN go install github.com/air-verse/air@latest
1959
+
1960
+ WORKDIR /app
1961
+
1962
+ COPY go.mod go.sum ./
1963
+ RUN go mod download
1964
+
1965
+ COPY . .
1966
+
1967
+ CMD ["air", "-c", ".air.toml"]
1968
+
1969
+ # Production stage
1970
+ FROM golang:1.25-alpine AS builder
1971
+
1972
+ WORKDIR /app
1973
+
1974
+ COPY go.mod go.sum ./
1975
+ RUN go mod download
1976
+
1977
+ COPY . .
1978
+
1979
+ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/api
1980
+
1981
+ FROM alpine:3.21 AS production
1982
+
1983
+ RUN apk --no-cache add ca-certificates
1984
+
1985
+ WORKDIR /root/
1986
+
1987
+ COPY --from=builder /app/main .
1988
+
1989
+ RUN adduser -D appuser
1990
+ USER appuser
1991
+
1992
+ EXPOSE 8080
1993
+
1994
+ CMD ["./main"]
1995
+ ```
1996
+
1997
+ ### 1. API REST (Node.js + Bun + Biome)
1998
+
1999
+ ```bash
2000
+ # Estructura inicial
2001
+ my-api/
2002
+ ├── src/
2003
+ │ ├── index.ts
2004
+ │ ├── routes/
2005
+ │ │ └── health.ts
2006
+ │ ├── middleware/
2007
+ │ └── types/
2008
+ ├── tests/
2009
+ │ └── health.test.ts
2010
+ ├── package.json
2011
+ ├── biome.json
2012
+ ├── Dockerfile
2013
+ ├── docker-compose.yml
2014
+ └── .gitignore
2015
+ ```
2016
+
2017
+ #### package.json
2018
+
2019
+ ```json
2020
+ {
2021
+ "name": "my-api",
2022
+ "type": "module",
2023
+ "scripts": {
2024
+ "dev": "bun run --hot src/index.ts",
2025
+ "build": "bun build src/index.ts --outdir dist --target node",
2026
+ "start": "NODE_ENV=production bun dist/index.js",
2027
+ "test": "bun test",
2028
+ "check": "biome ci ."
2029
+ },
2030
+ "dependencies": {
2031
+ "hono": "^4.0.0"
2032
+ },
2033
+ "devDependencies": {
2034
+ "@biomejs/biome": "^1.9.4",
2035
+ "@types/bun": "latest"
2036
+ }
2037
+ }
2038
+ ```
2039
+
2040
+ #### src/index.ts
2041
+
2042
+ ```typescript
2043
+ import { Hono } from 'hono';
2044
+ import { logger } from 'hono/logger';
2045
+ import { healthRoute } from './routes/health';
2046
+
2047
+ const app = new Hono();
2048
+
2049
+ // Middleware
2050
+ app.use('*', logger());
2051
+
2052
+ // Routes
2053
+ app.route('/health', healthRoute);
2054
+
2055
+ // Start server
2056
+ const port = process.env.PORT || 3000;
2057
+ console.log(`🚀 Server running on http://localhost:${port}`);
2058
+
2059
+ export default {
2060
+ port,
2061
+ fetch: app.fetch,
2062
+ };
2063
+ ```
2064
+
2065
+ #### tests/health.test.ts
2066
+
2067
+ ```typescript
2068
+ import { describe, expect, test } from 'bun:test';
2069
+ import app from '../src/index';
2070
+
2071
+ describe('Health Check', () => {
2072
+ test('GET /health returns 200', async () => {
2073
+ const req = new Request('http://localhost/health');
2074
+ const res = await app.fetch(req);
2075
+
2076
+ expect(res.status).toBe(200);
2077
+
2078
+ const body = await res.json();
2079
+ expect(body).toHaveProperty('status', 'ok');
2080
+ });
2081
+ });
2082
+ ```
2083
+
2084
+ #### Dockerfile
2085
+
2086
+ ```dockerfile
2087
+ FROM oven/bun:1.1-alpine as base
2088
+ WORKDIR /app
2089
+
2090
+ # Development
2091
+ FROM base as development
2092
+ COPY package.json bun.lockb ./
2093
+ RUN bun install
2094
+ COPY . .
2095
+ CMD ["bun", "run", "dev"]
2096
+
2097
+ # Production
2098
+ FROM base as production
2099
+ COPY package.json bun.lockb ./
2100
+ RUN bun install --production
2101
+ COPY . .
2102
+ RUN bun run build
2103
+ CMD ["bun", "run", "start"]
2104
+ ```
2105
+
2106
+ #### docker-compose.yml
2107
+
2108
+ ```yaml
2109
+ version: '3.8'
2110
+
2111
+ services:
2112
+ api:
2113
+ build:
2114
+ context: .
2115
+ target: development
2116
+ ports:
2117
+ - "3000:3000"
2118
+ volumes:
2119
+ - .:/app
2120
+ - /app/node_modules
2121
+ environment:
2122
+ - NODE_ENV=development
2123
+ - DATABASE_URL=postgresql://user:pass@db:5432/mydb
2124
+ depends_on:
2125
+ - db
2126
+
2127
+ db:
2128
+ image: postgres:16-alpine
2129
+ ports:
2130
+ - "5432:5432"
2131
+ volumes:
2132
+ - postgres-data:/var/lib/postgresql/data
2133
+ environment:
2134
+ - POSTGRES_USER=user
2135
+ - POSTGRES_PASSWORD=pass
2136
+ - POSTGRES_DB=mydb
2137
+
2138
+ volumes:
2139
+ postgres-data:
2140
+ ```
2141
+
2142
+ ---
2143
+
2144
+ ### 4. API REST con Python + FastAPI + uv
2145
+
2146
+ ```bash
2147
+ my-api/
2148
+ ├── app/
2149
+ │ ├── __init__.py
2150
+ │ ├── main.py
2151
+ │ └── routes/
2152
+ │ └── health.py
2153
+ ├── tests/
2154
+ │ └── test_health.py
2155
+ ├── pyproject.toml
2156
+ ├── uv.lock
2157
+ ├── Dockerfile
2158
+ └── docker-compose.yml
2159
+ ```
2160
+
2161
+ #### pyproject.toml
2162
+
2163
+ ```toml
2164
+ [project]
2165
+ name = "my-api"
2166
+ version = "0.1.0"
2167
+ description = "FastAPI project with uv"
2168
+ requires-python = ">=3.12"
2169
+ dependencies = [
2170
+ "fastapi>=0.109.0",
2171
+ "uvicorn[standard]>=0.27.0",
2172
+ "pydantic>=2.5.0",
2173
+ ]
2174
+
2175
+ [project.optional-dependencies]
2176
+ dev = [
2177
+ "pytest>=7.4.0",
2178
+ "httpx>=0.26.0",
2179
+ "ruff>=0.1.0",
2180
+ ]
2181
+
2182
+ [tool.ruff]
2183
+ line-length = 100
2184
+ target-version = "py312"
2185
+
2186
+ [tool.ruff.lint]
2187
+ select = ["E", "F", "I", "N", "W"]
2188
+ ignore = []
2189
+ ```
2190
+
2191
+ #### app/main.py
2192
+
2193
+ ```python
2194
+ from fastapi import FastAPI
2195
+ from fastapi.middleware.cors import CORSMiddleware
2196
+ from app.routes import health
2197
+
2198
+ app = FastAPI(title="My API")
2199
+
2200
+ # CORS
2201
+ app.add_middleware(
2202
+ CORSMiddleware,
2203
+ allow_origins=["*"],
2204
+ allow_credentials=True,
2205
+ allow_methods=["*"],
2206
+ allow_headers=["*"],
2207
+ )
2208
+
2209
+ # Routes
2210
+ app.include_router(health.router, prefix="/health", tags=["health"])
2211
+
2212
+ if __name__ == "__main__":
2213
+ import uvicorn
2214
+ uvicorn.run(app, host="0.0.0.0", port=8000)
2215
+ ```
2216
+
2217
+ #### app/routes/health.py
2218
+
2219
+ ```python
2220
+ from fastapi import APIRouter
2221
+ from pydantic import BaseModel
2222
+
2223
+ router = APIRouter()
2224
+
2225
+ class HealthResponse(BaseModel):
2226
+ status: str
2227
+ version: str = "0.1.0"
2228
+
2229
+ @router.get("/", response_model=HealthResponse)
2230
+ async def health_check():
2231
+ return {"status": "ok"}
2232
+ ```
2233
+
2234
+ #### tests/test_health.py
2235
+
2236
+ ```python
2237
+ from fastapi.testclient import TestClient
2238
+ from app.main import app
2239
+
2240
+ client = TestClient(app)
2241
+
2242
+ def test_health_check():
2243
+ response = client.get("/health/")
2244
+ assert response.status_code == 200
2245
+ assert response.json() == {"status": "ok", "version": "0.1.0"}
2246
+ ```
2247
+
2248
+ #### Dockerfile
2249
+
2250
+ ```dockerfile
2251
+ FROM python:3.12-slim as base
2252
+ WORKDIR /app
2253
+
2254
+ # Install uv
2255
+ RUN pip install uv
2256
+
2257
+ # Development
2258
+ FROM base as development
2259
+ COPY pyproject.toml uv.lock* ./
2260
+ RUN uv sync
2261
+ COPY . .
2262
+ CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--reload"]
2263
+
2264
+ # Production
2265
+ FROM base as production
2266
+ COPY pyproject.toml uv.lock* ./
2267
+ RUN uv sync --no-dev
2268
+ COPY . .
2269
+ RUN useradd -m appuser && chown -R appuser:appuser /app
2270
+ USER appuser
2271
+ CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--workers", "4"]
2272
+ ```
2273
+
2274
+ ---
2275
+
2276
+ ### 5. Monorepo Completo (Turborepo + Bun + Biome)
2277
+
2278
+ ```bash
2279
+ my-monorepo/
2280
+ ├── apps/
2281
+ │ ├── api/ # Backend (Bun + Hono)
2282
+ │ │ ├── src/
2283
+ │ │ ├── package.json
2284
+ │ │ └── Dockerfile
2285
+ │ ├── web/ # Frontend (Astro + React)
2286
+ │ │ ├── src/
2287
+ │ │ ├── package.json
2288
+ │ │ └── Dockerfile
2289
+ │ └── mobile/ # Mobile (Ionic + React)
2290
+ │ ├── src/
2291
+ │ └── package.json
2292
+ ├── packages/
2293
+ │ ├── ui/ # React components
2294
+ │ ├── types/ # Shared TypeScript types
2295
+ │ └── config/ # Shared Biome config
2296
+ ├── package.json # Root
2297
+ ├── turbo.json
2298
+ ├── biome.json
2299
+ ├── docker-compose.yml
2300
+ └── .gitignore
2301
+ ```
2302
+
2303
+ #### package.json (root)
2304
+
2305
+ ```json
2306
+ {
2307
+ "name": "my-monorepo",
2308
+ "private": true,
2309
+ "workspaces": [
2310
+ "apps/*",
2311
+ "packages/*"
2312
+ ],
2313
+ "scripts": {
2314
+ "dev": "turbo run dev",
2315
+ "build": "turbo run build",
2316
+ "test": "turbo run test",
2317
+ "lint": "biome check .",
2318
+ "format": "biome format --write .",
2319
+ "check": "biome ci ."
2320
+ },
2321
+ "devDependencies": {
2322
+ "@biomejs/biome": "^1.9.4",
2323
+ "turbo": "^2.0.0"
2324
+ },
2325
+ "packageManager": "bun@1.1.0"
2326
+ }
2327
+ ```
2328
+
2329
+ #### turbo.json
2330
+
2331
+ ```json
2332
+ {
2333
+ "$schema": "https://turbo.build/schema.json",
2334
+ "globalDependencies": ["**/.env.*local"],
2335
+ "pipeline": {
2336
+ "build": {
2337
+ "dependsOn": ["^build"],
2338
+ "outputs": ["dist/**", ".next/**", "build/**"]
2339
+ },
2340
+ "test": {
2341
+ "dependsOn": ["build"],
2342
+ "outputs": ["coverage/**"]
2343
+ },
2344
+ "lint": {
2345
+ "outputs": []
2346
+ },
2347
+ "dev": {
2348
+ "cache": false,
2349
+ "persistent": true
2350
+ }
2351
+ }
2352
+ }
2353
+ ```
2354
+
2355
+ #### biome.json (root - compartido)
2356
+
2357
+ ```json
2358
+ {
2359
+ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
2360
+ "organizeImports": {
2361
+ "enabled": true
2362
+ },
2363
+ "linter": {
2364
+ "enabled": true,
2365
+ "rules": {
2366
+ "recommended": true
2367
+ }
2368
+ },
2369
+ "formatter": {
2370
+ "enabled": true,
2371
+ "indentStyle": "space",
2372
+ "indentWidth": 2,
2373
+ "lineWidth": 100
2374
+ }
2375
+ }
2376
+ ```
2377
+
2378
+ #### packages/ui/package.json
2379
+
2380
+ ```json
2381
+ {
2382
+ "name": "@my-monorepo/ui",
2383
+ "version": "0.0.0",
2384
+ "type": "module",
2385
+ "main": "./dist/index.js",
2386
+ "types": "./dist/index.d.ts",
2387
+ "exports": {
2388
+ ".": "./dist/index.js"
2389
+ },
2390
+ "scripts": {
2391
+ "build": "bun build src/index.ts --outdir dist --target node",
2392
+ "dev": "bun build src/index.ts --outdir dist --target node --watch"
2393
+ },
2394
+ "peerDependencies": {
2395
+ "react": "^18.0.0",
2396
+ "react-dom": "^18.0.0"
2397
+ },
2398
+ "devDependencies": {
2399
+ "@types/react": "^18.2.0",
2400
+ "@types/react-dom": "^18.2.0"
2401
+ }
2402
+ }
2403
+ ```
2404
+
2405
+ #### packages/types/package.json
2406
+
2407
+ ```json
2408
+ {
2409
+ "name": "@my-monorepo/types",
2410
+ "version": "0.0.0",
2411
+ "type": "module",
2412
+ "main": "./dist/index.js",
2413
+ "types": "./dist/index.d.ts",
2414
+ "exports": {
2415
+ ".": "./dist/index.d.ts"
2416
+ },
2417
+ "scripts": {
2418
+ "build": "tsc",
2419
+ "dev": "tsc --watch"
2420
+ },
2421
+ "devDependencies": {
2422
+ "typescript": "^5.3.0"
2423
+ }
2424
+ }
2425
+ ```
2426
+
2427
+ #### apps/api/package.json
2428
+
2429
+ ```json
2430
+ {
2431
+ "name": "api",
2432
+ "version": "0.0.0",
2433
+ "type": "module",
2434
+ "scripts": {
2435
+ "dev": "bun run --hot src/index.ts",
2436
+ "build": "bun build src/index.ts --outdir dist --target node",
2437
+ "start": "NODE_ENV=production bun dist/index.js",
2438
+ "test": "bun test"
2439
+ },
2440
+ "dependencies": {
2441
+ "@my-monorepo/types": "workspace:*",
2442
+ "hono": "^4.0.0"
2443
+ },
2444
+ "devDependencies": {
2445
+ "@types/bun": "latest"
2446
+ }
2447
+ }
2448
+ ```
2449
+
2450
+ #### apps/web/package.json
2451
+
2452
+ ```json
2453
+ {
2454
+ "name": "web",
2455
+ "version": "0.0.0",
2456
+ "type": "module",
2457
+ "scripts": {
2458
+ "dev": "astro dev",
2459
+ "build": "astro build",
2460
+ "preview": "astro preview"
2461
+ },
2462
+ "dependencies": {
2463
+ "@my-monorepo/ui": "workspace:*",
2464
+ "@my-monorepo/types": "workspace:*",
2465
+ "astro": "^4.0.0",
2466
+ "react": "^18.2.0",
2467
+ "react-dom": "^18.2.0"
2468
+ }
2469
+ }
2470
+ ```
2471
+
2472
+ #### docker-compose.yml (monorepo)
2473
+
2474
+ ```yaml
2475
+ version: '3.8'
2476
+
2477
+ services:
2478
+ api:
2479
+ build:
2480
+ context: .
2481
+ dockerfile: apps/api/Dockerfile
2482
+ target: development
2483
+ ports:
2484
+ - "3000:3000"
2485
+ volumes:
2486
+ - .:/app
2487
+ - /app/node_modules
2488
+ environment:
2489
+ - NODE_ENV=development
2490
+ - DATABASE_URL=postgresql://user:pass@db:5432/mydb
2491
+ depends_on:
2492
+ - db
2493
+
2494
+ web:
2495
+ build:
2496
+ context: .
2497
+ dockerfile: apps/web/Dockerfile
2498
+ ports:
2499
+ - "4321:4321"
2500
+ volumes:
2501
+ - .:/app
2502
+ - /app/node_modules
2503
+ environment:
2504
+ - PUBLIC_API_URL=http://localhost:3000
2505
+
2506
+ db:
2507
+ image: postgres:16-alpine
2508
+ ports:
2509
+ - "5432:5432"
2510
+ volumes:
2511
+ - postgres-data:/var/lib/postgresql/data
2512
+ environment:
2513
+ - POSTGRES_USER=user
2514
+ - POSTGRES_PASSWORD=pass
2515
+ - POSTGRES_DB=mydb
2516
+
2517
+ volumes:
2518
+ postgres-data:
2519
+ ```
2520
+
2521
+ ---
2522
+
2523
+ ## 🔧 CI/CD Adaptativo Multi-Lenguaje
2524
+
2525
+ ### GitHub Actions con Biome + Bun
2526
+
2527
+ ```yaml
2528
+ # .github/workflows/ci.yml
2529
+ name: CI (Biome + Bun)
2530
+
2531
+ on:
2532
+ push:
2533
+ branches: [develop, main]
2534
+ pull_request:
2535
+ branches: [develop, main]
2536
+
2537
+ env:
2538
+ BUN_VERSION: '1.1.0'
2539
+
2540
+ jobs:
2541
+ detect-and-test:
2542
+ runs-on: ubuntu-latest
2543
+
2544
+ steps:
2545
+ - name: Checkout
2546
+ uses: actions/checkout@v4
2547
+ with:
2548
+ fetch-depth: 2
2549
+
2550
+ # ═══════════════════════════════════════════════════════════
2551
+ # DETECCIÓN AUTOMÁTICA DE STACK
2552
+ # ═══════════════════════════════════════════════════════════
2553
+ - name: Detect Tech Stack
2554
+ id: detect
2555
+ run: |
2556
+ if [ -f "package.json" ]; then
2557
+ echo "stack=node" >> $GITHUB_OUTPUT
2558
+ echo "pm=bun" >> $GITHUB_OUTPUT
2559
+ elif [ -f "pyproject.toml" ]; then
2560
+ echo "stack=python" >> $GITHUB_OUTPUT
2561
+ echo "pm=uv" >> $GITHUB_OUTPUT
2562
+ elif [ -f "go.mod" ]; then
2563
+ echo "stack=go" >> $GITHUB_OUTPUT
2564
+ elif [ -f "Cargo.toml" ]; then
2565
+ echo "stack=rust" >> $GITHUB_OUTPUT
2566
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
2567
+ echo "stack=java-gradle" >> $GITHUB_OUTPUT
2568
+ elif [ -f "pom.xml" ]; then
2569
+ echo "stack=java-maven" >> $GITHUB_OUTPUT
2570
+ fi
2571
+
2572
+ # Detectar monorepo
2573
+ if [ -f "turbo.json" ]; then
2574
+ echo "monorepo=turborepo" >> $GITHUB_OUTPUT
2575
+ fi
2576
+
2577
+ # ═══════════════════════════════════════════════════════════
2578
+ # NODE.JS + BUN + BIOME
2579
+ # ═══════════════════════════════════════════════════════════
2580
+ - name: Setup Bun
2581
+ if: steps.detect.outputs.stack == 'node'
2582
+ uses: oven-sh/setup-bun@v1
2583
+ with:
2584
+ bun-version: ${{ env.BUN_VERSION }}
2585
+
2586
+ - name: Install Dependencies
2587
+ if: steps.detect.outputs.stack == 'node'
2588
+ run: bun install --frozen-lockfile
2589
+
2590
+ - name: Biome Check
2591
+ if: steps.detect.outputs.stack == 'node'
2592
+ run: bun run check
2593
+
2594
+ - name: Run Tests
2595
+ if: steps.detect.outputs.stack == 'node'
2596
+ run: bun test
2597
+
2598
+ - name: Build
2599
+ if: steps.detect.outputs.stack == 'node'
2600
+ run: bun run build
2601
+
2602
+ # ═══════════════════════════════════════════════════════════
2603
+ # TURBOREPO (SI ES MONOREPO)
2604
+ # ═══════════════════════════════════════════════════════════
2605
+ - name: Turborepo Cache
2606
+ if: steps.detect.outputs.monorepo == 'turborepo'
2607
+ uses: actions/cache@v4
2608
+ with:
2609
+ path: .turbo
2610
+ key: turbo-${{ runner.os }}-${{ github.sha }}
2611
+ restore-keys: turbo-${{ runner.os }}-
2612
+
2613
+ - name: Build (Affected Only)
2614
+ if: steps.detect.outputs.monorepo == 'turborepo'
2615
+ run: bun run build --filter='...[origin/develop]'
2616
+
2617
+ - name: Test (Affected Only)
2618
+ if: steps.detect.outputs.monorepo == 'turborepo'
2619
+ run: bun test --filter='...[origin/develop]'
2620
+
2621
+ # ═══════════════════════════════════════════════════════════
2622
+ # PYTHON + UV
2623
+ # ═══════════════════════════════════════════════════════════
2624
+ - name: Setup Python
2625
+ if: steps.detect.outputs.stack == 'python'
2626
+ uses: actions/setup-python@v5
2627
+ with:
2628
+ python-version: '3.12'
2629
+
2630
+ - name: Install uv
2631
+ if: steps.detect.outputs.stack == 'python'
2632
+ run: pip install uv
2633
+
2634
+ - name: Install Dependencies
2635
+ if: steps.detect.outputs.stack == 'python'
2636
+ run: uv sync
2637
+
2638
+ - name: Lint (Ruff)
2639
+ if: steps.detect.outputs.stack == 'python'
2640
+ run: uv run ruff check .
2641
+
2642
+ - name: Run Tests
2643
+ if: steps.detect.outputs.stack == 'python'
2644
+ run: uv run pytest
2645
+
2646
+ # ═══════════════════════════════════════════════════════════
2647
+ # JAVA (GRADLE + KOTLIN)
2648
+ # ═══════════════════════════════════════════════════════════
2649
+ - name: Setup Java
2650
+ if: steps.detect.outputs.stack == 'java-gradle' || steps.detect.outputs.stack == 'java-maven'
2651
+ uses: actions/setup-java@v4
2652
+ with:
2653
+ distribution: 'temurin'
2654
+ java-version: '25'
2655
+ cache: 'gradle'
2656
+
2657
+ - name: Make gradlew executable
2658
+ if: steps.detect.outputs.stack == 'java-gradle'
2659
+ run: chmod +x ./gradlew
2660
+
2661
+ - name: Check Format (Spotless)
2662
+ if: steps.detect.outputs.stack == 'java-gradle'
2663
+ run: ./gradlew spotlessCheck
2664
+
2665
+ - name: Build and Test (Gradle)
2666
+ if: steps.detect.outputs.stack == 'java-gradle'
2667
+ run: ./gradlew build test
2668
+
2669
+ # ═══════════════════════════════════════════════════════════
2670
+ # GO
2671
+ # ═══════════════════════════════════════════════════════════
2672
+ - name: Setup Go
2673
+ if: steps.detect.outputs.stack == 'go'
2674
+ uses: actions/setup-go@v5
2675
+ with:
2676
+ go-version: '1.25'
2677
+ cache: true
2678
+
2679
+ - name: Install golangci-lint
2680
+ if: steps.detect.outputs.stack == 'go'
2681
+ run: |
2682
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
2683
+ echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
2684
+
2685
+ - name: Lint (golangci-lint)
2686
+ if: steps.detect.outputs.stack == 'go'
2687
+ run: golangci-lint run
2688
+
2689
+ - name: Install & Test (Go)
2690
+ if: steps.detect.outputs.stack == 'go'
2691
+ run: |
2692
+ go mod download
2693
+ go test -v ./...
2694
+ go build -v ./...
2695
+
2696
+ # ═══════════════════════════════════════════════════════════
2697
+ # RUST
2698
+ # ═══════════════════════════════════════════════════════════
2699
+ - name: Setup Rust
2700
+ if: steps.detect.outputs.stack == 'rust'
2701
+ uses: dtolnay/rust-toolchain@stable
2702
+
2703
+ - name: Cache Rust
2704
+ if: steps.detect.outputs.stack == 'rust'
2705
+ uses: Swatinem/rust-cache@v2
2706
+
2707
+ - name: Install & Test (Rust)
2708
+ if: steps.detect.outputs.stack == 'rust'
2709
+ run: |
2710
+ cargo test
2711
+ cargo build --release
2712
+
2713
+ # ═══════════════════════════════════════════════════════════
2714
+ # AUTO-MERGE (Para Solo Devs)
2715
+ # ═══════════════════════════════════════════════════════════
2716
+ auto-merge:
2717
+ needs: detect-and-test
2718
+ if: github.event_name == 'pull_request'
2719
+ runs-on: ubuntu-latest
2720
+
2721
+ steps:
2722
+ - name: Auto-merge PR
2723
+ uses: pascalgn/automerge-action@v0.16.2
2724
+ env:
2725
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2726
+ MERGE_METHOD: squash
2727
+ MERGE_DELETE_BRANCH: true
2728
+ MERGE_LABELS: ''
2729
+ ```
2730
+
2731
+ ---
2732
+
2733
+ ## 📅 Rutina Diaria del Solo Developer
2734
+
2735
+ ### El Ritmo Semanal Óptimo
2736
+
2737
+ ```typescript
2738
+ const WEEKLY_RHYTHM = {
2739
+ monday: {
2740
+ morning: 'PLANIFICACIÓN',
2741
+ tasks: [
2742
+ '1. Revisar backlog y priorizar',
2743
+ '2. Pedirle al agente el plan de la semana',
2744
+ '3. Configurar los pasos en GitHub Issues',
2745
+ '4. Empezar Paso 1 si queda tiempo'
2746
+ ],
2747
+ wipLimit: 0 // Solo planificar, no codear
2748
+ },
2749
+
2750
+ tuesdayToThursday: {
2751
+ morning: 'EJECUCIÓN ATÓMICA',
2752
+ routine: `
2753
+ 08:00 - git checkout develop && git pull
2754
+ 08:05 - Revisar el paso actual (Issue de GitHub)
2755
+ 08:10 - Crear branch: feat/XX-descripcion
2756
+ 08:15 - 12:00 DEEP WORK (código)
2757
+ 12:00 - Tests locales
2758
+ 12:30 - git push → CI automático
2759
+ 13:00 - Almuerzo (CI corriendo)
2760
+ 14:00 - Si CI verde → Merge
2761
+ 14:05 - Siguiente paso o continuar
2762
+ `,
2763
+ wipLimit: 1 // UNA sola tarea activa
2764
+ },
2765
+
2766
+ friday: {
2767
+ morning: 'DEPLOY + REFACTOR',
2768
+ tasks: [
2769
+ '1. Merge develop → main (si hay features completas)',
2770
+ '2. Deploy a staging/production',
2771
+ '3. Smoke test manual',
2772
+ '4. 2h de refactoring técnico',
2773
+ '5. Actualizar documentación si es necesario'
2774
+ ],
2775
+ wipLimit: 0 // Solo deploy y mantenimiento
2776
+ }
2777
+ };
2778
+ ```
2779
+
2780
+ ### Comandos Git del Día a Día
2781
+
2782
+ ```bash
2783
+ #!/bin/bash
2784
+ # scripts/solo-dev-flow.sh
2785
+
2786
+ # ═══════════════════════════════════════════════════════════
2787
+ # INICIAR NUEVO PASO
2788
+ # ═══════════════════════════════════════════════════════════
2789
+ start_step() {
2790
+ local step_num=$1
2791
+ local step_name=$2
2792
+
2793
+ echo "🚀 Iniciando Paso $step_num: $step_name"
2794
+
2795
+ # Siempre desde develop actualizado
2796
+ git checkout develop
2797
+ git pull origin develop
2798
+
2799
+ # Crear UNA SOLA rama para TODO el paso
2800
+ local branch="feat/$(printf '%02d' $step_num)-$step_name"
2801
+ git checkout -b "$branch"
2802
+
2803
+ echo "✅ Branch '$branch' creado"
2804
+ echo ""
2805
+ echo "💡 FLUJO DE TRABAJO:"
2806
+ echo " 1. Implementa una parte pequeña"
2807
+ echo " 2. git add . && git commit -m 'descripción'"
2808
+ echo " 3. Repite hasta completar TODO el paso"
2809
+ echo " 4. git push -u origin HEAD (pushea TODOS los commits)"
2810
+ echo " 5. finish_step (crea PR automático)"
2811
+ echo ""
2812
+ echo "📝 Puedes hacer tantos commits como necesites en esta rama"
2813
+ }
2814
+
2815
+ # ═══════════════════════════════════════════════════════════
2816
+ # FINALIZAR PASO (Push + PR automático)
2817
+ # ═══════════════════════════════════════════════════════════
2818
+ finish_step() {
2819
+ local message=$1
2820
+
2821
+ # Verificar que hay commits sin pushear
2822
+ if git diff origin/$(git branch --show-current) --quiet 2>/dev/null; then
2823
+ echo "⚠️ No hay cambios para pushear. ¿Ya hiciste commits?"
2824
+ echo "Usa: git add . && git commit -m 'tu mensaje'"
2825
+ return 1
2826
+ fi
2827
+
2828
+ # Push (puede ser de múltiples commits)
2829
+ echo "📤 Pusheando commits..."
2830
+ git push -u origin HEAD
2831
+
2832
+ # Crear PR con gh CLI
2833
+ gh pr create \
2834
+ --title "$message" \
2835
+ --body "## Paso Atómico
2836
+
2837
+ Este PR contiene $(git log origin/develop..HEAD --oneline | wc -l) commits que serán squashed en 1.
2838
+
2839
+ ### Commits en este PR:
2840
+ \`\`\`
2841
+ $(git log origin/develop..HEAD --oneline)
2842
+ \`\`\`
2843
+
2844
+ **Al merge**: Todos estos commits se combinarán en uno solo usando squash merge.
2845
+
2846
+ ---
2847
+ *Generado por Solo Dev Planner*" \
2848
+ --base develop
2849
+
2850
+ echo ""
2851
+ echo "✅ PR creado. Esperando CI..."
2852
+ echo "💡 El PR se mergeará automáticamente cuando CI pase"
2853
+ echo "📦 Squash merge: múltiples commits → 1 commit limpio en develop"
2854
+ }
2855
+
2856
+ # ═══════════════════════════════════════════════════════════
2857
+ # COMMIT HELPER (opcional - para recordar hacer commits frecuentes)
2858
+ # ═══════════════════════════════════════════════════════════
2859
+ quick_commit() {
2860
+ local msg=$1
2861
+
2862
+ if [ -z "$msg" ]; then
2863
+ echo "❌ Proporciona un mensaje: quick_commit 'descripción'"
2864
+ return 1
2865
+ fi
2866
+
2867
+ git add .
2868
+ git commit -m "$msg"
2869
+
2870
+ echo "✅ Commit creado: $msg"
2871
+ echo "💡 Puedes seguir haciendo más commits en esta rama"
2872
+ echo "💡 Cuando termines el paso, usa: finish_step"
2873
+ }
2874
+
2875
+ # ═══════════════════════════════════════════════════════════
2876
+ # VER ESTADO
2877
+ # ═══════════════════════════════════════════════════════════
2878
+ status() {
2879
+ echo "═══════════════════════════════════════════════════════════"
2880
+ echo "📊 ESTADO DEL PROYECTO"
2881
+ echo "═══════════════════════════════════════════════════════════"
2882
+ echo ""
2883
+ echo "🌳 Branch actual: $(git branch --show-current)"
2884
+ echo ""
2885
+
2886
+ # Commits locales sin pushear
2887
+ local unpushed=$(git log origin/$(git branch --show-current)..HEAD --oneline 2>/dev/null | wc -l)
2888
+ if [ "$unpushed" -gt 0 ]; then
2889
+ echo "📝 Commits locales sin pushear: $unpushed"
2890
+ git log origin/$(git branch --show-current)..HEAD --oneline
2891
+ echo ""
2892
+ fi
2893
+
2894
+ echo "📋 PRs abiertos:"
2895
+ gh pr list --state open
2896
+ echo ""
2897
+ echo "✅ PRs mergeados hoy:"
2898
+ gh pr list --state merged --search "merged:$(date +%Y-%m-%d)"
2899
+ echo ""
2900
+ echo "🔄 Estado de CI:"
2901
+ gh run list --limit 3
2902
+ }
2903
+
2904
+ # ═══════════════════════════════════════════════════════════
2905
+ # EJEMPLO DE USO
2906
+ # ═══════════════════════════════════════════════════════════
2907
+ example_usage() {
2908
+ cat << 'EOF'
2909
+ ═══════════════════════════════════════════════════════════
2910
+ 📖 EJEMPLO DE USO CORRECTO
2911
+ ═══════════════════════════════════════════════════════════
2912
+
2913
+ # 1. Iniciar paso
2914
+ source scripts/solo-dev-flow.sh
2915
+ start_step 01 "database-schema"
2916
+
2917
+ # 2. Trabajar en el paso (hacer múltiples commits)
2918
+ # ... editar archivos ...
2919
+ quick_commit "add User model"
2920
+
2921
+ # ... editar más archivos ...
2922
+ quick_commit "add migration script"
2923
+
2924
+ # ... editar tests ...
2925
+ quick_commit "add tests for User model"
2926
+
2927
+ # 3. Finalizar paso (pushea todos los commits y crea PR)
2928
+ finish_step "feat(db): implement database schema"
2929
+
2930
+ # 4. CI pasa → Auto-merge con SQUASH
2931
+ # Resultado en develop: 1 commit limpio con todos los cambios
2932
+
2933
+ # 5. Siguiente paso
2934
+ start_step 02 "api-endpoints"
2935
+ # ... repetir proceso ...
2936
+
2937
+ ═══════════════════════════════════════════════════════════
2938
+ EOF
2939
+ }
2940
+
2941
+ # Mostrar ayuda si se ejecuta sin argumentos
2942
+ if [ $# -eq 0 ]; then
2943
+ example_usage
2944
+ fi
2945
+ ```
2946
+
2947
+ ---
2948
+
2949
+ ## 🎯 Generación de Plan (Output del Agente)
2950
+
2951
+ ### Prompt para Iniciar Proyecto
2952
+
2953
+ ```markdown
2954
+ MODO: Solo-Developer / Proyecto Desde Cero
2955
+
2956
+ PROYECTO: [Nombre del proyecto]
2957
+
2958
+ DESCRIPCIÓN:
2959
+ [Breve descripción del objetivo del proyecto]
2960
+
2961
+ STACK PREFERIDO:
2962
+ - Backend: [Python/FastAPI, Node/Bun, Go, Rust, etc.]
2963
+ - Frontend: [Astro, Next.js, SvelteKit, etc.]
2964
+ - Base de datos: [PostgreSQL, MongoDB, etc.]
2965
+ - Monorepo: [Sí/No - Si sí, usar Turborepo]
2966
+
2967
+ FEATURES PRINCIPALES:
2968
+ 1. [Feature 1]
2969
+ 2. [Feature 2]
2970
+ 3. [Feature 3]
2971
+
2972
+ ENTREGABLE:
2973
+ Genera un plan atómico con:
2974
+ - Estructura de directorios inicial
2975
+ - Configuración de Biome + Bun (si aplica)
2976
+ - Docker Compose setup
2977
+ - CI/CD con GitHub Actions
2978
+ - Pasos granulares para implementar cada feature
2979
+ ```
2980
+
2981
+ ### Ejemplo: Feature "Sistema de Autenticación"
2982
+
2983
+ Cuando le pidas al agente planificar una feature, generará:
2984
+
2985
+ ```markdown
2986
+ # 🎯 PLAN: Sistema de Autenticación
2987
+
2988
+ ## 📊 Resumen
2989
+ - **Pasos totales:** 5
2990
+ - **Tiempo estimado:** 3-4 días de trabajo enfocado
2991
+ - **Stack:** Python/FastAPI + PostgreSQL + JWT
2992
+ - **Apps afectadas:** api-server
2993
+ - **Packages afectados:** types
2994
+
2995
+ ---
2996
+
2997
+ ## PASO 1: Setup Inicial + Docker
2998
+
2999
+ **Branch:** `feat/01-auth-setup`
3000
+ **Duración típica:** 1-2 horas
3001
+
3002
+ ### Objetivo
3003
+ Configurar estructura base del proyecto con Docker Compose.
3004
+
3005
+ ### Archivos a Crear
3006
+ - `pyproject.toml` - Configuración de proyecto con uv
3007
+ - `docker-compose.yml` - PostgreSQL + API
3008
+ - `Dockerfile` - Multi-stage para dev/prod
3009
+ - `app/main.py` - Entry point de FastAPI
3010
+ - `.env.example` - Variables de entorno
3011
+
3012
+ ### Template pyproject.toml
3013
+ ```toml
3014
+ [project]
3015
+ name = "auth-api"
3016
+ version = "0.1.0"
3017
+ requires-python = ">=3.12"
3018
+ dependencies = [
3019
+ "fastapi>=0.109.0",
3020
+ "uvicorn[standard]>=0.27.0",
3021
+ "sqlalchemy>=2.0.0",
3022
+ "asyncpg>=0.29.0",
3023
+ "python-jose[cryptography]>=3.3.0",
3024
+ "passlib[bcrypt]>=1.7.4",
3025
+ "python-multipart>=0.0.6",
3026
+ ]
3027
+
3028
+ [project.optional-dependencies]
3029
+ dev = [
3030
+ "pytest>=7.4.0",
3031
+ "pytest-asyncio>=0.21.0",
3032
+ "httpx>=0.26.0",
3033
+ "ruff>=0.1.0",
3034
+ ]
3035
+ ```
3036
+
3037
+ ### Comandos
3038
+ ```bash
3039
+ # Inicializar proyecto
3040
+ uv init
3041
+ uv add fastapi uvicorn sqlalchemy asyncpg python-jose passlib
3042
+ uv add --dev pytest pytest-asyncio httpx ruff
3043
+
3044
+ # Levantar stack
3045
+ docker compose up -d
3046
+
3047
+ # Verificar
3048
+ curl http://localhost:8000/health
3049
+ ```
3050
+
3051
+ ### Done Criteria
3052
+ - [ ] Docker Compose levanta PostgreSQL + API
3053
+ - [ ] Endpoint `/health` responde 200
3054
+ - [ ] uv sync funciona sin errores
3055
+
3056
+ ---
3057
+
3058
+ ## PASO 2: Schema de Base de Datos
3059
+
3060
+ **Branch:** `feat/02-auth-schema`
3061
+ **Prerequisito:** Paso 1 mergeado
3062
+ **Duración típica:** 2-3 horas
3063
+
3064
+ ### Objetivo
3065
+ Crear tablas `users` y `refresh_tokens` con SQLAlchemy.
3066
+
3067
+ ### Archivos a Crear
3068
+ - `app/database.py` - Configuración de SQLAlchemy
3069
+ - `app/models/user.py` - Modelo de usuario
3070
+ - `app/models/refresh_token.py` - Modelo de refresh tokens
3071
+ - `alembic.ini` - Configuración de migraciones
3072
+ - `migrations/versions/001_create_users.py` - Migración inicial
3073
+
3074
+ ### Contexto Just-in-Time: SQLAlchemy 2.0 Async
3075
+
3076
+ SQLAlchemy 2.0 cambió la sintaxis para queries async:
3077
+
3078
+ ```python
3079
+ # app/database.py
3080
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
3081
+ from sqlalchemy.orm import sessionmaker, declarative_base
3082
+
3083
+ DATABASE_URL = "postgresql+asyncpg://user:pass@db:5432/auth"
3084
+
3085
+ engine = create_async_engine(DATABASE_URL, echo=True)
3086
+ async_session = sessionmaker(
3087
+ engine, class_=AsyncSession, expire_on_commit=False
3088
+ )
3089
+
3090
+ Base = declarative_base()
3091
+
3092
+ async def get_db() -> AsyncSession:
3093
+ async with async_session() as session:
3094
+ yield session
3095
+ ```
3096
+
3097
+ ```python
3098
+ # app/models/user.py
3099
+ from sqlalchemy import Column, String, Boolean, DateTime
3100
+ from sqlalchemy.dialects.postgresql import UUID
3101
+ from app.database import Base
3102
+ import uuid
3103
+ from datetime import datetime
3104
+
3105
+ class User(Base):
3106
+ __tablename__ = "users"
3107
+
3108
+ id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
3109
+ email = Column(String, unique=True, index=True, nullable=False)
3110
+ hashed_password = Column(String, nullable=False)
3111
+ is_active = Column(Boolean, default=True)
3112
+ created_at = Column(DateTime, default=datetime.utcnow)
3113
+ ```
3114
+
3115
+ ### Comandos
3116
+ ```bash
3117
+ # Instalar Alembic
3118
+ uv add alembic
3119
+
3120
+ # Inicializar migraciones
3121
+ alembic init migrations
3122
+
3123
+ # Crear migración
3124
+ alembic revision --autogenerate -m "create users table"
3125
+
3126
+ # Aplicar migración
3127
+ docker compose exec api alembic upgrade head
3128
+ ```
3129
+
3130
+ ### Done Criteria
3131
+ - [ ] Migración ejecuta sin errores
3132
+ - [ ] Tabla `users` existe en PostgreSQL
3133
+ - [ ] Modelo `User` tiene validaciones correctas
3134
+
3135
+ ---
3136
+
3137
+ ## PASO 3: Endpoints de Registro y Login
3138
+
3139
+ **Branch:** `feat/03-auth-endpoints`
3140
+ **Prerequisito:** Paso 2 mergeado
3141
+ **Duración típica:** 4-5 horas
3142
+
3143
+ ### Objetivo
3144
+ Crear endpoints POST `/register` y POST `/login` con JWT.
3145
+
3146
+ ### Archivos a Crear
3147
+ - `app/schemas/user.py` - Pydantic schemas
3148
+ - `app/routes/auth.py` - Endpoints de auth
3149
+ - `app/services/auth.py` - Lógica de negocio (hash, JWT)
3150
+ - `app/dependencies.py` - Dependency injection
3151
+ - `tests/test_auth.py` - Tests de integración
3152
+
3153
+ ### Contexto Just-in-Time: JWT con python-jose
3154
+
3155
+ ```python
3156
+ # app/services/auth.py
3157
+ from jose import jwt
3158
+ from passlib.context import CryptContext
3159
+ from datetime import datetime, timedelta
3160
+
3161
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
3162
+
3163
+ SECRET_KEY = "your-secret-key-here" # Mover a .env en prod
3164
+ ALGORITHM = "HS256"
3165
+ ACCESS_TOKEN_EXPIRE_MINUTES = 30
3166
+
3167
+ def verify_password(plain_password: str, hashed_password: str) -> bool:
3168
+ return pwd_context.verify(plain_password, hashed_password)
3169
+
3170
+ def get_password_hash(password: str) -> str:
3171
+ return pwd_context.hash(password)
3172
+
3173
+ def create_access_token(data: dict) -> str:
3174
+ to_encode = data.copy()
3175
+ expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
3176
+ to_encode.update({"exp": expire})
3177
+ return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
3178
+ ```
3179
+
3180
+ ### Comandos para Probar
3181
+ ```bash
3182
+ # Registro
3183
+ curl -X POST http://localhost:8000/auth/register \
3184
+ -H "Content-Type: application/json" \
3185
+ -d '{"email": "test@example.com", "password": "secret123"}'
3186
+
3187
+ # Login
3188
+ curl -X POST http://localhost:8000/auth/login \
3189
+ -H "Content-Type: application/json" \
3190
+ -d '{"email": "test@example.com", "password": "secret123"}'
3191
+
3192
+ # Tests automatizados
3193
+ docker compose exec api pytest tests/test_auth.py -v
3194
+ ```
3195
+
3196
+ ### Done Criteria
3197
+ - [ ] POST `/register` crea usuario con password hasheado
3198
+ - [ ] POST `/login` retorna JWT válido
3199
+ - [ ] Passwords incorrectos retornan 401
3200
+ - [ ] Tests de integración pasan
3201
+
3202
+ ---
3203
+
3204
+ ## PASO 4: Middleware de Autenticación
3205
+
3206
+ **Branch:** `feat/04-auth-middleware`
3207
+ **Prerequisito:** Paso 3 mergeado
3208
+ **Duración típica:** 2-3 horas
3209
+
3210
+ ### Objetivo
3211
+ Crear dependency para proteger rutas con JWT.
3212
+
3213
+ ### Archivos a Crear/Modificar
3214
+ - `app/dependencies.py` - `get_current_user` dependency
3215
+ - `app/routes/users.py` - Endpoint protegido ejemplo
3216
+ - `tests/test_protected_routes.py` - Tests de autorización
3217
+
3218
+ ### Contexto Just-in-Time: FastAPI Dependencies
3219
+
3220
+ ```python
3221
+ # app/dependencies.py
3222
+ from fastapi import Depends, HTTPException, status
3223
+ from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
3224
+ from jose import jwt, JWTError
3225
+ from app.services.auth import SECRET_KEY, ALGORITHM
3226
+
3227
+ security = HTTPBearer()
3228
+
3229
+ async def get_current_user(
3230
+ credentials: HTTPAuthorizationCredentials = Depends(security)
3231
+ ) -> dict:
3232
+ token = credentials.credentials
3233
+
3234
+ try:
3235
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
3236
+ user_id: str = payload.get("sub")
3237
+ if user_id is None:
3238
+ raise HTTPException(status_code=401, detail="Invalid token")
3239
+ return {"user_id": user_id}
3240
+ except JWTError:
3241
+ raise HTTPException(status_code=401, detail="Invalid token")
3242
+
3243
+ # Uso en rutas protegidas:
3244
+ @router.get("/me")
3245
+ async def get_my_profile(current_user: dict = Depends(get_current_user)):
3246
+ return {"user_id": current_user["user_id"]}
3247
+ ```
3248
+
3249
+ ### Done Criteria
3250
+ - [ ] Rutas con `Depends(get_current_user)` requieren JWT
3251
+ - [ ] JWT inválido retorna 401
3252
+ - [ ] JWT válido permite acceso
3253
+ - [ ] Tests de autorización pasan
3254
+
3255
+ ---
3256
+
3257
+ ## PASO 5: Refresh Tokens
3258
+
3259
+ **Branch:** `feat/05-refresh-tokens`
3260
+ **Prerequisito:** Paso 4 mergeado
3261
+ **Duración típica:** 3-4 horas
3262
+
3263
+ ### Objetivo
3264
+ Implementar refresh tokens para no re-loguear cada 30 min.
3265
+
3266
+ ### Archivos a Crear/Modificar
3267
+ - `app/models/refresh_token.py` - Modelo ya creado en Paso 2
3268
+ - `app/routes/auth.py` - Endpoint POST `/refresh`
3269
+ - `app/services/auth.py` - Funciones para refresh tokens
3270
+ - `tests/test_refresh.py` - Tests
3271
+
3272
+ ### Flujo de Refresh Tokens
3273
+ 1. Login retorna: `{ access_token, refresh_token }`
3274
+ 2. Access token expira en 30 min
3275
+ 3. Frontend usa refresh token para obtener nuevo access token
3276
+ 4. Refresh token expira en 7 días
3277
+
3278
+ ### Done Criteria
3279
+ - [ ] Login retorna access + refresh token
3280
+ - [ ] POST `/refresh` con refresh token válido retorna nuevo access token
3281
+ - [ ] Refresh token expirado retorna 401
3282
+ - [ ] Tests de refresh pasan
3283
+
3284
+ ---
3285
+
3286
+ ## 🚀 Comandos Globales
3287
+
3288
+ ```bash
3289
+ # Iniciar desarrollo
3290
+ docker compose up -d
3291
+
3292
+ # Logs en tiempo real
3293
+ docker compose logs -f api
3294
+
3295
+ # Ejecutar tests
3296
+ docker compose exec api pytest -v
3297
+
3298
+ # Aplicar migraciones
3299
+ docker compose exec api alembic upgrade head
3300
+
3301
+ # Acceder a shell de Python
3302
+ docker compose exec api python
3303
+
3304
+ # Acceder a PostgreSQL
3305
+ docker compose exec db psql -U user -d auth
3306
+
3307
+ # Detener todo
3308
+ docker compose down
3309
+
3310
+ # Limpiar volúmenes (cuidado!)
3311
+ docker compose down -v
3312
+ ```
3313
+
3314
+ ---
3315
+
3316
+ ## 📋 Checklist Final
3317
+
3318
+ Antes de considerar la feature completa:
3319
+
3320
+ - [ ] Todos los tests pasan (100% coverage en servicios críticos)
3321
+ - [ ] Endpoints documentados en OpenAPI (`/docs`)
3322
+ - [ ] Variables sensibles en `.env` (no hardcoded)
3323
+ - [ ] Logs de seguridad para login fallido
3324
+ - [ ] Rate limiting en endpoints de auth (opcional)
3325
+ - [ ] CORS configurado correctamente
3326
+ - [ ] Docker Compose funciona en máquina limpia
3327
+ - [ ] README actualizado con instrucciones
3328
+ ```
3329
+
3330
+ ---
3331
+
3332
+ ## 🔧 Scripts Universales
3333
+
3334
+ ### scripts/test.sh (Detecta Stack)
3335
+
3336
+ ```bash
3337
+ #!/bin/bash
3338
+ # scripts/test.sh - Detecta stack y corre tests
3339
+ set -e
3340
+
3341
+ echo "🔍 Detectando tech stack..."
3342
+
3343
+ if [ -f "package.json" ]; then
3344
+ echo "📦 Bun detectado"
3345
+ bun test
3346
+ elif [ -f "pyproject.toml" ]; then
3347
+ echo "🐍 Python (uv) detectado"
3348
+ uv run pytest
3349
+ elif [ -f "go.mod" ]; then
3350
+ echo "🐹 Go detectado"
3351
+ go test -v ./...
3352
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
3353
+ echo "☕ Java (Gradle) detectado"
3354
+ ./gradlew test
3355
+ elif [ -f "pom.xml" ]; then
3356
+ echo "☕ Java (Maven) detectado"
3357
+ ./mvnw test
3358
+ elif [ -f "Cargo.toml" ]; then
3359
+ echo "🦀 Rust detectado"
3360
+ cargo test
3361
+ else
3362
+ echo "❌ Stack no reconocido"
3363
+ exit 1
3364
+ fi
3365
+
3366
+ echo "✅ Tests completados!"
3367
+ ```
3368
+
3369
+ ### scripts/lint.sh (Usa Biome, Spotless, golangci-lint, etc.)
3370
+
3371
+ ```bash
3372
+ #!/bin/bash
3373
+ # scripts/lint.sh
3374
+ set -e
3375
+
3376
+ echo "🔍 Detectando linter..."
3377
+
3378
+ if [ -f "biome.json" ]; then
3379
+ echo "🎨 Biome detectado"
3380
+ bun run check
3381
+ elif [ -f "pyproject.toml" ] && grep -q "ruff" pyproject.toml; then
3382
+ echo "🐍 Ruff detectado"
3383
+ uv run ruff check .
3384
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
3385
+ echo "☕ Spotless (Java/Gradle) detectado"
3386
+ ./gradlew spotlessCheck
3387
+ elif [ -f ".golangci.yml" ]; then
3388
+ echo "🐹 golangci-lint detectado"
3389
+ golangci-lint run
3390
+ elif [ -f "rustfmt.toml" ]; then
3391
+ echo "🦀 Rustfmt detectado"
3392
+ cargo fmt --check
3393
+ else
3394
+ echo "⚠️ No linter configurado"
3395
+ fi
3396
+
3397
+ echo "✅ Lint completado!"
3398
+ ```
3399
+
3400
+ ### scripts/format.sh (Formatea código automáticamente)
3401
+
3402
+ ```bash
3403
+ #!/bin/bash
3404
+ # scripts/format.sh
3405
+ set -e
3406
+
3407
+ echo "🎨 Formateando código..."
3408
+
3409
+ if [ -f "biome.json" ]; then
3410
+ echo "📦 Biome"
3411
+ bun run format
3412
+ elif [ -f "pyproject.toml" ] && grep -q "ruff" pyproject.toml; then
3413
+ echo "🐍 Ruff"
3414
+ uv run ruff format .
3415
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
3416
+ echo "☕ Spotless"
3417
+ ./gradlew spotlessApply
3418
+ elif [ -f "go.mod" ]; then
3419
+ echo "🐹 gofmt + goimports"
3420
+ go fmt ./...
3421
+ if command -v goimports &> /dev/null; then
3422
+ goimports -w .
3423
+ fi
3424
+ elif [ -f "Cargo.toml" ]; then
3425
+ echo "🦀 rustfmt"
3426
+ cargo fmt
3427
+ fi
3428
+
3429
+ echo "✅ Formato aplicado!"
3430
+ ```
3431
+
3432
+ ### scripts/dev.sh (Levanta Dev Server)
3433
+
3434
+ ```bash
3435
+ #!/bin/bash
3436
+ # scripts/dev.sh
3437
+ set -e
3438
+
3439
+ if [ -f "docker-compose.yml" ]; then
3440
+ echo "🐳 Levantando Docker Compose..."
3441
+ docker compose up
3442
+ elif [ -f "package.json" ]; then
3443
+ echo "📦 Iniciando dev server (Bun)..."
3444
+ bun run dev
3445
+ elif [ -f "pyproject.toml" ]; then
3446
+ echo "🐍 Iniciando dev server (uv)..."
3447
+ uv run uvicorn app.main:app --reload
3448
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
3449
+ echo "☕ Iniciando dev server (Gradle)..."
3450
+ ./gradlew bootRun
3451
+ elif [ -f "go.mod" ]; then
3452
+ echo "🐹 Iniciando dev server (Go)..."
3453
+ if command -v air &> /dev/null; then
3454
+ air
3455
+ else
3456
+ go run cmd/api/main.go
3457
+ fi
3458
+ else
3459
+ echo "❌ No se encontró configuración de dev"
3460
+ exit 1
3461
+ fi
3462
+ ```
3463
+
3464
+ ### scripts/build.sh (Build optimizado por stack)
3465
+
3466
+ ```bash
3467
+ #!/bin/bash
3468
+ # scripts/build.sh
3469
+ set -e
3470
+
3471
+ echo "🔨 Building..."
3472
+
3473
+ if [ -f "package.json" ]; then
3474
+ echo "📦 Bun build"
3475
+ bun run build
3476
+ elif [ -f "pyproject.toml" ]; then
3477
+ echo "🐍 Python no requiere build (interpretado)"
3478
+ elif [ -f "build.gradle.kts" ] || [ -f "build.gradle" ]; then
3479
+ echo "☕ Gradle build"
3480
+ ./gradlew build -x test
3481
+ elif [ -f "go.mod" ]; then
3482
+ echo "🐹 Go build"
3483
+ go build -o bin/api ./cmd/api
3484
+ elif [ -f "Cargo.toml" ]; then
3485
+ echo "🦀 Rust build"
3486
+ cargo build --release
3487
+ fi
3488
+
3489
+ echo "✅ Build completado!"
3490
+ ```
3491
+
3492
+ ---
3493
+