FastAPI-fastkit 1.3.0__py3-none-any.whl → 1.4.1__py3-none-any.whl

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 (338) hide show
  1. fastapi_fastkit/__init__.py +1 -1
  2. fastapi_fastkit/backend/inspection/__init__.py +26 -0
  3. fastapi_fastkit/backend/inspection/checks.py +349 -0
  4. fastapi_fastkit/backend/inspection/consistency.py +125 -0
  5. fastapi_fastkit/backend/inspection/context.py +71 -0
  6. fastapi_fastkit/backend/inspection/core.py +351 -0
  7. fastapi_fastkit/backend/inspection/docker.py +320 -0
  8. fastapi_fastkit/backend/inspection/freshness.py +145 -0
  9. fastapi_fastkit/backend/inspection/fsutils.py +139 -0
  10. fastapi_fastkit/backend/inspection/lint.py +103 -0
  11. fastapi_fastkit/backend/inspection/report.py +58 -0
  12. fastapi_fastkit/backend/inspection/smoke.py +381 -0
  13. fastapi_fastkit/backend/inspection/strategies.py +367 -0
  14. fastapi_fastkit/backend/inspector.py +18 -1400
  15. fastapi_fastkit/backend/interactive/__init__.py +6 -0
  16. fastapi_fastkit/backend/interactive/config_builder.py +45 -63
  17. fastapi_fastkit/backend/interactive/prompts.py +155 -6
  18. fastapi_fastkit/backend/interactive/selectors.py +18 -2
  19. fastapi_fastkit/backend/main.py +887 -99
  20. fastapi_fastkit/backend/package_managers/base.py +172 -0
  21. fastapi_fastkit/backend/package_managers/factory.py +5 -4
  22. fastapi_fastkit/backend/package_managers/pdm_manager.py +29 -82
  23. fastapi_fastkit/backend/package_managers/pip_manager.py +31 -85
  24. fastapi_fastkit/backend/package_managers/poetry_manager.py +70 -110
  25. fastapi_fastkit/backend/package_managers/uv_manager.py +43 -112
  26. fastapi_fastkit/backend/project_builder/__init__.py +8 -1
  27. fastapi_fastkit/backend/project_builder/config_generator.py +806 -450
  28. fastapi_fastkit/backend/project_builder/config_schema.py +384 -0
  29. fastapi_fastkit/backend/project_builder/dependency_collector.py +105 -66
  30. fastapi_fastkit/backend/project_builder/preset_layout.py +254 -28
  31. fastapi_fastkit/backend/scaffolder.py +578 -0
  32. fastapi_fastkit/backend/transducer.py +154 -22
  33. fastapi_fastkit/cli.py +434 -311
  34. fastapi_fastkit/core/settings.py +234 -45
  35. fastapi_fastkit/fastapi_project_template/README.md +26 -10
  36. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/README.md-tpl +3 -0
  37. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/pyproject.toml-tpl +21 -22
  38. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/requirements.txt-tpl +39 -36
  39. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/api.py-tpl +3 -0
  40. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/api/routes/items.py-tpl +1 -2
  41. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/core/config.py-tpl +5 -6
  42. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/crud/items.py-tpl +1 -2
  43. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/main.py-tpl +9 -1
  44. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/src/schemas/items.py-tpl +1 -2
  45. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/tests/conftest.py-tpl +0 -1
  46. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.env-tpl +21 -0
  47. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/.gitignore-tpl +33 -0
  48. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/Dockerfile-tpl +18 -0
  49. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/README.md-tpl +210 -0
  50. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/alembic.ini-tpl +119 -0
  51. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/pyproject.toml-tpl +86 -0
  52. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/requirements.txt-tpl +23 -0
  53. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/format.sh-tpl +5 -0
  54. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/lint.sh-tpl +6 -0
  55. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/run-server.sh-tpl +8 -0
  56. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/scripts/test.sh-tpl +6 -0
  57. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/__init__.py-tpl +0 -0
  58. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/__init__.py-tpl +0 -0
  59. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/README-tpl +1 -0
  60. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/env.py-tpl +51 -0
  61. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/script.py.mako-tpl +26 -0
  62. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/alembic/versions/0001_initial_auth_schema.py-tpl +62 -0
  63. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/__init__.py-tpl +0 -0
  64. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/deps.py-tpl +91 -0
  65. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/health.py-tpl +11 -0
  66. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/api/router.py-tpl +17 -0
  67. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/__init__.py-tpl +0 -0
  68. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/config.py-tpl +64 -0
  69. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/core/security.py-tpl +100 -0
  70. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/__init__.py-tpl +0 -0
  71. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/db/session.py-tpl +36 -0
  72. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/__init__.py-tpl +0 -0
  73. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/__init__.py-tpl +0 -0
  74. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/models.py-tpl +25 -0
  75. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/repository.py-tpl +41 -0
  76. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/router.py-tpl +82 -0
  77. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/schemas.py-tpl +14 -0
  78. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/auth/service.py-tpl +65 -0
  79. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/__init__.py-tpl +0 -0
  80. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/models.py-tpl +35 -0
  81. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/repository.py-tpl +33 -0
  82. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/router.py-tpl +71 -0
  83. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/schemas.py-tpl +29 -0
  84. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/domains/users/service.py-tpl +55 -0
  85. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/src/app/main.py-tpl +69 -0
  86. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/template-config.yml-tpl +16 -0
  87. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/__init__.py-tpl +0 -0
  88. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/conftest.py-tpl +73 -0
  89. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_auth.py-tpl +201 -0
  90. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_health.py-tpl +15 -0
  91. fastapi_fastkit/fastapi_project_template/fastapi-auth-jwt/tests/test_users.py-tpl +77 -0
  92. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/pyproject.toml-tpl +21 -22
  93. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/requirements.txt-tpl +39 -36
  94. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/api.py-tpl +3 -0
  95. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/api/routes/items.py-tpl +3 -3
  96. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/core/config.py-tpl +5 -6
  97. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/crud/items.py-tpl +1 -2
  98. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/helper/pagination.py-tpl +8 -8
  99. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/main.py-tpl +9 -0
  100. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/base.py-tpl +1 -1
  101. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/src/schemas/items.py-tpl +1 -2
  102. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/tests/conftest.py-tpl +0 -1
  103. fastapi_fastkit/fastapi_project_template/fastapi-default/pyproject.toml-tpl +18 -19
  104. fastapi_fastkit/fastapi_project_template/fastapi-default/requirements.txt-tpl +37 -34
  105. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/api.py-tpl +3 -0
  106. fastapi_fastkit/fastapi_project_template/fastapi-default/src/api/routes/items.py-tpl +1 -2
  107. fastapi_fastkit/fastapi_project_template/fastapi-default/src/core/config.py-tpl +5 -6
  108. fastapi_fastkit/fastapi_project_template/fastapi-default/src/crud/items.py-tpl +1 -2
  109. fastapi_fastkit/fastapi_project_template/fastapi-default/src/main.py-tpl +9 -1
  110. fastapi_fastkit/fastapi_project_template/fastapi-default/src/schemas/items.py-tpl +1 -2
  111. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/conftest.py-tpl +2 -3
  112. fastapi_fastkit/fastapi_project_template/fastapi-default/tests/test_items.py-tpl +0 -2
  113. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/Dockerfile-tpl +1 -1
  114. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/README.md-tpl +3 -0
  115. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/pyproject.toml-tpl +21 -22
  116. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/requirements.txt-tpl +41 -36
  117. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/api.py-tpl +3 -0
  118. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/api/routes/items.py-tpl +1 -2
  119. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/core/config.py-tpl +5 -6
  120. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/crud/items.py-tpl +1 -2
  121. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/main.py-tpl +9 -1
  122. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/src/schemas/items.py-tpl +1 -2
  123. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/conftest.py-tpl +2 -3
  124. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/tests/test_items.py-tpl +0 -2
  125. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/pyproject.toml-tpl +13 -14
  126. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/requirements.txt-tpl +36 -10
  127. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/api/router.py-tpl +3 -0
  128. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/core/config.py-tpl +4 -4
  129. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/db/memory.py-tpl +4 -3
  130. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/repository.py-tpl +4 -5
  131. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/router.py-tpl +2 -3
  132. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/domains/items/service.py-tpl +2 -3
  133. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/src/app/main.py-tpl +3 -0
  134. fastapi_fastkit/fastapi_project_template/fastapi-domain-starter/tests/conftest.py-tpl +0 -1
  135. fastapi_fastkit/fastapi_project_template/fastapi-empty/pyproject.toml-tpl +14 -15
  136. fastapi_fastkit/fastapi_project_template/fastapi-empty/requirements.txt-tpl +36 -10
  137. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/core/config.py-tpl +5 -6
  138. fastapi_fastkit/fastapi_project_template/fastapi-empty/src/main.py-tpl +3 -1
  139. fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/conftest.py-tpl +0 -1
  140. fastapi_fastkit/fastapi_project_template/fastapi-empty/tests/test_main.py-tpl +0 -1
  141. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.env-tpl +15 -0
  142. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/.gitignore-tpl +31 -0
  143. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/Dockerfile-tpl +18 -0
  144. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/README.md-tpl +193 -0
  145. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/pyproject.toml-tpl +76 -0
  146. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/requirements.txt-tpl +15 -0
  147. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/chat.sh-tpl +10 -0
  148. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/format.sh-tpl +5 -0
  149. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/lint.sh-tpl +6 -0
  150. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/run-server.sh-tpl +8 -0
  151. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/scripts/test.sh-tpl +6 -0
  152. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/__init__.py-tpl +0 -0
  153. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/__init__.py-tpl +0 -0
  154. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/__init__.py-tpl +0 -0
  155. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/chat.py-tpl +62 -0
  156. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/deps.py-tpl +23 -0
  157. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/health.py-tpl +11 -0
  158. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/api/router.py-tpl +13 -0
  159. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/__init__.py-tpl +0 -0
  160. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/core/config.py-tpl +67 -0
  161. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/__init__.py-tpl +0 -0
  162. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/agent.py-tpl +136 -0
  163. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/client.py-tpl +30 -0
  164. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/llm/tools.py-tpl +131 -0
  165. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/main.py-tpl +53 -0
  166. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/__init__.py-tpl +0 -0
  167. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/base.py-tpl +27 -0
  168. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/memory/in_memory.py-tpl +32 -0
  169. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/__init__.py-tpl +0 -0
  170. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/src/app/schemas/chat.py-tpl +46 -0
  171. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/template-config.yml-tpl +16 -0
  172. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/__init__.py-tpl +0 -0
  173. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/conftest.py-tpl +158 -0
  174. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_chat.py-tpl +160 -0
  175. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_health.py-tpl +12 -0
  176. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_memory.py-tpl +38 -0
  177. fastapi_fastkit/fastapi_project_template/fastapi-llm-agent/tests/test_tools.py-tpl +37 -0
  178. fastapi_fastkit/fastapi_project_template/fastapi-mcp/.env-tpl +1 -1
  179. fastapi_fastkit/fastapi_project_template/fastapi-mcp/README.md-tpl +2 -2
  180. fastapi_fastkit/fastapi_project_template/fastapi-mcp/pyproject.toml-tpl +25 -26
  181. fastapi_fastkit/fastapi_project_template/fastapi-mcp/requirements.txt-tpl +65 -40
  182. fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.cfg-tpl +2 -3
  183. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/api.py-tpl +3 -0
  184. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/auth.py-tpl +13 -14
  185. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/api/routes/items.py-tpl +3 -4
  186. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/auth/dependencies.py-tpl +6 -7
  187. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/core/config.py-tpl +5 -6
  188. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/main.py-tpl +4 -1
  189. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/router.py-tpl +3 -5
  190. fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/schemas/items.py-tpl +6 -7
  191. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/conftest.py-tpl +1 -1
  192. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_auth.py-tpl +0 -1
  193. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_items.py-tpl +0 -1
  194. fastapi_fastkit/fastapi_project_template/fastapi-mcp/tests/test_mcp.py-tpl +0 -1
  195. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/.env-tpl +2 -0
  196. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/Dockerfile-tpl +1 -1
  197. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/pyproject.toml-tpl +22 -23
  198. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/requirements.txt-tpl +44 -41
  199. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/env.py-tpl +1 -3
  200. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/alembic/versions/bedcdc35b64a_first_alembic.py-tpl +5 -6
  201. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/api.py-tpl +2 -0
  202. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/api/routes/items.py-tpl +2 -4
  203. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/config.py-tpl +1 -2
  204. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/core/db.py-tpl +1 -1
  205. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/crud/items.py-tpl +4 -6
  206. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/main.py-tpl +9 -0
  207. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/src/schemas/items.py-tpl +4 -5
  208. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/conftest.py-tpl +1 -5
  209. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/tests/test_items.py-tpl +0 -2
  210. fastapi_fastkit/fastapi_project_template/fastapi-single-module/.env-tpl +1 -0
  211. fastapi_fastkit/fastapi_project_template/fastapi-single-module/.gitignore-tpl +30 -0
  212. fastapi_fastkit/fastapi_project_template/fastapi-single-module/pyproject.toml-tpl +3 -4
  213. fastapi_fastkit/fastapi_project_template/fastapi-single-module/requirements.txt-tpl +26 -6
  214. fastapi_fastkit/fastapi_project_template/fastapi-single-module/src/main.py-tpl +3 -0
  215. fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/__init__.py-tpl +0 -0
  216. fastapi_fastkit/fastapi_project_template/fastapi-single-module/tests/conftest.py-tpl +0 -1
  217. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.env-tpl +7 -0
  218. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/.gitignore-tpl +35 -0
  219. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/Dockerfile-tpl +18 -0
  220. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/README.md-tpl +166 -0
  221. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/alembic.ini-tpl +44 -0
  222. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/pyproject.toml-tpl +82 -0
  223. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/requirements.txt-tpl +21 -0
  224. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/format.sh-tpl +5 -0
  225. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/lint.sh-tpl +6 -0
  226. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/migrate.sh-tpl +7 -0
  227. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/run-server.sh-tpl +8 -0
  228. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/scripts/test.sh-tpl +6 -0
  229. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/__init__.py-tpl +0 -0
  230. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/__init__.py-tpl +0 -0
  231. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/README-tpl +9 -0
  232. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/env.py-tpl +72 -0
  233. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/script.py.mako-tpl +27 -0
  234. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/alembic/versions/0001_create_items_table.py-tpl +38 -0
  235. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/__init__.py-tpl +0 -0
  236. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/health.py-tpl +11 -0
  237. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/api/router.py-tpl +15 -0
  238. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/__init__.py-tpl +0 -0
  239. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/core/config.py-tpl +62 -0
  240. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/__init__.py-tpl +0 -0
  241. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/base.py-tpl +62 -0
  242. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/crud/pagination.py-tpl +21 -0
  243. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/__init__.py-tpl +0 -0
  244. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/base.py-tpl +12 -0
  245. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/db/session.py-tpl +50 -0
  246. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/__init__.py-tpl +0 -0
  247. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/__init__.py-tpl +0 -0
  248. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/crud.py-tpl +26 -0
  249. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/models.py-tpl +70 -0
  250. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/domains/items/router.py-tpl +69 -0
  251. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/src/app/main.py-tpl +43 -0
  252. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/template-config.yml-tpl +16 -0
  253. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/__init__.py-tpl +0 -0
  254. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/conftest.py-tpl +60 -0
  255. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_crud_base.py-tpl +43 -0
  256. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_health.py-tpl +12 -0
  257. fastapi_fastkit/fastapi_project_template/fastapi-sqlmodel/tests/test_items.py-tpl +110 -0
  258. fastapi_fastkit/fastapi_project_template/modules/api/routes/new_route.py-tpl +2 -2
  259. fastapi_fastkit/fragments/README.md +90 -0
  260. fastapi_fastkit/fragments/auth/fastapi_users.py.j2 +8 -0
  261. fastapi_fastkit/fragments/auth/jwt.py.j2 +44 -0
  262. fastapi_fastkit/fragments/auth/oauth2.py.j2 +105 -0
  263. fastapi_fastkit/fragments/auth/session.py.j2 +67 -0
  264. fastapi_fastkit/fragments/db/mongodb.py.j2 +19 -0
  265. fastapi_fastkit/fragments/db/redis.py.j2 +26 -0
  266. fastapi_fastkit/fragments/db/sqlalchemy.py.j2 +45 -0
  267. fastapi_fastkit/fragments/docker/docker_compose.j2 +84 -0
  268. fastapi_fastkit/fragments/docker/dockerfile.j2 +19 -0
  269. fastapi_fastkit/fragments/features/cache.py.j2 +26 -0
  270. fastapi_fastkit/fragments/features/pagination.py.j2 +31 -0
  271. fastapi_fastkit/fragments/features/tasks_celery.py.j2 +50 -0
  272. fastapi_fastkit/fragments/features/tasks_dramatiq.py.j2 +59 -0
  273. fastapi_fastkit/fragments/features/websocket.py.j2 +66 -0
  274. fastapi_fastkit/fragments/header.j2 +4 -0
  275. fastapi_fastkit/fragments/logging/structured.py.j2 +88 -0
  276. fastapi_fastkit/fragments/main/imports/async_tasks.j2 +1 -0
  277. fastapi_fastkit/fragments/main/imports/caching.j2 +5 -0
  278. fastapi_fastkit/fragments/main/imports/fastapi_users.j2 +1 -0
  279. fastapi_fastkit/fragments/main/imports/jwt.j2 +1 -0
  280. fastapi_fastkit/fragments/main/imports/loguru.j2 +1 -0
  281. fastapi_fastkit/fragments/main/imports/mongodb.j2 +1 -0
  282. fastapi_fastkit/fragments/main/imports/oauth2.j2 +4 -0
  283. fastapi_fastkit/fragments/main/imports/opentelemetry.j2 +6 -0
  284. fastapi_fastkit/fragments/main/imports/pagination.j2 +3 -0
  285. fastapi_fastkit/fragments/main/imports/prometheus.j2 +1 -0
  286. fastapi_fastkit/fragments/main/imports/rate_limiting.j2 +3 -0
  287. fastapi_fastkit/fragments/main/imports/session_auth.j2 +4 -0
  288. fastapi_fastkit/fragments/main/imports/sqlalchemy.j2 +2 -0
  289. fastapi_fastkit/fragments/main/imports/structured_logging.j2 +1 -0
  290. fastapi_fastkit/fragments/main/imports/websocket.j2 +1 -0
  291. fastapi_fastkit/fragments/main/lifespan/caching.j2 +7 -0
  292. fastapi_fastkit/fragments/main/lifespan/mongodb.j2 +2 -0
  293. fastapi_fastkit/fragments/main/lifespan/prometheus.j2 +2 -0
  294. fastapi_fastkit/fragments/main/lifespan/sqlalchemy.j2 +2 -0
  295. fastapi_fastkit/fragments/main/setup/async_tasks.j2 +1 -0
  296. fastapi_fastkit/fragments/main/setup/caching.j2 +1 -0
  297. fastapi_fastkit/fragments/main/setup/cors.j2 +8 -0
  298. fastapi_fastkit/fragments/main/setup/oauth2.j2 +3 -0
  299. fastapi_fastkit/fragments/main/setup/opentelemetry.j2 +19 -0
  300. fastapi_fastkit/fragments/main/setup/pagination.j2 +2 -0
  301. fastapi_fastkit/fragments/main/setup/rate_limiting.j2 +3 -0
  302. fastapi_fastkit/fragments/main/setup/session_auth.j2 +6 -0
  303. fastapi_fastkit/fragments/main/setup/structured_logging.j2 +2 -0
  304. fastapi_fastkit/fragments/main/setup/websocket.j2 +1 -0
  305. fastapi_fastkit/fragments/main.py.j2 +57 -0
  306. fastapi_fastkit/fragments/migrations/alembic_ini.j2 +42 -0
  307. fastapi_fastkit/fragments/migrations/env.py.j2 +76 -0
  308. fastapi_fastkit/fragments/migrations/initial_revision.py.j2 +27 -0
  309. fastapi_fastkit/fragments/migrations/migrate_sh.j2 +34 -0
  310. fastapi_fastkit/fragments/migrations/script.py.mako.j2 +26 -0
  311. fastapi_fastkit/fragments/tasks/celery_worker.py.j2 +49 -0
  312. fastapi_fastkit/fragments/tasks/dramatiq_worker.py.j2 +41 -0
  313. fastapi_fastkit/fragments/test/factories.py.j2 +68 -0
  314. fastapi_fastkit/fragments/test/pytest_ini.j2 +16 -0
  315. fastapi_fastkit/fragments/test/test_factories.py.j2 +27 -0
  316. fastapi_fastkit/fragments/test/test_main.py.j2 +46 -0
  317. fastapi_fastkit/fragments/tooling/devcontainer.j2 +26 -0
  318. fastapi_fastkit/fragments/tooling/github_actions.j2 +37 -0
  319. fastapi_fastkit/fragments/tooling/makefile.j2 +40 -0
  320. fastapi_fastkit/fragments/tooling/pre_commit.j2 +36 -0
  321. fastapi_fastkit/fragments/tooling/ruff_toml.j2 +16 -0
  322. fastapi_fastkit/utils/config_file.py +263 -0
  323. fastapi_fastkit/utils/main.py +38 -0
  324. {fastapi_fastkit-1.3.0.dist-info → fastapi_fastkit-1.4.1.dist-info}/METADATA +49 -6
  325. fastapi_fastkit-1.4.1.dist-info/RECORD +484 -0
  326. {fastapi_fastkit-1.3.0.dist-info → fastapi_fastkit-1.4.1.dist-info}/WHEEL +1 -1
  327. fastapi_fastkit/fastapi_project_template/fastapi-async-crud/setup.py-tpl +0 -25
  328. fastapi_fastkit/fastapi_project_template/fastapi-custom-response/setup.py-tpl +0 -27
  329. fastapi_fastkit/fastapi_project_template/fastapi-default/setup.py-tpl +0 -22
  330. fastapi_fastkit/fastapi_project_template/fastapi-dockerized/setup.py-tpl +0 -22
  331. fastapi_fastkit/fastapi_project_template/fastapi-empty/setup.py-tpl +0 -22
  332. fastapi_fastkit/fastapi_project_template/fastapi-mcp/setup.py-tpl +0 -51
  333. fastapi_fastkit/fastapi_project_template/fastapi-psql-orm/setup.py-tpl +0 -25
  334. fastapi_fastkit/fastapi_project_template/fastapi-single-module/setup.py-tpl +0 -17
  335. fastapi_fastkit-1.3.0.dist-info/RECORD +0 -287
  336. /fastapi_fastkit/fastapi_project_template/fastapi-mcp/src/{mcp → mcp_server}/__init__.py-tpl +0 -0
  337. {fastapi_fastkit-1.3.0.dist-info → fastapi_fastkit-1.4.1.dist-info}/entry_points.txt +0 -0
  338. {fastapi_fastkit-1.3.0.dist-info → fastapi_fastkit-1.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -16,10 +16,13 @@ from .prompts import (
16
16
  prompt_custom_packages,
17
17
  prompt_database_selection,
18
18
  prompt_deployment_options,
19
+ prompt_logging_selection,
20
+ prompt_migrations_selection,
19
21
  prompt_monitoring_selection,
20
22
  prompt_package_manager_selection,
21
23
  prompt_template_selection,
22
24
  prompt_testing_selection,
25
+ prompt_tooling_selection,
23
26
  prompt_utilities_selection,
24
27
  )
25
28
  from .selectors import confirm_selections, multi_select_prompt, render_selection_table
@@ -37,6 +40,9 @@ __all__ = [
37
40
  "prompt_database_selection",
38
41
  "prompt_authentication_selection",
39
42
  "prompt_additional_features",
43
+ "prompt_logging_selection",
44
+ "prompt_migrations_selection",
45
+ "prompt_tooling_selection",
40
46
  "prompt_testing_selection",
41
47
  "prompt_deployment_options",
42
48
  "prompt_custom_packages",
@@ -10,6 +10,8 @@ from typing import Any, Dict, List
10
10
 
11
11
  from fastapi_fastkit.utils.main import console, print_warning
12
12
 
13
+ from ..project_builder.config_schema import normalize_project_config
14
+ from ..project_builder.dependency_collector import DependencyCollector
13
15
  from .prompts import (
14
16
  prompt_additional_features,
15
17
  prompt_architecture_preset,
@@ -107,6 +109,32 @@ class InteractiveConfigBuilder:
107
109
  features = prompt_additional_features(self.settings)
108
110
  self.config.update(features)
109
111
 
112
+ def build_config_from_mapping(self, config: Dict[str, Any]) -> Dict[str, Any]:
113
+ """
114
+ Complete a configuration that came from a file instead of prompts.
115
+
116
+ ``fastkit init --config`` accepts a hand-written file that lists only
117
+ feature selections; running them back through the same dependency
118
+ collection the interactive flow uses keeps both entry points in
119
+ agreement about which packages a selection implies.
120
+
121
+ The mapping is normalised first, so a file that spells an axis
122
+ differently than the prompts do (a ``{"type": ...}`` block for a
123
+ single-select axis, say) still resolves to the catalog choice the
124
+ rest of the pipeline reads.
125
+
126
+ Args:
127
+ config: Configuration mapping (interactive builder shape)
128
+
129
+ Returns:
130
+ The normalised mapping with ``all_dependencies`` filled in
131
+
132
+ Raises:
133
+ ConfigSchemaError: If the mapping holds an unknown key or choice
134
+ """
135
+ self.config = normalize_project_config(config, self.settings)
136
+ return self._build_final_config()
137
+
110
138
  def _build_final_config(self) -> Dict[str, Any]:
111
139
  """
112
140
  Build and validate final configuration.
@@ -114,6 +142,10 @@ class InteractiveConfigBuilder:
114
142
  Returns:
115
143
  Complete configuration dictionary with collected dependencies
116
144
  """
145
+ # Normalise before anything reads the selections, so an interactive
146
+ # session and a ``--config`` file hand the pipeline the same shape.
147
+ self.config = normalize_project_config(self.config, self.settings)
148
+
117
149
  # Collect all dependencies
118
150
  all_deps = self._collect_all_dependencies()
119
151
 
@@ -126,74 +158,24 @@ class InteractiveConfigBuilder:
126
158
  """
127
159
  Collect all dependencies from selected features.
128
160
 
161
+ Delegates to :class:`DependencyCollector`, which walks every axis in
162
+ ``PACKAGE_CATALOG`` generically. Duplicating the walk here meant a
163
+ newly added axis (logging, migrations, tooling) was silently skipped
164
+ for interactive projects while ``fastkit init --config`` picked it up.
165
+
129
166
  Returns:
130
167
  Deduplicated list of all package dependencies
131
168
  """
132
- dependencies = set()
133
-
134
- # Always add base FastAPI dependencies
135
- dependencies.update(["fastapi", "uvicorn", "pydantic", "pydantic-settings"])
136
-
137
- # Database dependencies
138
- db_info = self.config.get("database", {})
139
- if isinstance(db_info, dict) and db_info.get("packages"):
140
- dependencies.update(db_info["packages"])
141
-
142
- # Authentication dependencies
143
- auth_type = self.config.get("authentication", "None")
144
- if auth_type != "None":
145
- auth_packages = self.settings.PACKAGE_CATALOG["authentication"].get(
146
- auth_type, []
147
- )
148
- dependencies.update(auth_packages)
149
-
150
- # Async tasks dependencies
151
- tasks_type = self.config.get("async_tasks", "None")
152
- if tasks_type != "None":
153
- task_packages = self.settings.PACKAGE_CATALOG["async_tasks"].get(
154
- tasks_type, []
155
- )
156
- dependencies.update(task_packages)
157
-
158
- # Caching dependencies
159
- cache_type = self.config.get("caching", "None")
160
- if cache_type != "None":
161
- cache_packages = self.settings.PACKAGE_CATALOG["caching"].get(
162
- cache_type, []
163
- )
164
- dependencies.update(cache_packages)
165
-
166
- # Monitoring dependencies
167
- monitoring_type = self.config.get("monitoring", "None")
168
- if monitoring_type != "None":
169
- monitoring_packages = self.settings.PACKAGE_CATALOG["monitoring"].get(
170
- monitoring_type, []
171
- )
172
- dependencies.update(monitoring_packages)
173
-
174
- # Testing dependencies
175
- testing_type = self.config.get("testing", "None")
176
- if testing_type != "None":
177
- testing_packages = self.settings.PACKAGE_CATALOG["testing"].get(
178
- testing_type, []
179
- )
180
- dependencies.update(testing_packages)
181
-
182
- # Utilities dependencies
183
- utilities = self.config.get("utilities", [])
184
- for util in utilities:
185
- if util in self.settings.PACKAGE_CATALOG["utilities"]:
186
- util_packages = self.settings.PACKAGE_CATALOG["utilities"][util]
187
- dependencies.update(util_packages)
188
-
189
- # Custom packages
190
- custom_packages = self.config.get("custom_packages", [])
169
+ config = dict(self.config)
170
+
171
+ # Custom packages are free-form user input, so they are sanitized
172
+ # before the collector merges them with the catalog-derived set.
173
+ custom_packages = config.get("custom_packages", [])
191
174
  if custom_packages:
192
- sanitized = sanitize_custom_packages(custom_packages)
193
- dependencies.update(sanitized)
175
+ config["custom_packages"] = sanitize_custom_packages(custom_packages)
194
176
 
195
- # Convert to sorted list
196
- return sorted(list(dependencies))
177
+ collector = DependencyCollector(self.settings)
178
+ return collector.collect_from_config(config)
197
179
 
198
180
  def get_config(self) -> Dict[str, Any]:
199
181
  """
@@ -16,6 +16,14 @@ from typing import Any, Dict, List, Optional, cast
16
16
 
17
17
  import click
18
18
 
19
+ from fastapi_fastkit.backend.project_builder.config_generator import SQL_DATABASES
20
+ from fastapi_fastkit.core.settings import (
21
+ NONE_CHOICE,
22
+ FeatureAxis,
23
+ LoggingChoice,
24
+ MigrationsChoice,
25
+ ToolingChoice,
26
+ )
19
27
  from fastapi_fastkit.utils.main import console, print_error
20
28
 
21
29
  from .selectors import render_selection_table
@@ -103,7 +111,7 @@ def prompt_architecture_preset(settings: Any) -> str:
103
111
  }
104
112
  render_selection_table("Architecture Presets", display_options)
105
113
 
106
- preset_ids = list(presets.keys())
114
+ preset_ids: List[str] = list(presets.keys())
107
115
  default_idx = preset_ids.index(default_id) + 1
108
116
 
109
117
  choice = click.prompt(
@@ -112,7 +120,8 @@ def prompt_architecture_preset(settings: Any) -> str:
112
120
  default=default_idx,
113
121
  )
114
122
 
115
- return cast(str, preset_ids[choice - 1])
123
+ result: str = preset_ids[choice - 1]
124
+ return result
116
125
 
117
126
 
118
127
  def prompt_template_selection(settings: Any) -> Optional[str]:
@@ -161,11 +170,10 @@ def prompt_template_selection(settings: Any) -> Optional[str]:
161
170
  default=1,
162
171
  )
163
172
 
164
- selected_key = list(options.keys())[choice - 1]
173
+ template_keys: List[str] = list(options.keys())
174
+ selected_key: str = template_keys[choice - 1]
165
175
 
166
- return cast(
167
- Optional[str], selected_key if selected_key != "Empty Project" else None
168
- )
176
+ return selected_key if selected_key != "Empty Project" else None
169
177
 
170
178
 
171
179
  def prompt_database_selection(settings: Any) -> Dict[str, Any]:
@@ -436,6 +444,137 @@ def prompt_utilities_selection(settings: Any) -> List[str]:
436
444
  return []
437
445
 
438
446
 
447
+ def prompt_logging_selection(settings: Any) -> str:
448
+ """
449
+ Prompt for the application logging format.
450
+
451
+ Args:
452
+ settings: FastkitConfig instance
453
+
454
+ Returns:
455
+ Logging style name
456
+ """
457
+ console.print("\n[bold cyan]🪵 Logging Format[/bold cyan]")
458
+ console.print("[dim]Choose how the application emits its logs[/dim]\n")
459
+
460
+ logging_catalog = settings.PACKAGE_CATALOG[FeatureAxis.LOGGING]
461
+ descriptions = {
462
+ LoggingChoice.STRUCTURED: (
463
+ "JSON logs + X-Request-ID correlation middleware (stdlib only)"
464
+ ),
465
+ LoggingChoice.NONE: "Uvicorn's default plain-text logging",
466
+ }
467
+ options = {
468
+ name: descriptions.get(name, f"Packages: {', '.join(pkgs) or 'None'}")
469
+ for name, pkgs in logging_catalog.items()
470
+ }
471
+
472
+ render_selection_table("Logging Options", options)
473
+
474
+ choice = click.prompt(
475
+ "\nSelect logging format",
476
+ type=click.IntRange(1, len(options)),
477
+ default=len(options), # Default to "None"
478
+ )
479
+
480
+ return cast(str, list(options.keys())[choice - 1])
481
+
482
+
483
+ def prompt_migrations_selection(settings: Any, database_type: str = "None") -> str:
484
+ """
485
+ Prompt for the schema migration tool.
486
+
487
+ Alembic only has something to migrate on a relational database, so it is
488
+ pre-selected as the default when the user picked one and the prompt
489
+ defaults to ``None`` otherwise.
490
+
491
+ Args:
492
+ settings: FastkitConfig instance
493
+ database_type: The database chosen earlier in the flow
494
+
495
+ Returns:
496
+ Migration tool name
497
+ """
498
+ console.print("\n[bold cyan]🧬 Database Migrations[/bold cyan]")
499
+ console.print("[dim]Version-control your database schema[/dim]\n")
500
+
501
+ migrations_catalog = settings.PACKAGE_CATALOG[FeatureAxis.MIGRATIONS]
502
+ is_sql = database_type in SQL_DATABASES
503
+
504
+ descriptions = {
505
+ MigrationsChoice.ALEMBIC: (
506
+ "alembic.ini + async alembic/env.py + scripts/migrate.sh"
507
+ + (
508
+ " [bold green](recommended for SQL databases)[/bold green]"
509
+ if is_sql
510
+ else " [yellow](needs a relational database)[/yellow]"
511
+ )
512
+ ),
513
+ MigrationsChoice.NONE: "No migration tooling",
514
+ }
515
+ options = {name: descriptions.get(name, "") for name in migrations_catalog}
516
+
517
+ render_selection_table("Migration Options", options)
518
+
519
+ option_names = list(options.keys())
520
+ default_idx = (
521
+ option_names.index(MigrationsChoice.ALEMBIC) + 1 if is_sql else len(options)
522
+ )
523
+
524
+ choice = click.prompt(
525
+ "\nSelect migration tool",
526
+ type=click.IntRange(1, len(options)),
527
+ default=default_idx,
528
+ )
529
+
530
+ return cast(str, option_names[choice - 1])
531
+
532
+
533
+ def prompt_tooling_selection(settings: Any) -> List[str]:
534
+ """
535
+ Prompt for developer tooling (multi-select).
536
+
537
+ Args:
538
+ settings: FastkitConfig instance
539
+
540
+ Returns:
541
+ List of selected tooling names
542
+ """
543
+ console.print("\n[bold cyan]🧰 Developer Tooling[/bold cyan]")
544
+ console.print(
545
+ "[dim]Select tooling to generate (comma-separated numbers, e.g., 1,3)[/dim]\n"
546
+ )
547
+
548
+ tooling_catalog = settings.PACKAGE_CATALOG[FeatureAxis.TOOLING]
549
+ descriptions = {
550
+ ToolingChoice.RUFF: "ruff + ruff-format config in pyproject.toml (replaces black/isort)",
551
+ ToolingChoice.PRE_COMMIT: ".pre-commit-config.yaml",
552
+ ToolingChoice.GITHUB_ACTIONS: ".github/workflows/test.yml (Python 3.12)",
553
+ ToolingChoice.DEVCONTAINER: ".devcontainer/devcontainer.json",
554
+ ToolingChoice.MAKEFILE: "Makefile with install/test/lint/format/run",
555
+ }
556
+
557
+ options = [name for name in tooling_catalog if name != NONE_CHOICE]
558
+ for i, option in enumerate(options, 1):
559
+ console.print(
560
+ f" [cyan]{i}[/cyan]. {option} [dim]{descriptions.get(option, '')}[/dim]"
561
+ )
562
+
563
+ selected_input = console.input(
564
+ "\n[cyan]Your choice (or press Enter to skip):[/cyan] "
565
+ ).strip()
566
+
567
+ if not selected_input:
568
+ return []
569
+
570
+ try:
571
+ indices = [int(x.strip()) for x in selected_input.split(",") if x.strip()]
572
+ return [options[idx - 1] for idx in indices if 1 <= idx <= len(options)]
573
+ except (ValueError, IndexError):
574
+ console.print("[yellow]Invalid selection. Skipping tooling.[/yellow]")
575
+ return []
576
+
577
+
439
578
  def prompt_deployment_options() -> List[str]:
440
579
  """
441
580
  Prompt for deployment configuration.
@@ -561,12 +700,22 @@ def prompt_additional_features(settings: Any) -> Dict[str, Any]:
561
700
  # Monitoring
562
701
  features["monitoring"] = prompt_monitoring_selection(settings)
563
702
 
703
+ # Logging format
704
+ features["logging"] = prompt_logging_selection(settings)
705
+
564
706
  # Testing
565
707
  features["testing"] = prompt_testing_selection(settings)
566
708
 
709
+ # Migrations — the database choice decides the recommended default.
710
+ database_type = features["database"].get("type", NONE_CHOICE)
711
+ features["migrations"] = prompt_migrations_selection(settings, database_type)
712
+
567
713
  # Utilities
568
714
  features["utilities"] = prompt_utilities_selection(settings)
569
715
 
716
+ # Developer tooling
717
+ features["tooling"] = prompt_tooling_selection(settings)
718
+
570
719
  # Deployment
571
720
  features["deployment"] = prompt_deployment_options()
572
721
 
@@ -13,6 +13,7 @@ from typing import Any, Dict, List, Optional
13
13
  from rich.panel import Panel
14
14
  from rich.table import Table
15
15
 
16
+ from fastapi_fastkit.core.settings import MULTI_SELECT_AXES
16
17
  from fastapi_fastkit.utils.main import console
17
18
 
18
19
 
@@ -177,11 +178,26 @@ def confirm_selections(config: Dict[str, Any]) -> bool:
177
178
  if testing_type != "None":
178
179
  table.add_row("Testing", testing_type)
179
180
 
181
+ # Logging format
182
+ logging_type = config.get("logging", "None")
183
+ if logging_type != "None":
184
+ table.add_row("Logging", logging_type)
185
+
186
+ # Migrations
187
+ migrations_type = config.get("migrations", "None")
188
+ if migrations_type != "None":
189
+ table.add_row("Migrations", migrations_type)
190
+
180
191
  # Utilities
181
192
  utilities = config.get("utilities", [])
182
193
  if utilities:
183
194
  table.add_row("Utilities", ", ".join(utilities))
184
195
 
196
+ # Developer tooling
197
+ tooling = config.get("tooling", [])
198
+ if tooling:
199
+ table.add_row("Tooling", ", ".join(tooling))
200
+
185
201
  # Custom packages
186
202
  custom = config.get("custom_packages", [])
187
203
  if custom:
@@ -229,8 +245,8 @@ def display_feature_catalog(
229
245
  console.print(panel)
230
246
 
231
247
  for category, options in catalog.items():
232
- if category == "utilities":
233
- continue # Skip utilities as they may have empty package lists
248
+ if category in MULTI_SELECT_AXES:
249
+ continue # Skip multi-selects: several options ship no packages
234
250
 
235
251
  desc = descriptions.get(category, category.title())
236
252
  table = Table(title=f"{desc}", show_header=True, header_style="bold yellow")