@eventmodelers/cli 0.0.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 (220) hide show
  1. package/README.md +175 -0
  2. package/cli.js +676 -0
  3. package/package.json +35 -0
  4. package/shared/build-kit/code-export.mjs +560 -0
  5. package/shared/build-kit/lib/ollama-agent.js +147 -0
  6. package/shared/build-kit/package.json +11 -0
  7. package/shared/build-kit/ralph-ollama.js +39 -0
  8. package/shared/build-kit/realtime-agent.js +18 -0
  9. package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +407 -0
  10. package/stacks/axon/templates/.claude/skills/build-automation/references/feature-flag-patterns.md +114 -0
  11. package/stacks/axon/templates/.claude/skills/build-automation-workflow/SKILL.md +496 -0
  12. package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/axon-workflow-api.md +279 -0
  13. package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/feature-flag-patterns.md +114 -0
  14. package/stacks/axon/templates/.claude/skills/build-state-change/SKILL.md +396 -0
  15. package/stacks/axon/templates/.claude/skills/build-state-change/references/axon-test-fixture-patterns.md +162 -0
  16. package/stacks/axon/templates/.claude/skills/build-state-change/references/feature-flag-patterns.md +56 -0
  17. package/stacks/axon/templates/.claude/skills/build-state-change/references/rest-api-patterns.md +115 -0
  18. package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +282 -0
  19. package/stacks/axon/templates/.claude/skills/connect/SKILL.md +178 -0
  20. package/stacks/axon/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +611 -0
  21. package/stacks/axon/templates/.claude/skills/load-slice/SKILL.md +141 -0
  22. package/stacks/axon/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
  23. package/stacks/axon/templates/build-kit/lib/AGENT.md +47 -0
  24. package/stacks/axon/templates/build-kit/lib/agent.sh +20 -0
  25. package/stacks/axon/templates/build-kit/lib/backend-prompt.md +158 -0
  26. package/stacks/axon/templates/build-kit/lib/prompt.md +126 -0
  27. package/stacks/axon/templates/build-kit/lib/ralph.js +369 -0
  28. package/stacks/axon/templates/build-kit/ralph-claude.js +44 -0
  29. package/stacks/axon/templates/build-kit/ralph.sh +98 -0
  30. package/stacks/axon/templates/root/.env.example +5 -0
  31. package/stacks/axon/templates/root/CLAUDE.md +60 -0
  32. package/stacks/axon/templates/root/README.md +44 -0
  33. package/stacks/axon/templates/root/docker-compose.yml +64 -0
  34. package/stacks/axon/templates/root/mvnw +259 -0
  35. package/stacks/axon/templates/root/mvnw.cmd +149 -0
  36. package/stacks/axon/templates/root/pom.xml +125 -0
  37. package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/QuickstartApplication.java +128 -0
  38. package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/config/WebConfig.java +155 -0
  39. package/stacks/axon/templates/root/src/main/resources/application.properties +2 -0
  40. package/stacks/axon/templates/root/src/main/resources/static/bg-body.png +0 -0
  41. package/stacks/axon/templates/root/src/main/resources/static/bg-header.png +0 -0
  42. package/stacks/axon/templates/root/src/main/resources/static/index.html +596 -0
  43. package/stacks/cratis-csharp/templates/.claude/skills/_shared/cratis-conventions.md +251 -0
  44. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +99 -0
  45. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/references/patterns.md +115 -0
  46. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +163 -0
  47. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/references/patterns.md +234 -0
  48. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +120 -0
  49. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/references/patterns.md +166 -0
  50. package/stacks/cratis-csharp/templates/.claude/skills/connect/SKILL.md +169 -0
  51. package/stacks/cratis-csharp/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +609 -0
  52. package/stacks/cratis-csharp/templates/.claude/skills/load-slice/SKILL.md +141 -0
  53. package/stacks/cratis-csharp/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
  54. package/stacks/cratis-csharp/templates/build-kit/lib/AGENT.md +58 -0
  55. package/stacks/cratis-csharp/templates/build-kit/lib/agent.sh +20 -0
  56. package/stacks/cratis-csharp/templates/build-kit/lib/backend-prompt.md +129 -0
  57. package/stacks/cratis-csharp/templates/build-kit/lib/prompt.md +124 -0
  58. package/stacks/cratis-csharp/templates/build-kit/lib/ralph.js +302 -0
  59. package/stacks/cratis-csharp/templates/build-kit/ralph-claude.js +37 -0
  60. package/stacks/cratis-csharp/templates/build-kit/ralph.sh +98 -0
  61. package/stacks/cratis-csharp/templates/root/.frontend/index.css +29 -0
  62. package/stacks/cratis-csharp/templates/root/.frontend/index.html +17 -0
  63. package/stacks/cratis-csharp/templates/root/.frontend/main.tsx +18 -0
  64. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.json +42 -0
  65. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.node.json +11 -0
  66. package/stacks/cratis-csharp/templates/root/.frontend/vite.config.ts +56 -0
  67. package/stacks/cratis-csharp/templates/root/App.tsx +23 -0
  68. package/stacks/cratis-csharp/templates/root/CLAUDE.md +62 -0
  69. package/stacks/cratis-csharp/templates/root/CratisApp.csproj +25 -0
  70. package/stacks/cratis-csharp/templates/root/CratisApp.sln +18 -0
  71. package/stacks/cratis-csharp/templates/root/GlobalUsings.cs +3 -0
  72. package/stacks/cratis-csharp/templates/root/Home.tsx +102 -0
  73. package/stacks/cratis-csharp/templates/root/Program.cs +26 -0
  74. package/stacks/cratis-csharp/templates/root/README.md +192 -0
  75. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/AllListings.ts +47 -0
  76. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.cs +11 -0
  77. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.ts +12 -0
  78. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx +17 -0
  79. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/index.ts +1 -0
  80. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Register.ts +51 -0
  81. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx +18 -0
  82. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs +27 -0
  83. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/index.ts +1 -0
  84. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeFeature.tsx +22 -0
  85. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeName.cs +3 -0
  86. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/index.ts +1 -0
  87. package/stacks/cratis-csharp/templates/root/appsettings.Development.json +9 -0
  88. package/stacks/cratis-csharp/templates/root/appsettings.json +26 -0
  89. package/stacks/cratis-csharp/templates/root/docker-compose.yml +23 -0
  90. package/stacks/cratis-csharp/templates/root/package.json +33 -0
  91. package/stacks/cratis-csharp/templates/root/tsconfig.json +3 -0
  92. package/stacks/modeling-kit/templates/.claude/settings.local.json +13 -0
  93. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +215 -0
  94. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +176 -0
  95. package/stacks/modeling-kit/templates/.claude/skills/connect/SKILL.md +182 -0
  96. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +383 -0
  97. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +465 -0
  98. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +587 -0
  99. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md +626 -0
  100. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +542 -0
  101. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +497 -0
  102. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +783 -0
  103. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +604 -0
  104. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +699 -0
  105. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +674 -0
  106. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +231 -0
  107. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +150 -0
  108. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +329 -0
  109. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +204 -0
  110. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +352 -0
  111. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md +341 -0
  112. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +153 -0
  113. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +136 -0
  114. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +78 -0
  115. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +85 -0
  116. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +655 -0
  117. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +479 -0
  118. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +234 -0
  119. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +353 -0
  120. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +200 -0
  121. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +94 -0
  122. package/stacks/modeling-kit/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +441 -0
  123. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +290 -0
  124. package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +212 -0
  125. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +123 -0
  126. package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +353 -0
  127. package/stacks/modeling-kit/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  128. package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +134 -0
  129. package/stacks/modeling-kit/templates/kit/lib/agent.sh +20 -0
  130. package/stacks/modeling-kit/templates/kit/lib/ollama-agent.js +147 -0
  131. package/stacks/modeling-kit/templates/kit/lib/ralph.js +286 -0
  132. package/stacks/modeling-kit/templates/kit/package.json +12 -0
  133. package/stacks/modeling-kit/templates/kit/ralph-claude.js +50 -0
  134. package/stacks/modeling-kit/templates/kit/ralph-ollama.js +38 -0
  135. package/stacks/modeling-kit/templates/kit/ralph.sh +61 -0
  136. package/stacks/modeling-kit/templates/kit/realtime-agent.js +18 -0
  137. package/stacks/modeling-kit/templates/root/CLAUDE.md +56 -0
  138. package/stacks/node/templates/.claude/skills/build-automation/SKILL.md +266 -0
  139. package/stacks/node/templates/.claude/skills/build-state-change/SKILL.md +344 -0
  140. package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +412 -0
  141. package/stacks/node/templates/.claude/skills/connect/SKILL.md +178 -0
  142. package/stacks/node/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
  143. package/stacks/node/templates/.claude/skills/load-slice/SKILL.md +143 -0
  144. package/stacks/node/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  145. package/stacks/node/templates/build-kit/README.md +86 -0
  146. package/stacks/node/templates/build-kit/lib/AGENT.md +47 -0
  147. package/stacks/node/templates/build-kit/lib/agent.sh +20 -0
  148. package/stacks/node/templates/build-kit/lib/backend-prompt.md +152 -0
  149. package/stacks/node/templates/build-kit/lib/prompt.md +122 -0
  150. package/stacks/node/templates/build-kit/lib/ralph.js +369 -0
  151. package/stacks/node/templates/build-kit/ralph-claude.js +44 -0
  152. package/stacks/node/templates/build-kit/ralph.sh +98 -0
  153. package/stacks/node/templates/root/.env.example +15 -0
  154. package/stacks/node/templates/root/CLAUDE.md +60 -0
  155. package/stacks/node/templates/root/docker-compose.yml +15 -0
  156. package/stacks/node/templates/root/flyway.conf +17 -0
  157. package/stacks/node/templates/root/migrations/V1__schema.sql.example +12 -0
  158. package/stacks/node/templates/root/package.json +50 -0
  159. package/stacks/node/templates/root/server.ts +130 -0
  160. package/stacks/node/templates/root/setup-env.sh +53 -0
  161. package/stacks/node/templates/root/src/common/assertions.ts +6 -0
  162. package/stacks/node/templates/root/src/common/db.ts +32 -0
  163. package/stacks/node/templates/root/src/common/loadPostgresEventstore.ts +23 -0
  164. package/stacks/node/templates/root/src/common/parseEndpoint.ts +51 -0
  165. package/stacks/node/templates/root/src/common/processorDlq.ts +28 -0
  166. package/stacks/node/templates/root/src/common/realtimeBroadcast.ts +12 -0
  167. package/stacks/node/templates/root/src/common/replay.ts +16 -0
  168. package/stacks/node/templates/root/src/common/routes.ts +19 -0
  169. package/stacks/node/templates/root/src/common/testHelpers.ts +44 -0
  170. package/stacks/node/templates/root/src/swagger.ts +34 -0
  171. package/stacks/node/templates/root/src/util/assertions.ts +6 -0
  172. package/stacks/node/templates/root/src/util/hash.ts +9 -0
  173. package/stacks/node/templates/root/src/util/sanitize.ts +23 -0
  174. package/stacks/node/templates/root/tsconfig.json +32 -0
  175. package/stacks/node/templates/root/vercel.json +8 -0
  176. package/stacks/supabase/templates/.claude/skills/build-automation/SKILL.md +266 -0
  177. package/stacks/supabase/templates/.claude/skills/build-state-change/SKILL.md +344 -0
  178. package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +390 -0
  179. package/stacks/supabase/templates/.claude/skills/build-webhook/SKILL.md +303 -0
  180. package/stacks/supabase/templates/.claude/skills/connect/SKILL.md +178 -0
  181. package/stacks/supabase/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
  182. package/stacks/supabase/templates/.claude/skills/load-slice/SKILL.md +143 -0
  183. package/stacks/supabase/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
  184. package/stacks/supabase/templates/build-kit/README.md +86 -0
  185. package/stacks/supabase/templates/build-kit/lib/AGENT.md +47 -0
  186. package/stacks/supabase/templates/build-kit/lib/agent.sh +20 -0
  187. package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +152 -0
  188. package/stacks/supabase/templates/build-kit/lib/prompt.md +123 -0
  189. package/stacks/supabase/templates/build-kit/lib/ralph.js +369 -0
  190. package/stacks/supabase/templates/build-kit/ralph-claude.js +44 -0
  191. package/stacks/supabase/templates/build-kit/ralph.sh +98 -0
  192. package/stacks/supabase/templates/root/.env.example +22 -0
  193. package/stacks/supabase/templates/root/CLAUDE.md +61 -0
  194. package/stacks/supabase/templates/root/flyway.conf +17 -0
  195. package/stacks/supabase/templates/root/package.json +52 -0
  196. package/stacks/supabase/templates/root/server.ts +177 -0
  197. package/stacks/supabase/templates/root/setup-env.sh +53 -0
  198. package/stacks/supabase/templates/root/src/common/assertions.ts +6 -0
  199. package/stacks/supabase/templates/root/src/common/db.ts +32 -0
  200. package/stacks/supabase/templates/root/src/common/loadPostgresEventstore.ts +23 -0
  201. package/stacks/supabase/templates/root/src/common/parseEndpoint.ts +51 -0
  202. package/stacks/supabase/templates/root/src/common/processorDlq.ts +28 -0
  203. package/stacks/supabase/templates/root/src/common/realtimeBroadcast.ts +19 -0
  204. package/stacks/supabase/templates/root/src/common/replay.ts +16 -0
  205. package/stacks/supabase/templates/root/src/common/routes.ts +23 -0
  206. package/stacks/supabase/templates/root/src/common/testHelpers.ts +54 -0
  207. package/stacks/supabase/templates/root/src/supabase/README.md +141 -0
  208. package/stacks/supabase/templates/root/src/supabase/api.ts +56 -0
  209. package/stacks/supabase/templates/root/src/supabase/requireOrgaAdmin.ts +32 -0
  210. package/stacks/supabase/templates/root/src/supabase/requireSysUser.ts +40 -0
  211. package/stacks/supabase/templates/root/src/supabase/requireUser.ts +72 -0
  212. package/stacks/supabase/templates/root/src/swagger.ts +34 -0
  213. package/stacks/supabase/templates/root/src/util/assertions.ts +6 -0
  214. package/stacks/supabase/templates/root/src/util/hash.ts +9 -0
  215. package/stacks/supabase/templates/root/src/util/sanitize.ts +23 -0
  216. package/stacks/supabase/templates/root/supabase/config.toml +295 -0
  217. package/stacks/supabase/templates/root/supabase/migrations/V1__schema.sql.example +12 -0
  218. package/stacks/supabase/templates/root/supabase/seed.sql +1 -0
  219. package/stacks/supabase/templates/root/tsconfig.json +32 -0
  220. package/stacks/supabase/templates/root/vercel.json +8 -0
@@ -0,0 +1,62 @@
1
+ # CratisApp — agent conventions
2
+
3
+ This is a **Cratis** application: Cratis Arc (CQRS) + Cratis Chronicle (event sourcing) + MongoDB read
4
+ models on the backend, React + TypeScript (Vite + PrimeReact) on the frontend, with **full-stack type
5
+ safety** via TypeScript proxy generation on `dotnet build`.
6
+
7
+ Build slices with the kit's skills — `/build-state-change`, `/build-state-view`, `/build-automation` —
8
+ and follow the conventions distilled in
9
+ `.build-kit/.claude/skills/_shared/cratis-conventions.md`. **The shipped example slice
10
+ under `SomeModule/SomeFeature/` is the concrete pattern to copy** — match its structure exactly.
11
+
12
+ ## Structure (learn from `SomeModule/SomeFeature/`)
13
+
14
+ ```
15
+ <Module>/<Feature>/
16
+ ├── <Feature>.tsx ← composition page (buttons, dialogs, tables)
17
+ ├── index.ts ← barrel: export * from './<Feature>'
18
+ ├── <Concept>.cs ← shared concepts (ConceptAs<T>)
19
+ └── <Slice>/ ← one slice = one behavior
20
+ ├── <Slice>.cs ← ALL backend artifacts for the slice in ONE file
21
+ ├── <Proxy>.ts ← GENERATED by dotnet build — never hand-edit
22
+ ├── <Component>.tsx ← React component using the generated proxy
23
+ └── index.ts ← barrel export
24
+ ```
25
+
26
+ - Top folder is a **module**, then a **feature**, then **slices**. Namespace is
27
+ `CratisApp.<Module>.<Feature>.<Slice>` (the `RootNamespace` is `CratisApp` — see `CratisApp.csproj`).
28
+ - **Proxies are generated next to the source** (`CratisProxiesUseSourceFileAsOutputFile=true` in the
29
+ `.csproj`): `Register.ts` sits beside `Registration.cs`. Frontend imports the proxy from the **same
30
+ folder** (`import { Register } from './Register'`). Files marked `// @generated` are never edited.
31
+
32
+ ## Non-negotiables (full detail in the shared conventions doc)
33
+
34
+ - ALL backend artifacts for a slice live in ONE `.cs` file.
35
+ - `[Command]` records define `Handle()` directly — never separate handler classes.
36
+ - `[EventType]` takes NO arguments; events are past-tense and never nullable.
37
+ - `ConceptAs<T>` for identity/value types — no raw `Guid` / `string` in the domain.
38
+ - `[ReadModel]` records expose queries as `public static` methods; observable queries return
39
+ `ISubject<T>` directly (`collection.Observe()`).
40
+ - Reactors implement the marker `IReactor`; dispatch is by the first parameter type. Write new events
41
+ only via `ICommandPipeline.Execute(...)`, never `IEventLog`. Keep reactors idempotent + stateless.
42
+ - Frontend: `CommandDialog` / `InputTextField` from `@cratis/components/*`; never import `Dialog` from
43
+ `primereact/dialog`. PrimeReact CSS variables / Tailwind classes for styling; no `any`.
44
+
45
+ ## Build, run, test
46
+
47
+ ```bash
48
+ docker-compose up -d # Chronicle (+ MongoDB) + Aspire dashboard
49
+ dotnet build # compiles backend AND regenerates TypeScript proxies
50
+ dotnet test # run specs (filter while iterating: --filter "FullyQualifiedName~<Slice>")
51
+ npm install && npm run dev # frontend dev server (Vite)
52
+ dotnet run # backend (http://localhost:5000, Swagger at /swagger)
53
+ ```
54
+
55
+ **Sequencing is strict:** a slice's frontend cannot reference its proxy until the backend compiles, so
56
+ always go Backend → `dotnet build` → Specs → Frontend → Composition page → Routes (`App.tsx`). Backend
57
+ and frontend of the same slice never run in parallel. Build must be zero-warning, zero-error.
58
+
59
+ ## Learn more
60
+
61
+ - Cratis docs: https://www.cratis.io/docs/
62
+ - Conventions: `.build-kit/.claude/skills/_shared/cratis-conventions.md`
@@ -0,0 +1,25 @@
1
+ <Project Sdk="Microsoft.NET.Sdk.Web">
2
+ <PropertyGroup>
3
+ <TargetFramework>net9.0</TargetFramework>
4
+ <RootNamespace>CratisApp</RootNamespace>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
8
+
9
+ <CratisProxiesOutputPath>$(MSBuildThisFileDirectory)</CratisProxiesOutputPath>
10
+ <CratisProxiesSegmentsToSkip>1</CratisProxiesSegmentsToSkip>
11
+ <CratisProxiesSkipOutputDeletion>true</CratisProxiesSkipOutputDeletion>
12
+ <CratisProxiesSkipCommandNameInRoute>true</CratisProxiesSkipCommandNameInRoute>
13
+ <CratisProxiesUseSourceFileAsOutputFile>true</CratisProxiesUseSourceFileAsOutputFile>
14
+ </PropertyGroup>
15
+
16
+ <ItemGroup>
17
+ <Content Remove="package.json" />
18
+ <None Remove="package.json" />
19
+ </ItemGroup>
20
+
21
+ <ItemGroup>
22
+ <PackageReference Include="Cratis" Version="*" />
23
+ <PackageReference Include="Cratis.Arc.MongoDB" Version="*" />
24
+ </ItemGroup>
25
+ </Project>
@@ -0,0 +1,18 @@
1
+ Microsoft Visual Studio Solution File, Format Version 12.00
2
+ # Visual Studio Version 17
3
+ VisualStudioVersion = 17.9.34728.123
4
+ MinimumVisualStudioVersion = 10.0.40219.1
5
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CratisApp", "CratisApp.csproj", "{6F1B2C3D-4E5A-6B7C-8D9E-0F1A2B3C4D5E}"
6
+ EndProject
7
+ Global
8
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
9
+ Debug|Any CPU = Debug|Any CPU
10
+ Release|Any CPU = Release|Any CPU
11
+ EndGlobalSection
12
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
13
+ {6F1B2C3D-4E5A-6B7C-8D9E-0F1A2B3C4D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14
+ {6F1B2C3D-4E5A-6B7C-8D9E-0F1A2B3C4D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
15
+ {6F1B2C3D-4E5A-6B7C-8D9E-0F1A2B3C4D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
16
+ {6F1B2C3D-4E5A-6B7C-8D9E-0F1A2B3C4D5E}.Release|Any CPU.Build.0 = Release|Any CPU
17
+ EndGlobalSection
18
+ EndGlobal
@@ -0,0 +1,3 @@
1
+ global using System.Reactive.Subjects;
2
+ global using Cratis.Arc.MongoDB;
3
+ global using MongoDB.Driver;
@@ -0,0 +1,102 @@
1
+
2
+
3
+
4
+ export const Home = () => {
5
+ return (
6
+ <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '80vh', padding: '2rem', textAlign: 'center' }}>
7
+ <svg style={{ borderRadius: 0, boxShadow: 'none', height: '120px', marginBottom: '2rem' }} width="600.000000pt" height="328.000000pt" viewBox="0 0 600.000000 328.000000" preserveAspectRatio="xMidYMid meet">
8
+ <g transform="translate(0.000000,328.000000) scale(0.100000,-0.100000)" fill="white" stroke="none">
9
+ <path d="M974 2789 c-319 -182 -592 -343 -607 -358 -16 -14 -34 -35 -40 -46
10
+ -8 -14 -10 -229 -9 -735 l3 -715 23 -35 c18 -26 74 -64 222 -151 110 -64 374
11
+ -219 589 -344 214 -126 400 -231 413 -233 13 -3 31 3 42 13 19 17 20 33 20
12
+ 307 0 233 -3 294 -15 317 -10 21 -93 74 -327 211 -172 101 -324 194 -338 207
13
+ l-25 23 0 401 0 401 27 23 c14 12 161 100 327 194 177 101 310 184 325 202
14
+ l26 31 0 293 c0 318 -1 325 -55 325 -12 0 -283 -149 -601 -331z"></path>
15
+ <path d="M4830 2314 c-62 -23 -90 -58 -90 -115 0 -22 10 -41 34 -65 30 -30 40
16
+ -34 85 -34 59 0 95 19 117 61 25 49 12 105 -32 134 -25 16 -91 27 -114 19z"></path>
17
+ <path d="M4310 2080 l0 -80 -55 0 -55 0 0 -80 0 -80 55 0 55 0 0 -168 c0 -164
18
+ 1 -170 28 -223 22 -44 36 -58 81 -81 45 -24 66 -28 131 -28 77 0 134 12 157
19
+ 34 8 8 5 28 -14 79 -21 55 -29 67 -42 61 -9 -4 -35 -9 -57 -12 -34 -3 -46 1
20
+ -63 19 -19 21 -21 34 -21 171 l0 148 80 0 80 0 0 80 0 80 -80 0 -80 0 0 80 0
21
+ 80 -100 0 -100 0 0 -80z"></path>
22
+ <path d="M1495 2019 c-178 -98 -219 -126 -237 -157 -15 -26 -18 -57 -18 -215
23
+ 0 -175 1 -186 23 -218 30 -45 326 -219 372 -219 34 0 319 157 361 199 24 23
24
+ 24 26 24 230 l0 207 -27 31 c-39 44 -319 203 -358 203 -19 0 -73 -24 -140 -61z"></path>
25
+ <path d="M2635 2006 c-110 -35 -200 -116 -230 -207 -22 -64 -22 -180 -1 -238
26
+ 35 -96 124 -178 225 -208 79 -23 231 -15 291 16 53 27 106 75 126 113 l14 27
27
+ -74 40 c-40 23 -76 41 -79 41 -2 0 -22 -18 -44 -39 -30 -30 -50 -41 -86 -46
28
+ -135 -20 -230 129 -167 261 49 101 177 119 259 37 l35 -35 69 33 c37 19 72 39
29
+ 78 45 13 15 -41 87 -90 119 -21 15 -60 33 -87 41 -58 17 -184 17 -239 0z"></path>
30
+ <path d="M3405 2008 c-16 -6 -47 -22 -67 -35 l-38 -23 0 30 0 30 -100 0 -100
31
+ 0 0 -330 0 -330 99 0 99 0 4 183 c3 159 6 187 24 222 25 49 89 85 151 85 l43
32
+ 0 0 90 0 90 -42 -1 c-24 0 -56 -5 -73 -11z"></path>
33
+ <path d="M3705 2007 c-61 -16 -145 -55 -145 -68 0 -7 56 -126 64 -136 1 -1 25
34
+ 9 53 23 61 31 155 42 206 25 43 -14 77 -53 77 -87 0 -24 -1 -24 -108 -24 -173
35
+ 0 -262 -34 -302 -116 -45 -92 -9 -203 83 -255 33 -18 62 -24 128 -27 97 -5
36
+ 144 6 189 45 l30 25 0 -31 0 -31 96 0 96 0 -5 228 c-2 125 -10 243 -16 263
37
+ -19 63 -65 115 -128 145 -51 25 -70 29 -163 31 -60 1 -127 -3 -155 -10z m255
38
+ -425 c0 -71 -86 -123 -168 -100 -42 12 -61 33 -62 69 0 25 21 51 50 62 8 3 52
39
+ 6 98 6 l82 1 0 -38z"></path>
40
+ <path d="M5207 2006 c-66 -19 -119 -58 -146 -107 -19 -34 -23 -52 -19 -109 3
41
+ -60 8 -73 33 -101 42 -44 94 -65 210 -84 109 -19 145 -35 145 -66 0 -55 -151
42
+ -63 -272 -15 -36 14 -67 26 -69 26 -9 0 -73 -140 -67 -146 4 -3 37 -17 75 -31
43
+ 90 -34 269 -44 353 -19 119 35 172 95 172 194 0 124 -50 164 -249 202 -56 10
44
+ -112 24 -123 30 -31 17 -22 51 20 73 45 23 149 17 216 -12 26 -12 48 -21 51
45
+ -21 5 0 63 129 63 140 0 5 -26 19 -57 31 -73 28 -261 36 -336 15z"></path>
46
+ <path d="M4760 1680 l0 -330 100 0 100 0 0 330 0 330 -100 0 -100 0 0 -330z"></path>
47
+ </g>
48
+ </svg>
49
+
50
+ <h1 style={{ color: 'white', fontSize: '1.5rem', fontWeight: 300, marginBottom: '1.5rem', opacity: 0.9 }}>
51
+ Welcome to your Cratis application 🚀
52
+ </h1>
53
+
54
+ <p style={{ color: 'rgba(255,255,255,0.7)', maxWidth: '600px', lineHeight: 1.7, marginBottom: '1rem' }}>
55
+ <strong style={{ color: 'white' }}>Event sourcing</strong> meets <strong style={{ color: 'white' }}>vertical slices</strong> — powered
56
+ by <strong style={{ color: 'white' }}>Cratis Arc</strong> and the <strong style={{ color: 'white' }}>Chronicle</strong> event store. 📜✨
57
+ </p>
58
+
59
+ <p style={{ color: 'rgba(255,255,255,0.7)', maxWidth: '600px', lineHeight: 1.7, marginBottom: '2rem' }}>
60
+ Every feature lives in one folder — events, commands, queries, projections, and React components side by side.
61
+ Capture intent as events, project read models, and build reactive UIs — all in one slice. 🧩
62
+ </p>
63
+
64
+ <div style={{ display: 'flex', gap: '1.5rem', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'stretch', marginBottom: '2rem' }}>
65
+ <InfoCard emoji="📖" title="README.md" description="Setup guide, project structure & getting started" />
66
+ <InfoCard emoji="🔗" title="cratis.io" description="Documentation, guides & community" link="https://cratis.io" />
67
+ <InfoCard emoji="🛠️" title="Swagger UI" description="Explore your API endpoints" link="/swagger" />
68
+ <InfoCard emoji="🎮" title="Demo" description="See it in action with a live example" link="/demo" />
69
+ </div>
70
+
71
+ <p style={{ color: 'rgba(255,255,255,0.4)', fontSize: '0.85rem' }}>
72
+ Generated with <code style={{ background: 'rgba(255,255,255,0.1)', padding: '2px 6px', borderRadius: '4px' }}>dotnet new cratis</code>
73
+ </p>
74
+ </div>
75
+ );
76
+ };
77
+
78
+ const InfoCard = ({ emoji, title, description, link }: { emoji: string; title: string; description: string; link?: string }) => {
79
+ const content = (
80
+ <div style={{
81
+ background: 'rgba(255,255,255,0.06)',
82
+ border: '1px solid rgba(255,255,255,0.1)',
83
+ borderRadius: '12px',
84
+ padding: '1.25rem 1.5rem',
85
+ width: '200px',
86
+ height: '100%',
87
+ boxSizing: 'border-box',
88
+ textAlign: 'left',
89
+ transition: 'background 0.2s',
90
+ cursor: link ? 'pointer' : 'default',
91
+ }}>
92
+ <div style={{ fontSize: '1.5rem', marginBottom: '0.5rem' }}>{emoji}</div>
93
+ <div style={{ color: 'white', fontWeight: 600, marginBottom: '0.25rem' }}>{title}</div>
94
+ <div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '0.85rem', lineHeight: 1.4 }}>{description}</div>
95
+ </div>
96
+ );
97
+
98
+ if (link) {
99
+ return <a href={link} target={link.startsWith('http') ? '_blank' : undefined} rel="noopener noreferrer" style={{ textDecoration: 'none' }}>{content}</a>;
100
+ }
101
+ return content;
102
+ };
@@ -0,0 +1,26 @@
1
+ var builder = WebApplication.CreateBuilder(args);
2
+ builder.AddCratis(
3
+ configureChronicleBuilder: chronicleBuilder => chronicleBuilder.WithCamelCaseNamingPolicy(),
4
+ configureArcBuilder: arcBuilder => arcBuilder.WithMongoDB(configureMongoDB: builder => builder.WithCamelCaseNamingPolicy()));
5
+
6
+ builder.Services.AddControllers();
7
+ builder.Services.AddMvc();
8
+ builder.Services.AddEndpointsApiExplorer();
9
+ builder.Services.AddSwaggerGen(options => options.AddConcepts());
10
+
11
+ var app = builder.Build();
12
+
13
+ app.UseRouting();
14
+
15
+ app.UseDefaultFiles();
16
+ app.UseStaticFiles();
17
+
18
+ app.UseWebSockets();
19
+ app.MapControllers();
20
+ app.UseCratis();
21
+
22
+ app.UseSwagger();
23
+ app.UseSwaggerUI();
24
+ app.MapFallbackToFile("/index.html");
25
+
26
+ await app.RunAsync();
@@ -0,0 +1,192 @@
1
+ # CratisApp
2
+
3
+ A web application built with Cratis Arc and Chronicle.
4
+
5
+ ## Prerequisites
6
+
7
+ - .NET 9.0 or later
8
+ - Docker and Docker Compose (for running Chronicle and Aspire Dashboard)
9
+ - Node.js 20 or later
10
+ - A package manager (yarn, pnpm, or npm)
11
+
12
+ ## Getting Started
13
+
14
+ 1. Start the infrastructure:
15
+
16
+ ```bash
17
+ docker-compose up -d
18
+ ```
19
+
20
+ This will start:
21
+
22
+ - Chronicle (with MongoDB on port 27017)
23
+ - Aspire Dashboard (on port 18888)
24
+
25
+ 2. Install frontend dependencies:
26
+
27
+ ```bash
28
+ npm install
29
+ ```
30
+
31
+ 3. Start the frontend development server:
32
+
33
+ ```bash
34
+ npm run dev
35
+ ```
36
+
37
+ 4. Run the application:
38
+
39
+ ```bash
40
+ dotnet run
41
+ ```
42
+
43
+ The application will be available at:
44
+
45
+ - Backend API: http://localhost:5000
46
+ - Swagger UI: http://localhost:5000/swagger
47
+ - Frontend: http://localhost:5173 (Vite dev server)
48
+ - Aspire Dashboard: http://localhost:18888
49
+
50
+ ## Project Structure
51
+
52
+ ```shell
53
+ CratisApp.csproj - .NET project file
54
+ Program.cs - Application entry point
55
+ GlobalUsings.cs - Global using directives
56
+ appsettings.json - Configuration
57
+ package.json - Node.js dependencies
58
+ tsconfig.json - TypeScript configuration
59
+ docker-compose.yml - Infrastructure services
60
+ .frontend/ - Frontend application shell
61
+ index.html - HTML entry point
62
+ main.tsx - React entry point
63
+ App.tsx - Root React component
64
+ index.css - Global styles
65
+ vite.config.ts - Vite configuration
66
+ <Module>/ - A domain module
67
+ <Feature>/ - A vertical slice
68
+ <Feature>.tsx - React composition page
69
+ <Feature>.cs - Backend C# code
70
+ index.ts - TypeScript barrel export
71
+ <Slice>/ - Sub-slice
72
+ ...
73
+ ```
74
+
75
+ ## Vertical Slices
76
+
77
+ This template follows a **vertical slice architecture** where backend and frontend code live side by side in the same folder. Each feature folder holds all the artifacts needed for that slice — C# commands, queries, events, and React components — rather than separating them by layer (e.g. `Controllers/`, `Services/`, `Components/`).
78
+
79
+ This makes it easy to reason about a feature, evolve it independently, and keep related code together.
80
+
81
+ - Each slice is a self-contained unit of functionality from UI to backend.
82
+ - C# and TypeScript files coexist in the same directory.
83
+ - Run `dotnet build` after backend changes to regenerate the TypeScript proxies used by the frontend.
84
+
85
+ ## Cratis Build Tool (Proxy Generation)
86
+
87
+ This template is designed to work with `Cratis.Arc.ProxyGenerator.Build`, which generates TypeScript command/query proxies during `dotnet build`.
88
+
89
+ ### Add package reference
90
+
91
+ If not already present, add the build package to your `.csproj`:
92
+
93
+ ```xml
94
+ <ItemGroup>
95
+ <PackageReference Include="Cratis.Arc.ProxyGenerator.Build" Version="<version>" />
96
+ </ItemGroup>
97
+ ```
98
+
99
+ ### Required setting
100
+
101
+ `CratisProxiesOutputPath` tells the build tool where generated TypeScript proxies should be written.
102
+
103
+ ```xml
104
+ <PropertyGroup>
105
+ <CratisProxiesOutputPath>$(MSBuildThisFileDirectory)Features</CratisProxiesOutputPath>
106
+ </PropertyGroup>
107
+ ```
108
+
109
+ ### Common configuration
110
+
111
+ ```xml
112
+ <PropertyGroup>
113
+ <CratisProxiesOutputPath>$(MSBuildThisFileDirectory)Features</CratisProxiesOutputPath>
114
+ <CratisProxiesSegmentsToSkip>1</CratisProxiesSegmentsToSkip>
115
+ <CratisProxiesSkipOutputDeletion>true</CratisProxiesSkipOutputDeletion>
116
+ <CratisProxiesSkipCommandNameInRoute>true</CratisProxiesSkipCommandNameInRoute>
117
+ <CratisProxiesSkipQueryNameInRoute>false</CratisProxiesSkipQueryNameInRoute>
118
+ <CratisProxiesApiPrefix>api</CratisProxiesApiPrefix>
119
+ <CratisProxiesSkipFileIndexTracking>false</CratisProxiesSkipFileIndexTracking>
120
+ <CratisProxiesSkipIndexGeneration>false</CratisProxiesSkipIndexGeneration>
121
+ </PropertyGroup>
122
+ ```
123
+
124
+ ### What each setting does
125
+
126
+ - `CratisProxiesOutputPath`: Output directory for generated proxies.
127
+ - `CratisProxiesSegmentsToSkip`: Skips namespace segments when creating folder paths.
128
+ - `CratisProxiesSkipOutputDeletion`: When `false` (default), output folder is deleted on each build; set `true` for incremental generation.
129
+ - `CratisProxiesSkipCommandNameInRoute`: Excludes command names from generated routes when possible.
130
+ - `CratisProxiesSkipQueryNameInRoute`: Excludes query names from generated routes when possible.
131
+ - `CratisProxiesApiPrefix`: API prefix used in generated routes (default `api`).
132
+ - `CratisProxiesSkipFileIndexTracking`: Disables orphan-file tracking when `true`.
133
+ - `CratisProxiesSkipIndexGeneration`: Disables `index.ts` generation when `true`.
134
+
135
+ ### Automatic routes and proxy generation
136
+
137
+ Arc automatically maps model-bound commands and queries to HTTP routes based on namespace conventions.
138
+
139
+ Keep runtime (`appsettings.json`) and proxy generation (`.csproj`) settings aligned:
140
+
141
+ - `Cratis:Arc:GeneratedApis:RoutePrefix` <-> `CratisProxiesApiPrefix`
142
+ - `Cratis:Arc:GeneratedApis:SegmentsToSkipForRoute` <-> `CratisProxiesSegmentsToSkip`
143
+ - `Cratis:Arc:GeneratedApis:IncludeCommandNameInRoute` <-> inverse of `CratisProxiesSkipCommandNameInRoute`
144
+ - `Cratis:Arc:GeneratedApis:IncludeQueryNameInRoute` <-> inverse of `CratisProxiesSkipQueryNameInRoute`
145
+
146
+ If these are out of sync, generated TypeScript proxies can call routes that do not match mapped backend endpoints.
147
+
148
+ In this template, both segment-skip settings are set to `1`:
149
+
150
+ ```json
151
+ {
152
+ "Cratis": {
153
+ "Arc": {
154
+ "GeneratedApis": {
155
+ "RoutePrefix": "api",
156
+ "IncludeCommandNameInRoute": false,
157
+ "SegmentsToSkipForRoute": 1
158
+ }
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ ```xml
165
+ <PropertyGroup>
166
+ <CratisProxiesSegmentsToSkip>1</CratisProxiesSegmentsToSkip>
167
+ <CratisProxiesSkipCommandNameInRoute>true</CratisProxiesSkipCommandNameInRoute>
168
+ </PropertyGroup>
169
+ ```
170
+
171
+ `IncludeQueryNameInRoute` is not explicitly set in this template, so the Arc default (`true`) applies. This matches proxy generation default `CratisProxiesSkipQueryNameInRoute=false`.
172
+
173
+ When command/query names are excluded, both runtime mapping and proxy generation automatically re-include names when needed to avoid route collisions.
174
+
175
+ ### Verify generation
176
+
177
+ Run:
178
+
179
+ ```bash
180
+ dotnet build
181
+ ```
182
+
183
+ Then inspect your configured `CratisProxiesOutputPath` directory for generated proxies.
184
+
185
+ ## Learn More
186
+
187
+ - [Cratis Arc Documentation](https://www.cratis.io/docs/Arc/)
188
+ - [Cratis Arc ASP.NET Core Configuration](https://www.cratis.io/docs/Arc/backend/asp-net-core/configuration.html)
189
+ - [Cratis Arc Proxy Generation Configuration](https://www.cratis.io/docs/Arc/backend/proxy-generation/index.html)
190
+ - [Cratis Arc Model Bound Commands](https://www.cratis.io/docs/Arc/backend/commands/model-bound/index.html)
191
+ - [Cratis Arc Model Bound Queries](https://www.cratis.io/docs/Arc/backend/queries/model-bound/index.html)
192
+ - [Chronicle Documentation](https://www.cratis.io/docs/Chronicle/)
@@ -0,0 +1,47 @@
1
+ // @generated - This file is automatically generated by the Cratis proxy generator. Do not edit manually.
2
+
3
+ /* eslint-disable sort-imports */
4
+ import { ObservableQueryFor, QueryResultWithState, Sorting, Paging } from '@cratis/arc/queries';
5
+ import { useObservableQuery, useObservableQueryWithPaging, SetSorting, SetPage, SetPageSize } from '@cratis/arc.react/queries';
6
+ import { ParameterDescriptor } from '@cratis/arc/reflection';
7
+ import { Listing } from './Listing';
8
+
9
+ class AllListingsSortBy {
10
+ constructor(readonly query: AllListings) {}
11
+ }
12
+
13
+ class AllListingsSortByWithoutQuery {}
14
+
15
+ export class AllListings extends ObservableQueryFor<Listing[]> {
16
+ readonly route: string = '/api/some-module/some-feature/listing/all-listings';
17
+ readonly defaultValue: Listing[] = [];
18
+ private readonly _sortBy: AllListingsSortBy;
19
+ private static readonly _sortBy: AllListingsSortByWithoutQuery = new AllListingsSortByWithoutQuery();
20
+
21
+ constructor() {
22
+ super(Listing, true);
23
+ this._sortBy = new AllListingsSortBy(this);
24
+ }
25
+
26
+ get requiredRequestParameters(): string[] {
27
+ return [];
28
+ }
29
+
30
+ readonly parameterDescriptors: ParameterDescriptor[] = [];
31
+
32
+ get sortBy(): AllListingsSortBy {
33
+ return this._sortBy;
34
+ }
35
+
36
+ static get sortBy(): AllListingsSortByWithoutQuery {
37
+ return this._sortBy;
38
+ }
39
+
40
+ static use(sorting?: Sorting): [QueryResultWithState<Listing[]>, SetSorting] {
41
+ return useObservableQuery<Listing[], AllListings>(AllListings, undefined, sorting);
42
+ }
43
+
44
+ static useWithPaging(pageSize: number, sorting?: Sorting): [QueryResultWithState<Listing[]>, SetSorting, SetPage, SetPageSize] {
45
+ return useObservableQueryWithPaging<Listing[], AllListings>(AllListings, new Paging(0, pageSize), undefined, sorting);
46
+ }
47
+ }
@@ -0,0 +1,11 @@
1
+ using CratisApp.SomeModule.SomeFeature.Registration;
2
+
3
+ namespace CratisApp.SomeModule.SomeFeature.Listing;
4
+
5
+ [ReadModel]
6
+ [FromEvent<Registered>]
7
+ public record Listing(Guid Id, SomeName Name, EventSourceId EventSourceId)
8
+ {
9
+ public static ISubject<IEnumerable<Listing>> AllListings(IMongoCollection<Listing> collection) =>
10
+ collection.Observe();
11
+ }
@@ -0,0 +1,12 @@
1
+ // @generated - This file is automatically generated by the Cratis proxy generator. Do not edit manually.
2
+
3
+ /* eslint-disable sort-imports */
4
+ import { field } from '@cratis/fundamentals';
5
+
6
+ export class Listing {
7
+ @field(String)
8
+ name!: string;
9
+
10
+ @field(String)
11
+ eventSourceId!: string;
12
+ }
@@ -0,0 +1,17 @@
1
+ import { DataTableForObservableQuery } from '@cratis/components/DataTables';
2
+ import { AllListings } from './AllListings';
3
+ import { Column } from 'primereact/column';
4
+
5
+ export const ListingDataTable = () => {
6
+ return (
7
+ <>
8
+ <DataTableForObservableQuery
9
+ query={AllListings}
10
+ dataKey='eventSourceId'
11
+ emptyMessage='No items registered yet.'>
12
+ <Column field='name' header='Name' />
13
+ <Column field='eventSourceId' header='Id' />
14
+ </DataTableForObservableQuery>
15
+ </>
16
+ );
17
+ }
@@ -0,0 +1 @@
1
+ export * from './ListingDataTable';
@@ -0,0 +1,51 @@
1
+ // @generated - This file is automatically generated by the Cratis proxy generator. Do not edit manually.
2
+
3
+ /* eslint-disable sort-imports */
4
+ /* eslint-disable @typescript-eslint/no-empty-interface */
5
+ import { Command, CommandValidator } from '@cratis/arc/commands';
6
+ import { useCommand, SetCommandValues, ClearCommandValues } from '@cratis/arc.react/commands';
7
+ import { PropertyDescriptor } from '@cratis/arc/reflection';
8
+ import { Guid } from '@cratis/fundamentals';
9
+
10
+ export interface IRegister {
11
+ name?: string;
12
+ }
13
+
14
+ export class RegisterValidator extends CommandValidator<IRegister> {
15
+ constructor() {
16
+ super();
17
+ }
18
+ }
19
+
20
+ export class Register extends Command<IRegister, Guid> implements IRegister {
21
+ readonly route: string = '/api/some-module/some-feature/registration';
22
+ readonly validation: CommandValidator = new RegisterValidator();
23
+ readonly propertyDescriptors: PropertyDescriptor[] = [
24
+ new PropertyDescriptor('name', String, false),
25
+ ];
26
+
27
+ private _name!: string;
28
+
29
+ constructor() {
30
+ super(Guid, false);
31
+ }
32
+
33
+ get requestParameters(): string[] {
34
+ return [];
35
+ }
36
+
37
+ get name(): string {
38
+ return this._name;
39
+ }
40
+
41
+ set name(value: string) {
42
+ this._name = value;
43
+ this.propertyChanged('name');
44
+ }
45
+
46
+ static use(initialValues?: IRegister): [Register, SetCommandValues<IRegister>, ClearCommandValues] {
47
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
48
+ // @ts-ignore
49
+ return useCommand<Register, IRegister>(Register, initialValues);
50
+ }
51
+ }
@@ -0,0 +1,18 @@
1
+ import { CommandDialog } from '@cratis/components/CommandDialog';
2
+ import { InputTextField } from '@cratis/components/CommandForm';
3
+ import { Register } from './Register';
4
+
5
+ export const RegisterDialog = () => {
6
+ return (
7
+ <CommandDialog
8
+ command={Register}
9
+ title='Register'
10
+ okLabel='Register'
11
+ cancelLabel='Cancel'>
12
+ <InputTextField<Register>
13
+ value={c => c.name}
14
+ title='Name'
15
+ icon={<i className='pi pi-pencil' />} />
16
+ </CommandDialog>
17
+ );
18
+ }
@@ -0,0 +1,27 @@
1
+ namespace CratisApp.SomeModule.SomeFeature.Registration;
2
+
3
+ [Command]
4
+ public record Register(SomeName Name)
5
+ {
6
+ public (Guid, Registered) Handle()
7
+ {
8
+ var eventSourceId = Guid.NewGuid();
9
+
10
+ return (eventSourceId, new(Name));
11
+ }
12
+ }
13
+
14
+ [EventType]
15
+ public record Registered(SomeName Name);
16
+
17
+ public partial class RegistrationReactor(ILogger<RegistrationReactor> logger) : IReactor
18
+ {
19
+ public Task Handle(Registered evt)
20
+ {
21
+ LogRegistered(evt.Name);
22
+ return Task.CompletedTask;
23
+ }
24
+
25
+ [LoggerMessage(LogLevel.Information, "Registered: {Name}")]
26
+ partial void LogRegistered(string name);
27
+ }
@@ -0,0 +1 @@
1
+ export * from './RegisterDialog';
@@ -0,0 +1,22 @@
1
+ import { Button } from 'primereact/button';
2
+ import { RegisterDialog } from './Registration';
3
+ import { ListingDataTable } from './Listing';
4
+ import { useDialog } from '@cratis/arc.react/dialogs';
5
+
6
+ export const SomeFeature = () => {
7
+ const [RegistrationDialog, showRegistrationDialog] = useDialog(RegisterDialog);
8
+
9
+ return (
10
+ <div className='p-4'>
11
+ <div className='flex justify-between items-center mb-4'>
12
+ <h1 className='text-2xl font-bold'>SomeFeature</h1>
13
+ <Button
14
+ label='Register'
15
+ icon='pi pi-plus'
16
+ onClick={() => showRegistrationDialog()} />
17
+ </div>
18
+ <ListingDataTable />
19
+ <RegistrationDialog />
20
+ </div>
21
+ );
22
+ };
@@ -0,0 +1,3 @@
1
+ namespace CratisApp.SomeModule.SomeFeature;
2
+
3
+ public record SomeName(string Value) : ConceptAs<string>(Value);
@@ -0,0 +1 @@
1
+ export * from './SomeFeature';