rapidkit 0.40.1 → 0.41.1

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 (199) hide show
  1. package/README.md +48 -7
  2. package/contracts/agent-customization-pack.v1.json +52 -2
  3. package/contracts/extension-cli-compatibility.v1.json +14 -2
  4. package/contracts/runtime-command-surface.v1.json +7 -1
  5. package/contracts/workspace-intelligence/agent-action-outcome.v1.json +38 -0
  6. package/contracts/workspace-intelligence/blocker-resolution.v1.json +65 -0
  7. package/contracts/workspace-intelligence/doctor-fix-result.v1.json +34 -0
  8. package/contracts/workspace-intelligence/studio-blocker-handoff.v1.json +91 -0
  9. package/contracts/workspace-intelligence/workspace-contract-verify.v1.json +51 -0
  10. package/contracts/workspace-intelligence/workspace-dependency-graph.v1.json +61 -1
  11. package/contracts/workspace-intelligence/workspace-explain.v1.json +31 -0
  12. package/contracts/workspace-intelligence/workspace-intelligence-history.v1.json +36 -0
  13. package/contracts/workspace-intelligence/workspace-operational-skill.v1.json +37 -0
  14. package/contracts/workspace-intelligence/workspace-skills-index.v1.json +27 -0
  15. package/dist/analyze-QYHMGLSG.js +1 -0
  16. package/dist/autopilot-release-AHMQEUFH.js +1 -0
  17. package/dist/chunk-33LR2QEM.js +2 -0
  18. package/dist/chunk-3PTJID76.js +2 -0
  19. package/dist/chunk-46AGNYI7.js +50 -0
  20. package/dist/chunk-64RTZBHU.js +2 -0
  21. package/dist/chunk-AQ4XZZC6.js +1 -0
  22. package/dist/{chunk-RXWM5DSC.js → chunk-BFEBZABL.js} +3 -3
  23. package/dist/{chunk-3YLMCP3V.js → chunk-CDCYRBAY.js} +1 -1
  24. package/dist/chunk-CDPR2YKL.js +13 -0
  25. package/dist/chunk-CKXJR3YT.js +7 -0
  26. package/dist/chunk-E5ZVQL3C.js +13 -0
  27. package/dist/chunk-ELU3G6DQ.js +9 -0
  28. package/dist/chunk-EN6YCX36.js +1 -0
  29. package/dist/chunk-FMBSON6H.js +33 -0
  30. package/dist/chunk-GBJBQ43T.js +1 -0
  31. package/dist/chunk-ICGWHIMK.js +1 -0
  32. package/dist/{chunk-4FJQWL7P.js → chunk-ITJ6RKUW.js} +3 -3
  33. package/dist/{workspace-graph-ICB7OVAZ.js → chunk-JEI6BTZI.js} +1 -1
  34. package/dist/{chunk-G76C74EV.js → chunk-JU3VNLTY.js} +1 -1
  35. package/dist/chunk-JW2FSKT3.js +2 -0
  36. package/dist/chunk-KIUSCFHF.js +1 -0
  37. package/dist/chunk-LKX3L7TE.js +2 -0
  38. package/dist/chunk-MIWDCR6I.js +2 -0
  39. package/dist/{chunk-6G2KSHP6.js → chunk-OLDPVVSV.js} +1 -1
  40. package/dist/{chunk-4Q2ZZKGB.js → chunk-PCXSTKZ5.js} +1 -1
  41. package/dist/{chunk-6KD5F6LX.js → chunk-Q2KZIBV4.js} +1 -1
  42. package/dist/{chunk-ERCD6NFF.js → chunk-RSYUNEH7.js} +13 -13
  43. package/dist/chunk-TJN7G2MA.js +1 -0
  44. package/dist/chunk-UQR6G7KH.js +32 -0
  45. package/dist/chunk-VMJA36WD.js +1 -0
  46. package/dist/chunk-WRMCPKGA.js +1 -0
  47. package/dist/{create-XVDDQA42.js → create-RNP5ACQL.js} +1 -1
  48. package/dist/demo-kit-N5U3NGAE.js +149 -0
  49. package/dist/{doctor-UOLOGJ2Z.js → doctor-XM6QDTDC.js} +1 -1
  50. package/dist/{dotnet-webapi-clean-RTBRPDPL.js → dotnet-webapi-clean-K33C77EI.js} +1 -1
  51. package/dist/{gofiber-standard-UGIRKPKL.js → gofiber-standard-BQ4HCXL2.js} +1 -1
  52. package/dist/{gogin-standard-HJ7SPFNT.js → gogin-standard-PUBCYW3A.js} +1 -1
  53. package/dist/index.d.ts +45 -7
  54. package/dist/index.js +145 -127
  55. package/dist/{pipeline-XK62WL4D.js → pipeline-DH6Z47O4.js} +1 -1
  56. package/dist/platform-capabilities-TSLK667K.js +1 -0
  57. package/dist/{pythonRapidkitExec-MNWRC4F2.js → pythonRapidkitExec-SGKW76XM.js} +1 -1
  58. package/dist/{springboot-standard-IWJSVDLZ.js → springboot-standard-XFVQI37R.js} +1 -1
  59. package/dist/{workspace-L4ITCKMM.js → workspace-E554C5SM.js} +1 -1
  60. package/dist/workspace-agent-sync-2HRPM5ZD.js +1 -0
  61. package/dist/{workspace-context-NMMQMHNU.js → workspace-context-VJTXW3K4.js} +1 -1
  62. package/dist/workspace-contract-OO4GMENV.js +1 -0
  63. package/dist/workspace-explain-3WSJLIJ6.js +1 -0
  64. package/dist/workspace-explain-contract-24RQ7KIW.js +1 -0
  65. package/dist/workspace-feedback-65NR3EZH.js +1 -0
  66. package/dist/{workspace-foundation-HNIRAIBF.js → workspace-foundation-LISDH53T.js} +1 -1
  67. package/dist/workspace-graph-2A5THUCI.js +1 -0
  68. package/dist/workspace-history-VPDADQKG.js +1 -0
  69. package/dist/{workspace-intelligence-64IWAYHS.js → workspace-intelligence-E3KXEZCM.js} +1 -1
  70. package/dist/workspace-mcp-serve-RFYDCA2L.js +3 -0
  71. package/dist/workspace-model-YL7W3573.js +1 -0
  72. package/dist/workspace-registry-summary-X5WRUU3T.js +1 -0
  73. package/dist/workspace-run-GCIQD73R.js +1 -0
  74. package/dist/workspace-verify-NRYH7RNB.js +1 -0
  75. package/dist/workspace-watch-H2AETGFI.js +1 -0
  76. package/docs/DEVELOPMENT.md +1 -1
  77. package/docs/OPEN_SOURCE_USER_SCENARIOS.md +1 -1
  78. package/docs/README.md +1 -1
  79. package/docs/commands-reference.md +10 -2
  80. package/docs/contracts/ARTIFACT_CATALOG.md +3 -1
  81. package/docs/contracts/NAMING_AND_COEXISTENCE.md +58 -0
  82. package/docs/workspace-run.md +25 -1
  83. package/package.json +7 -3
  84. package/scripts/enterprise-package-smoke.mjs +427 -0
  85. package/scripts/prepack-enterprise.mjs +40 -0
  86. package/templates/generator.js +175 -0
  87. package/templates/kits/fastapi-ddd/README.md.j2 +122 -0
  88. package/templates/kits/fastapi-ddd/common/env.example.j2 +10 -0
  89. package/templates/kits/fastapi-ddd/env.example.j2 +1 -0
  90. package/templates/kits/fastapi-ddd/pyproject.toml.j2 +64 -0
  91. package/templates/kits/fastapi-ddd/src/__init__.py.j2 +3 -0
  92. package/templates/kits/fastapi-ddd/src/app/__init__.py.j2 +11 -0
  93. package/templates/kits/fastapi-ddd/src/app/application/__init__.py.j2 +5 -0
  94. package/templates/kits/fastapi-ddd/src/app/application/interfaces.py.j2 +43 -0
  95. package/templates/kits/fastapi-ddd/src/app/application/use_cases/__init__.py.j2 +6 -0
  96. package/templates/kits/fastapi-ddd/src/app/application/use_cases/health.py.j2 +14 -0
  97. package/templates/kits/fastapi-ddd/src/app/application/use_cases/notes.py.j2 +24 -0
  98. package/templates/kits/fastapi-ddd/src/app/config/__init__.py.j2 +16 -0
  99. package/templates/kits/fastapi-ddd/src/app/domain/__init__.py.j2 +3 -0
  100. package/templates/kits/fastapi-ddd/src/app/domain/models/__init__.py.j2 +6 -0
  101. package/templates/kits/fastapi-ddd/src/app/domain/models/health.py.j2 +16 -0
  102. package/templates/kits/fastapi-ddd/src/app/domain/models/note.py.j2 +27 -0
  103. package/templates/kits/fastapi-ddd/src/app/infrastructure/__init__.py.j2 +5 -0
  104. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/__init__.py.j2 +6 -0
  105. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/health.py.j2 +17 -0
  106. package/templates/kits/fastapi-ddd/src/app/infrastructure/repositories/notes.py.j2 +28 -0
  107. package/templates/kits/fastapi-ddd/src/app/main.py.j2 +61 -0
  108. package/templates/kits/fastapi-ddd/src/app/presentation/__init__.py.j2 +3 -0
  109. package/templates/kits/fastapi-ddd/src/app/presentation/api/__init__.py.j2 +5 -0
  110. package/templates/kits/fastapi-ddd/src/app/presentation/api/dependencies/__init__.py.j2 +19 -0
  111. package/templates/kits/fastapi-ddd/src/app/presentation/api/router.py.j2 +10 -0
  112. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/__init__.py.j2 +5 -0
  113. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/health.py.j2 +27 -0
  114. package/templates/kits/fastapi-ddd/src/app/presentation/api/routes/notes.py.j2 +50 -0
  115. package/templates/kits/fastapi-ddd/src/app/shared/__init__.py.j2 +5 -0
  116. package/templates/kits/fastapi-ddd/src/app/shared/result.py.j2 +28 -0
  117. package/templates/kits/fastapi-ddd/src/cli.py.j2 +167 -0
  118. package/templates/kits/fastapi-ddd/src/main.py.j2 +35 -0
  119. package/templates/kits/fastapi-ddd/src/modules/__init__.py.j2 +3 -0
  120. package/templates/kits/fastapi-ddd/src/routing/__init__.py.j2 +13 -0
  121. package/templates/kits/fastapi-ddd/src/routing/health.py.j2 +7 -0
  122. package/templates/kits/fastapi-ddd/src/routing/notes.py.j2 +7 -0
  123. package/templates/kits/fastapi-ddd/tests/__init__.py.j2 +1 -0
  124. package/templates/kits/fastapi-ddd/tests/test_app_factory.py.j2 +22 -0
  125. package/templates/kits/fastapi-ddd/tests/test_health.py.j2 +17 -0
  126. package/templates/kits/fastapi-ddd/tests/test_notes.py.j2 +27 -0
  127. package/templates/kits/fastapi-standard/README.md.j2 +145 -0
  128. package/templates/kits/fastapi-standard/common/env.example.j2 +10 -0
  129. package/templates/kits/fastapi-standard/env.example.j2 +1 -0
  130. package/templates/kits/fastapi-standard/pyproject.toml.j2 +64 -0
  131. package/templates/kits/fastapi-standard/src/__init__.py.j2 +3 -0
  132. package/templates/kits/fastapi-standard/src/cli.py.j2 +168 -0
  133. package/templates/kits/fastapi-standard/src/main.py.j2 +66 -0
  134. package/templates/kits/fastapi-standard/src/modules/__init__.py.j2 +3 -0
  135. package/templates/kits/fastapi-standard/src/routing/__init__.py.j2 +16 -0
  136. package/templates/kits/fastapi-standard/src/routing/examples.py.j2 +71 -0
  137. package/templates/kits/fastapi-standard/src/routing/health.py.j2 +22 -0
  138. package/templates/kits/fastapi-standard/tests/__init__.py.j2 +1 -0
  139. package/templates/kits/fastapi-standard/tests/test_examples.py.j2 +29 -0
  140. package/templates/kits/fastapi-standard/tests/test_health.py.j2 +17 -0
  141. package/templates/kits/nestjs-standard/Dockerfile.j2 +41 -0
  142. package/templates/kits/nestjs-standard/README.md.j2 +139 -0
  143. package/templates/kits/nestjs-standard/docker-compose.yml.j2 +94 -0
  144. package/templates/kits/nestjs-standard/docs/README.md.j2 +15 -0
  145. package/templates/kits/nestjs-standard/env.example.j2 +18 -0
  146. package/templates/kits/nestjs-standard/eslint.config.cjs.j2 +9 -0
  147. package/templates/kits/nestjs-standard/jest.config.ts.j2 +22 -0
  148. package/templates/kits/nestjs-standard/nest-cli.json.j2 +10 -0
  149. package/templates/kits/nestjs-standard/package.json.j2 +101 -0
  150. package/templates/kits/nestjs-standard/src/app.controller.ts.j2 +14 -0
  151. package/templates/kits/nestjs-standard/src/app.module.ts.j2 +26 -0
  152. package/templates/kits/nestjs-standard/src/app.service.ts.j2 +16 -0
  153. package/templates/kits/nestjs-standard/src/auth/auth.controller.ts.j2 +20 -0
  154. package/templates/kits/nestjs-standard/src/auth/auth.module.ts.j2 +13 -0
  155. package/templates/kits/nestjs-standard/src/auth/auth.service.ts.j2 +6 -0
  156. package/templates/kits/nestjs-standard/src/auth/entities/token.entity.ts.j2 +3 -0
  157. package/templates/kits/nestjs-standard/src/auth/entities/user.entity.ts.j2 +3 -0
  158. package/templates/kits/nestjs-standard/src/auth/entities/webauthn.entity.ts.j2 +3 -0
  159. package/templates/kits/nestjs-standard/src/config/configuration.ts.j2 +85 -0
  160. package/templates/kits/nestjs-standard/src/config/index.ts.j2 +2 -0
  161. package/templates/kits/nestjs-standard/src/config/validation.ts.j2 +21 -0
  162. package/templates/kits/nestjs-standard/src/examples/dto/create-note.dto.ts.j2 +11 -0
  163. package/templates/kits/nestjs-standard/src/examples/examples.controller.ts.j2 +24 -0
  164. package/templates/kits/nestjs-standard/src/examples/examples.module.ts.j2 +10 -0
  165. package/templates/kits/nestjs-standard/src/examples/examples.service.ts.j2 +33 -0
  166. package/templates/kits/nestjs-standard/src/main.ts.j2 +53 -0
  167. package/templates/kits/nestjs-standard/src/modules/index.ts.j2 +25 -0
  168. package/templates/kits/nestjs-standard/test/app.controller.spec.ts.j2 +24 -0
  169. package/templates/kits/nestjs-standard/test/app.e2e-spec.ts.j2 +60 -0
  170. package/templates/kits/nestjs-standard/test/examples.controller.spec.ts.j2 +28 -0
  171. package/templates/kits/nestjs-standard/test/jest-e2e.json.j2 +15 -0
  172. package/templates/kits/nestjs-standard/tsconfig.build.json.j2 +12 -0
  173. package/templates/kits/nestjs-standard/tsconfig.json.j2 +26 -0
  174. package/dist/analyze-RHQM4AB2.js +0 -1
  175. package/dist/autopilot-release-OJTLXPMX.js +0 -1
  176. package/dist/chunk-5VBRMLRU.js +0 -7
  177. package/dist/chunk-7VI4U7Q5.js +0 -2
  178. package/dist/chunk-FV5A3N3I.js +0 -2
  179. package/dist/chunk-GDGATWR5.js +0 -2
  180. package/dist/chunk-GOM3RFB3.js +0 -2
  181. package/dist/chunk-GX7UU7LL.js +0 -33
  182. package/dist/chunk-KYH364KQ.js +0 -1
  183. package/dist/chunk-OWNGSAO3.js +0 -2
  184. package/dist/chunk-QPEBI6AB.js +0 -2
  185. package/dist/chunk-TYZPPUBH.js +0 -1
  186. package/dist/chunk-VQMZC5TC.js +0 -9
  187. package/dist/chunk-WHCON2VN.js +0 -50
  188. package/dist/chunk-X7PWDIQW.js +0 -1
  189. package/dist/chunk-Z5LKRG57.js +0 -1
  190. package/dist/chunk-ZWKLRZE5.js +0 -13
  191. package/dist/demo-kit-RWGOEDW4.js +0 -141
  192. package/dist/workspace-agent-sync-G7JU77IK.js +0 -25
  193. package/dist/workspace-contract-D5O4OZD5.js +0 -1
  194. package/dist/workspace-history-LHUTLE3S.js +0 -1
  195. package/dist/workspace-model-SDHH5RBC.js +0 -1
  196. package/dist/workspace-registry-summary-MIPHVB56.js +0 -1
  197. package/dist/workspace-run-SPP32MPV.js +0 -1
  198. package/dist/workspace-verify-6Q6MGRG6.js +0 -1
  199. package/dist/workspace-watch-JDXVGW4H.js +0 -1
@@ -0,0 +1,28 @@
1
+ """Basic result type shared across layers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Generic, Optional, TypeVar
7
+
8
+ T = TypeVar("T")
9
+ E = TypeVar("E")
10
+
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class Result(Generic[T, E]):
14
+ """Simple functional-style result wrapper."""
15
+
16
+ value: Optional[T] = None
17
+ error: Optional[E] = None
18
+
19
+ @property
20
+ def is_ok(self) -> bool:
21
+ return self.error is None
22
+
23
+ @property
24
+ def is_err(self) -> bool:
25
+ return self.error is not None
26
+
27
+
28
+ __all__ = ["Result"]
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python3
2
+ """Project CLI wrapper for {{ project_name }} (DDD edition).
3
+
4
+ Prefer a per-project CLI in `.rapidkit/cli.py` when present. Otherwise
5
+ provide helpful guidance to the developer rather than guessing environment
6
+ details.
7
+ """
8
+
9
+ import importlib.util
10
+ import sys
11
+ import argparse
12
+ from pathlib import Path
13
+ from typing import Optional
14
+
15
+
16
+ def _missing_cli(name: str) -> None:
17
+ print(f"❌ Missing project-local CLI (.rapidkit/cli.py) - can't run '{name}'")
18
+ print("💡 If you're a new user run: rapidkit init # create venv + install deps")
19
+ sys.exit(127)
20
+
21
+
22
+ def _load_project_cli_module() -> Optional[object]:
23
+ project_root = Path(__file__).resolve().parents[1]
24
+ cli_file = project_root / ".rapidkit" / "cli.py"
25
+ if not cli_file.exists():
26
+ return None
27
+ spec = importlib.util.spec_from_file_location("project_cli", str(cli_file))
28
+ if spec is None or spec.loader is None:
29
+ return None
30
+ module = importlib.util.module_from_spec(spec)
31
+ spec.loader.exec_module(module) # type: ignore
32
+ return module
33
+
34
+
35
+ _mod = _load_project_cli_module()
36
+
37
+
38
+ # Default placeholders -- call `_missing_cli` if the project-local CLI isn't
39
+ # available. These are real functions so linters don't complain.
40
+ def init() -> None:
41
+ _missing_cli("init")
42
+
43
+
44
+ def dev() -> None:
45
+ _missing_cli("dev")
46
+
47
+
48
+ def start() -> None:
49
+ _missing_cli("start")
50
+
51
+
52
+ def build() -> None:
53
+ _missing_cli("build")
54
+
55
+
56
+ def test() -> None:
57
+ _missing_cli("test")
58
+
59
+
60
+ def lint() -> None:
61
+ _missing_cli("lint")
62
+
63
+
64
+ def format() -> None: # type: ignore[misc]
65
+ _missing_cli("format")
66
+
67
+
68
+ def help_cmd() -> None:
69
+ print("Usage: poetry run <command> # (init|dev|start|build|test|lint|format)")
70
+
71
+
72
+ if _mod is not None:
73
+ # prefer project-provided implementations when available
74
+ init = getattr(_mod, "init", init)
75
+ dev = getattr(_mod, "dev", dev)
76
+ start = getattr(_mod, "start", start)
77
+ build = getattr(_mod, "build", build)
78
+ test = getattr(_mod, "test", test)
79
+ lint = getattr(_mod, "lint", lint)
80
+ format = getattr(_mod, "format", format)
81
+ help_cmd = getattr(_mod, "help_cmd", help_cmd)
82
+
83
+
84
+ _dev_impl = dev
85
+ _start_impl = start
86
+
87
+
88
+ def _runtime_kwargs_from_argv(argv: list[str]) -> dict:
89
+ parser = argparse.ArgumentParser(add_help=False)
90
+ parser.add_argument("-p", "--port", type=int, dest="port")
91
+ parser.add_argument("--host", dest="host")
92
+ parser.add_argument("--allow-global-runtime", action="store_true", dest="allow_global_runtime")
93
+ ns, _ = parser.parse_known_args(argv)
94
+
95
+ kwargs = {}
96
+ if ns.port is not None:
97
+ kwargs["port"] = ns.port
98
+ if ns.host is not None:
99
+ kwargs["host"] = ns.host
100
+ if ns.allow_global_runtime:
101
+ kwargs["allow_global_runtime"] = True
102
+ return kwargs
103
+
104
+
105
+ def dev() -> None: # type: ignore[no-redef]
106
+ kwargs = _runtime_kwargs_from_argv(sys.argv[1:])
107
+ try:
108
+ _dev_impl(**kwargs)
109
+ except TypeError:
110
+ _dev_impl()
111
+
112
+
113
+ def start() -> None: # type: ignore[no-redef]
114
+ kwargs = _runtime_kwargs_from_argv(sys.argv[1:])
115
+ try:
116
+ _start_impl(**kwargs)
117
+ except TypeError:
118
+ _start_impl()
119
+
120
+
121
+ def main() -> None:
122
+ if len(sys.argv) < 2:
123
+ help_cmd()
124
+ return
125
+
126
+ command = sys.argv[1]
127
+ commands = {
128
+ "init": init,
129
+ "dev": dev,
130
+ "start": start,
131
+ "build": build,
132
+ "test": test,
133
+ "lint": lint,
134
+ "format": format,
135
+ "help": help_cmd,
136
+ }
137
+
138
+ if command in commands:
139
+ if command in ("dev", "start"):
140
+ parser = argparse.ArgumentParser(prog=f"poetry run {command}", add_help=False)
141
+ parser.add_argument("-p", "--port", type=int, dest="port")
142
+ parser.add_argument("--host", dest="host")
143
+ parser.add_argument("--allow-global-runtime", action="store_true", dest="allow_global_runtime")
144
+ ns, _ = parser.parse_known_args(sys.argv[2:])
145
+
146
+ kwargs = {}
147
+ if ns.port is not None:
148
+ kwargs["port"] = ns.port
149
+ if ns.host is not None:
150
+ kwargs["host"] = ns.host
151
+ if ns.allow_global_runtime:
152
+ kwargs["allow_global_runtime"] = True
153
+
154
+ try:
155
+ commands[command](**kwargs)
156
+ except TypeError:
157
+ commands[command]()
158
+ else:
159
+ commands[command]()
160
+ else:
161
+ print(f"Unknown command: {command}")
162
+ print("Run 'poetry run help' to see available commands.")
163
+ sys.exit(1)
164
+
165
+
166
+ if __name__ == "__main__":
167
+ main()
@@ -0,0 +1,35 @@
1
+ """{{ project_name }} FastAPI application entrypoint (DDD)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import AsyncIterator
6
+ from contextlib import asynccontextmanager
7
+
8
+ from fastapi import FastAPI
9
+
10
+ from src.app.main import create_app
11
+
12
+ # <<<inject:imports>>>
13
+
14
+
15
+ @asynccontextmanager
16
+ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
17
+ """Coordinate startup/shutdown hooks contributed by RapidKit modules."""
18
+
19
+ _ = app # ensure the app reference stays available for injected hooks
20
+ # <<<inject:startup>>>
21
+ try:
22
+ yield
23
+ finally:
24
+ # <<<inject:shutdown>>>
25
+ pass
26
+
27
+
28
+ app: FastAPI = create_app(
29
+ title="{{ project_name }}",
30
+ description="{{ description }}",
31
+ version="{{ app_version }}",
32
+ lifespan=lifespan,
33
+ )
34
+
35
+ # <<<inject:routes>>>
@@ -0,0 +1,3 @@
1
+ """Module bootstrap namespace."""
2
+
3
+ # <<<inject:module-init>>>
@@ -0,0 +1,13 @@
1
+ """API router assembly bridging DDD presentation routes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from src.app.presentation.api.router import get_api_router
6
+ from .health import router as health_router
7
+ from .notes import router as notes_router
8
+ # <<<inject:router-imports>>>
9
+
10
+ api_router = get_api_router()
11
+ api_router.include_router(health_router, prefix="/health", tags=["health"])
12
+ api_router.include_router(notes_router, prefix="/examples", tags=["examples"])
13
+ # <<<inject:router-mount>>>
@@ -0,0 +1,7 @@
1
+ """Health endpoints re-export for module compatibility."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from src.app.presentation.api.routes.health import router
6
+
7
+ __all__ = ["router"]
@@ -0,0 +1,7 @@
1
+ """Re-export example note routes for compatibility with module injection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from src.app.presentation.api.routes.notes import router
6
+
7
+ __all__ = ["router"]
@@ -0,0 +1 @@
1
+ """Test package placeholder."""
@@ -0,0 +1,22 @@
1
+ """Smoke tests for the generated FastAPI DDD scaffold."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from fastapi import FastAPI
6
+ from fastapi.testclient import TestClient
7
+
8
+ from src.app.main import create_app
9
+ from src.main import app
10
+
11
+
12
+ def test_create_app_returns_fastapi_instance() -> None:
13
+ instance = create_app(title="Test", description="Sample", version="1.0.0")
14
+ assert isinstance(instance, FastAPI)
15
+ assert instance.title == "Test"
16
+
17
+
18
+ def test_health_route_returns_ok() -> None:
19
+ client = TestClient(app)
20
+ response = client.get("/api/health/")
21
+ assert response.status_code == 200
22
+ assert response.json()["status"] == "ok"
@@ -0,0 +1,17 @@
1
+ """Health-check regression tests for FastAPI DDD projects."""
2
+
3
+ from fastapi.testclient import TestClient
4
+
5
+ from src.main import app
6
+
7
+ client = TestClient(app)
8
+
9
+
10
+ def test_health_endpoint() -> None:
11
+ response = client.get("/api/health/")
12
+ assert response.status_code == 200
13
+ payload = response.json()
14
+ assert payload["status"] == "ok"
15
+ assert "version" in payload
16
+ assert "uptime" in payload
17
+ assert "module" in payload
@@ -0,0 +1,27 @@
1
+ """Example feature tests exercising the DDD notes handlers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from fastapi.testclient import TestClient
6
+
7
+ from src.main import app
8
+
9
+ client = TestClient(app)
10
+
11
+
12
+ def test_create_and_fetch_note() -> None:
13
+ payload = {"title": "architecture note", "body": "Documented via FastAPI DDD kit."}
14
+ create_response = client.post("/api/examples/notes", json=payload)
15
+ assert create_response.status_code == 201
16
+ body = create_response.json()
17
+ note_id = body["id"]
18
+ assert body["title"] == payload["title"]
19
+
20
+ get_response = client.get(f"/api/examples/notes/{note_id}")
21
+ assert get_response.status_code == 200
22
+ assert get_response.json()["id"] == note_id
23
+
24
+
25
+ def test_missing_note_returns_404() -> None:
26
+ response = client.get("/api/examples/notes/999")
27
+ assert response.status_code == 404
@@ -0,0 +1,145 @@
1
+ # {{ project_name | replace('_', ' ') | title }}
2
+
3
+ A minimal FastAPI service generated with the **FastAPI Standard Kit**. All domain-specific capabilities (configuration, logging, persistence, observability, authentication, etc.) are provided by RapidKit modules.
4
+
5
+ ## Quick start
6
+
7
+ ```bash
8
+ # Load the project-aware RapidKit CLI (adds .rapidkit/rapidkit to PATH)
9
+ source .rapidkit/activate
10
+
11
+ # Bootstrap dependencies (creates .venv + installs Poetry-managed deps)
12
+ rapidkit init # use make init if you prefer a Make target
13
+
14
+ # Copy env templates and install hooks/tooling
15
+ ./bootstrap.sh
16
+
17
+ # Run linting, typing, testing, and supply-chain audits
18
+ make lint
19
+ make typecheck
20
+ make test
21
+ make audit
22
+
23
+ # Start development server with hot reload
24
+ make dev
25
+ rapidkit dev # same as make dev but auto-detects the project
26
+
27
+ # Prefer RapidKit CLI helpers when you want it to resolve scripts automatically
28
+ rapidkit lint
29
+ rapidkit test
30
+ rapidkit start
31
+ ```
32
+
33
+ > Always run `source .rapidkit/activate` after opening a new shell so the project-local `rapidkit` launcher and helper scripts stay on your PATH.
34
+
35
+ > Re-run `rapidkit init` (or `make init`) whenever dependencies change, or use `SKIP_INIT=1 make install` if you only need to refresh tooling/hooks without reinstalling packages.
36
+
37
+ > Lockfiles are generated automatically during scaffolding. Set `RAPIDKIT_SKIP_LOCKS=1` (or `RAPIDKIT_GENERATE_LOCKS=0`) before running `rapidkit create` if you need to opt out.
38
+
39
+ > Want the full RapidKit CLI catalog? Run `rapidkit --help` or visit the CLI reference in the docs to explore every global/project command.
40
+
41
+ ---
42
+
43
+ ## Local development
44
+
45
+ - `rapidkit init` bootstraps dependencies via the project-local CLI (run it after sourcing `.rapidkit/activate`).
46
+ - `make init` is an optional alias for `rapidkit init` when you prefer Make targets.
47
+ - `make install` re-runs `rapidkit init` (unless you set `SKIP_INIT=1`) and refreshes developer tooling such as pre-commit hooks.
48
+ - `./bootstrap.sh` copies `.env.example` to `.env` (if missing) and runs `SKIP_INIT=1 make install` for you.
49
+ - `make dev` (or `rapidkit dev`) launches Uvicorn with the correct module path and reload settings.
50
+ - `make lint`, `make typecheck`, and `make test` wrap Ruff, mypy, and pytest for consistent CI parity.
51
+ - `make audit` shells out to `pip-audit` to surface vulnerable dependencies.
52
+ - Prefer `rapidkit lint`, `rapidkit test`, and `rapidkit start` if you want RapidKit to autodetect the virtualenv and command wiring.
53
+ ```
54
+
55
+ ## Available commands
56
+
57
+ ```bash
58
+ rapidkit init # 🔧 Bootstrap the project (create .venv + install deps)
59
+ make init # 🔧 Optional alias for rapidkit init (wraps the local CLI)
60
+ ./bootstrap.sh # 🪄 Copy env template + install hooks/tooling (idempotent)
61
+ rapidkit dev # 🚀 Start development server with hot reload
62
+ make dev # 🚀 Alternative via Makefile helper
63
+ rapidkit start # ⚡ Start production server
64
+ rapidkit lint # 🔧 Run lint checks via project-aware CLI
65
+ rapidkit test # 🧪 Run pytest through RapidKit CLI
66
+ make install # 📦 Install Poetry deps + hooks
67
+ make lint # ✅ Lint via Ruff + Black
68
+ make typecheck # 🔍 Run mypy on src
69
+ make test # 🧪 Run tests
70
+ make audit # 🔐 Run pip-audit across dependencies
71
+ make docker-up # 🐳 Start docker compose stack (if enabled)
72
+ ```
73
+
74
+ ## Project layout
75
+
76
+ - `src/main.py` – FastAPI application entrypoint
77
+ - `src/routing/` – Core routers (health) and anchors for module routers
78
+ - `src/modules/` – Module bootstrap anchors
79
+ - `pyproject.toml` – Poetry configuration and dependencies
80
+ - `Makefile` – Common developer workflows (format, lint, docker, etc.)
81
+ - `Dockerfile` / `docker-compose.yml` – Optional container setup for local dev and deployment
82
+ - `.github/workflows/ci.yml` – Optional GitHub Actions pipeline for linting and tests
83
+
84
+ ## Example feature
85
+
86
+ The scaffold ships with a tiny in-memory **notes** API mounted under `/api/examples/notes`. Use it as a safe playground for wiring routers, schemas, and tests without touching your real domain logic:
87
+
88
+ ```bash
89
+ # Create a note
90
+ curl -s -X POST http://localhost:8000/api/examples/notes \
91
+ -H "Content-Type: application/json" \
92
+ -d '{"title":"first","body":"scaffolded by RapidKit"}'
93
+
94
+ # List notes
95
+ curl -s http://localhost:8000/api/examples/notes | jq
96
+ ```
97
+
98
+ The implementation intentionally stays in memory so you can replace it with a repository-backed service once you install RapidKit database modules.
99
+
100
+ {% if selected_modules %}
101
+ ## Recommended RapidKit modules
102
+
103
+ The following RapidKit modules are suggested during scaffolding; install them any time with `rapidkit add module <name>`:
104
+
105
+ {% for module in selected_modules %}- {{ module.name | replace('_', ' ') | title }} (`{{ module.name }}`{% if not module.required %}, optional{% endif %}) – tier: {{ module.tier }}
106
+ {% endfor %}
107
+ {% endif %}
108
+
109
+ ## Adding features
110
+
111
+ Use `rapidkit add module <module-name>` to install optional capabilities. Modules inject imports, routes, and services through the anchors defined in `src/main.py` and `src/routing/__init__.py`.
112
+
113
+ During kit generation you can decide whether the core RapidKit modules ship with the scaffold:
114
+
115
+ ```text
116
+ Install the RapidKit settings module? [Y/n]
117
+ Install the RapidKit logging module? [Y/n]
118
+ Install deployment module assets (Docker/CI)? [Y/n]
119
+ ```
120
+
121
+ ### Scaffold toggles vs RapidKit modules
122
+
123
+ - `enable_*` prompts (for Docker, CI, SQLite, etc.) control the starter assets generated by this kit.
124
+ - `install_*` prompts control which RapidKit modules are installed up front.
125
+ - You can always add modules later with `rapidkit add module <name>` if you skip them during scaffolding.
126
+
127
+ When you need deployment artefacts in an existing project, install the optional `deployment` module:
128
+
129
+ ```bash
130
+ rapidkit add module deployment
131
+ rapidkit modules lock --overwrite
132
+ ```
133
+
134
+ <!-- <<<inject:module-snippet>>> -->
135
+
136
+ ## 📄 License
137
+
138
+ This project is licensed under the **{{ license }}** License - see the `LICENSE` file included at the project root for details.
139
+
140
+ ## 🔒 Security & secrets
141
+
142
+ - Copy `.env.example` to `.env` and populate secrets (`SECRET_KEY`, DB credentials, etc.) before deploying.
143
+ - **Do not** commit real secrets or `.env` to git; `.gitignore` already contains `.env` to protect accidental commits.
144
+ - For production, tighten CORS and allowed hosts rather than using wildcard settings provided for convenience in dev.
145
+ - Run `make audit` (pip-audit) before releases to catch dependency CVEs early.
@@ -0,0 +1,10 @@
1
+ # RapidKit environment defaults
2
+ PROJECT_NAME="{{ project_name | default('rapidkit-app') }}"
3
+ ENV="development"
4
+ DEBUG="true"
5
+ APP_HOST="0.0.0.0"
6
+ APP_PORT="8000"
7
+ LOG_LEVEL="info"
8
+
9
+ # Module-specific environment variables
10
+ # <<<inject:module-env>>>
@@ -0,0 +1 @@
1
+ {% include 'common/env.example.j2' %}
@@ -0,0 +1,64 @@
1
+ [tool.poetry]
2
+ name = "{{ project_name }}"
3
+ version = "{{ app_version }}"
4
+ description = "{{ description }}"
5
+ authors = ["{{ author }} <you@example.com>"]
6
+ license = "{{ license }}"
7
+ packages = [{ include = "src" }]
8
+
9
+ [tool.poetry.scripts]
10
+ dev = "src.cli:dev"
11
+ start = "src.cli:start"
12
+ build = "src.cli:build"
13
+ test = "src.cli:test"
14
+ lint = "src.cli:lint"
15
+ format = "src.cli:format"
16
+ help = "src.cli:help_cmd"
17
+
18
+ [tool.poetry.dependencies]
19
+ python = "^{{ python_version }}"
20
+ fastapi = "^0.128.0"
21
+ uvicorn = { extras = ["standard"], version = "^0.40.0" }
22
+ pydantic = "^2.12.5"
23
+ {% if has_settings -%}
24
+ pydantic-settings = { version = "^2.12.0", extras = ["yaml"] }
25
+ {% endif %}
26
+ # <<<inject:poetry-dependencies>>>
27
+
28
+ [tool.poetry.group.dev.dependencies]
29
+ pytest = "^9.0.2"
30
+ pytest-asyncio = "^1.3.0"
31
+ pytest-cov = "^7.0.0"
32
+ httpx = "^0.28.1"
33
+ ruff = "^0.14.10"
34
+ black = "^25.12.0"
35
+ isort = "^7.0.0"
36
+ mypy = "^1.19.1"
37
+ build = "^1.3.0"
38
+
39
+ # <<<inject:poetry-dev-dependencies>>>
40
+
41
+ [build-system]
42
+ requires = ["poetry-core"]
43
+ build-backend = "poetry.core.masonry.api"
44
+
45
+ [tool.pytest.ini_options]
46
+ markers = [
47
+ "integration: mark tests as integration tests",
48
+ "template_integration: mark template integration tests",
49
+ ]
50
+
51
+ [tool.ruff]
52
+ line-length = 100
53
+ exclude = [".rapidkit/vendor"]
54
+
55
+ [tool.ruff.lint]
56
+ ignore = ["E501"]
57
+
58
+ [tool.mypy]
59
+ python_version = "{{ python_version }}"
60
+ ignore_missing_imports = true
61
+ warn_unused_configs = false
62
+ show_error_codes = true
63
+ # Ignore vendor snapshots and generated health shims from strict static checking
64
+ exclude = "(^\\.rapidkit/vendor/|src/health/|src/main.py$)"
@@ -0,0 +1,3 @@
1
+ """{{ project_name }} package."""
2
+
3
+ __all__ = ["main"]