@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.
- package/README.md +175 -0
- package/cli.js +676 -0
- package/package.json +35 -0
- package/shared/build-kit/code-export.mjs +560 -0
- package/shared/build-kit/lib/ollama-agent.js +147 -0
- package/shared/build-kit/package.json +11 -0
- package/shared/build-kit/ralph-ollama.js +39 -0
- package/shared/build-kit/realtime-agent.js +18 -0
- package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +407 -0
- package/stacks/axon/templates/.claude/skills/build-automation/references/feature-flag-patterns.md +114 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/SKILL.md +496 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/axon-workflow-api.md +279 -0
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/references/feature-flag-patterns.md +114 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/SKILL.md +396 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/axon-test-fixture-patterns.md +162 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/feature-flag-patterns.md +56 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/references/rest-api-patterns.md +115 -0
- package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +282 -0
- package/stacks/axon/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/axon/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +611 -0
- package/stacks/axon/templates/.claude/skills/load-slice/SKILL.md +141 -0
- package/stacks/axon/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
- package/stacks/axon/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/axon/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/axon/templates/build-kit/lib/backend-prompt.md +158 -0
- package/stacks/axon/templates/build-kit/lib/prompt.md +126 -0
- package/stacks/axon/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/axon/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/axon/templates/build-kit/ralph.sh +98 -0
- package/stacks/axon/templates/root/.env.example +5 -0
- package/stacks/axon/templates/root/CLAUDE.md +60 -0
- package/stacks/axon/templates/root/README.md +44 -0
- package/stacks/axon/templates/root/docker-compose.yml +64 -0
- package/stacks/axon/templates/root/mvnw +259 -0
- package/stacks/axon/templates/root/mvnw.cmd +149 -0
- package/stacks/axon/templates/root/pom.xml +125 -0
- package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/QuickstartApplication.java +128 -0
- package/stacks/axon/templates/root/src/main/java/io/axoniq/quickstart/config/WebConfig.java +155 -0
- package/stacks/axon/templates/root/src/main/resources/application.properties +2 -0
- package/stacks/axon/templates/root/src/main/resources/static/bg-body.png +0 -0
- package/stacks/axon/templates/root/src/main/resources/static/bg-header.png +0 -0
- package/stacks/axon/templates/root/src/main/resources/static/index.html +596 -0
- package/stacks/cratis-csharp/templates/.claude/skills/_shared/cratis-conventions.md +251 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +99 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-automation/references/patterns.md +115 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +163 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/references/patterns.md +234 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +120 -0
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/references/patterns.md +166 -0
- package/stacks/cratis-csharp/templates/.claude/skills/connect/SKILL.md +169 -0
- package/stacks/cratis-csharp/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +609 -0
- package/stacks/cratis-csharp/templates/.claude/skills/load-slice/SKILL.md +141 -0
- package/stacks/cratis-csharp/templates/.claude/skills/update-slice-status/SKILL.md +105 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/AGENT.md +58 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/backend-prompt.md +129 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/prompt.md +124 -0
- package/stacks/cratis-csharp/templates/build-kit/lib/ralph.js +302 -0
- package/stacks/cratis-csharp/templates/build-kit/ralph-claude.js +37 -0
- package/stacks/cratis-csharp/templates/build-kit/ralph.sh +98 -0
- package/stacks/cratis-csharp/templates/root/.frontend/index.css +29 -0
- package/stacks/cratis-csharp/templates/root/.frontend/index.html +17 -0
- package/stacks/cratis-csharp/templates/root/.frontend/main.tsx +18 -0
- package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.json +42 -0
- package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.node.json +11 -0
- package/stacks/cratis-csharp/templates/root/.frontend/vite.config.ts +56 -0
- package/stacks/cratis-csharp/templates/root/App.tsx +23 -0
- package/stacks/cratis-csharp/templates/root/CLAUDE.md +62 -0
- package/stacks/cratis-csharp/templates/root/CratisApp.csproj +25 -0
- package/stacks/cratis-csharp/templates/root/CratisApp.sln +18 -0
- package/stacks/cratis-csharp/templates/root/GlobalUsings.cs +3 -0
- package/stacks/cratis-csharp/templates/root/Home.tsx +102 -0
- package/stacks/cratis-csharp/templates/root/Program.cs +26 -0
- package/stacks/cratis-csharp/templates/root/README.md +192 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/AllListings.ts +47 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.cs +11 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.ts +12 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx +17 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Register.ts +51 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx +18 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs +27 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeFeature.tsx +22 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeName.cs +3 -0
- package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/index.ts +1 -0
- package/stacks/cratis-csharp/templates/root/appsettings.Development.json +9 -0
- package/stacks/cratis-csharp/templates/root/appsettings.json +26 -0
- package/stacks/cratis-csharp/templates/root/docker-compose.yml +23 -0
- package/stacks/cratis-csharp/templates/root/package.json +33 -0
- package/stacks/cratis-csharp/templates/root/tsconfig.json +3 -0
- package/stacks/modeling-kit/templates/.claude/settings.local.json +13 -0
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +215 -0
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +176 -0
- package/stacks/modeling-kit/templates/.claude/skills/connect/SKILL.md +182 -0
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +383 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +465 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +587 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/facilitating-event-modeling-workshops.md +626 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +542 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +497 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +783 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +604 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +699 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +674 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +231 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +150 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +329 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +204 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +352 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/project-planning-with-event-modeling.md +341 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +153 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +136 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +78 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +85 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +655 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +479 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +234 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +353 -0
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +200 -0
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +94 -0
- package/stacks/modeling-kit/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +441 -0
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +290 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +212 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +123 -0
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +353 -0
- package/stacks/modeling-kit/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +134 -0
- package/stacks/modeling-kit/templates/kit/lib/agent.sh +20 -0
- package/stacks/modeling-kit/templates/kit/lib/ollama-agent.js +147 -0
- package/stacks/modeling-kit/templates/kit/lib/ralph.js +286 -0
- package/stacks/modeling-kit/templates/kit/package.json +12 -0
- package/stacks/modeling-kit/templates/kit/ralph-claude.js +50 -0
- package/stacks/modeling-kit/templates/kit/ralph-ollama.js +38 -0
- package/stacks/modeling-kit/templates/kit/ralph.sh +61 -0
- package/stacks/modeling-kit/templates/kit/realtime-agent.js +18 -0
- package/stacks/modeling-kit/templates/root/CLAUDE.md +56 -0
- package/stacks/node/templates/.claude/skills/build-automation/SKILL.md +266 -0
- package/stacks/node/templates/.claude/skills/build-state-change/SKILL.md +344 -0
- package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +412 -0
- package/stacks/node/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/node/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
- package/stacks/node/templates/.claude/skills/load-slice/SKILL.md +143 -0
- package/stacks/node/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/node/templates/build-kit/README.md +86 -0
- package/stacks/node/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/node/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/node/templates/build-kit/lib/backend-prompt.md +152 -0
- package/stacks/node/templates/build-kit/lib/prompt.md +122 -0
- package/stacks/node/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/node/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/node/templates/build-kit/ralph.sh +98 -0
- package/stacks/node/templates/root/.env.example +15 -0
- package/stacks/node/templates/root/CLAUDE.md +60 -0
- package/stacks/node/templates/root/docker-compose.yml +15 -0
- package/stacks/node/templates/root/flyway.conf +17 -0
- package/stacks/node/templates/root/migrations/V1__schema.sql.example +12 -0
- package/stacks/node/templates/root/package.json +50 -0
- package/stacks/node/templates/root/server.ts +130 -0
- package/stacks/node/templates/root/setup-env.sh +53 -0
- package/stacks/node/templates/root/src/common/assertions.ts +6 -0
- package/stacks/node/templates/root/src/common/db.ts +32 -0
- package/stacks/node/templates/root/src/common/loadPostgresEventstore.ts +23 -0
- package/stacks/node/templates/root/src/common/parseEndpoint.ts +51 -0
- package/stacks/node/templates/root/src/common/processorDlq.ts +28 -0
- package/stacks/node/templates/root/src/common/realtimeBroadcast.ts +12 -0
- package/stacks/node/templates/root/src/common/replay.ts +16 -0
- package/stacks/node/templates/root/src/common/routes.ts +19 -0
- package/stacks/node/templates/root/src/common/testHelpers.ts +44 -0
- package/stacks/node/templates/root/src/swagger.ts +34 -0
- package/stacks/node/templates/root/src/util/assertions.ts +6 -0
- package/stacks/node/templates/root/src/util/hash.ts +9 -0
- package/stacks/node/templates/root/src/util/sanitize.ts +23 -0
- package/stacks/node/templates/root/tsconfig.json +32 -0
- package/stacks/node/templates/root/vercel.json +8 -0
- package/stacks/supabase/templates/.claude/skills/build-automation/SKILL.md +266 -0
- package/stacks/supabase/templates/.claude/skills/build-state-change/SKILL.md +344 -0
- package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +390 -0
- package/stacks/supabase/templates/.claude/skills/build-webhook/SKILL.md +303 -0
- package/stacks/supabase/templates/.claude/skills/connect/SKILL.md +178 -0
- package/stacks/supabase/templates/.claude/skills/learn-eventmodelers-api/SKILL.md +628 -0
- package/stacks/supabase/templates/.claude/skills/load-slice/SKILL.md +143 -0
- package/stacks/supabase/templates/.claude/skills/update-slice-status/SKILL.md +110 -0
- package/stacks/supabase/templates/build-kit/README.md +86 -0
- package/stacks/supabase/templates/build-kit/lib/AGENT.md +47 -0
- package/stacks/supabase/templates/build-kit/lib/agent.sh +20 -0
- package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +152 -0
- package/stacks/supabase/templates/build-kit/lib/prompt.md +123 -0
- package/stacks/supabase/templates/build-kit/lib/ralph.js +369 -0
- package/stacks/supabase/templates/build-kit/ralph-claude.js +44 -0
- package/stacks/supabase/templates/build-kit/ralph.sh +98 -0
- package/stacks/supabase/templates/root/.env.example +22 -0
- package/stacks/supabase/templates/root/CLAUDE.md +61 -0
- package/stacks/supabase/templates/root/flyway.conf +17 -0
- package/stacks/supabase/templates/root/package.json +52 -0
- package/stacks/supabase/templates/root/server.ts +177 -0
- package/stacks/supabase/templates/root/setup-env.sh +53 -0
- package/stacks/supabase/templates/root/src/common/assertions.ts +6 -0
- package/stacks/supabase/templates/root/src/common/db.ts +32 -0
- package/stacks/supabase/templates/root/src/common/loadPostgresEventstore.ts +23 -0
- package/stacks/supabase/templates/root/src/common/parseEndpoint.ts +51 -0
- package/stacks/supabase/templates/root/src/common/processorDlq.ts +28 -0
- package/stacks/supabase/templates/root/src/common/realtimeBroadcast.ts +19 -0
- package/stacks/supabase/templates/root/src/common/replay.ts +16 -0
- package/stacks/supabase/templates/root/src/common/routes.ts +23 -0
- package/stacks/supabase/templates/root/src/common/testHelpers.ts +54 -0
- package/stacks/supabase/templates/root/src/supabase/README.md +141 -0
- package/stacks/supabase/templates/root/src/supabase/api.ts +56 -0
- package/stacks/supabase/templates/root/src/supabase/requireOrgaAdmin.ts +32 -0
- package/stacks/supabase/templates/root/src/supabase/requireSysUser.ts +40 -0
- package/stacks/supabase/templates/root/src/supabase/requireUser.ts +72 -0
- package/stacks/supabase/templates/root/src/swagger.ts +34 -0
- package/stacks/supabase/templates/root/src/util/assertions.ts +6 -0
- package/stacks/supabase/templates/root/src/util/hash.ts +9 -0
- package/stacks/supabase/templates/root/src/util/sanitize.ts +23 -0
- package/stacks/supabase/templates/root/supabase/config.toml +295 -0
- package/stacks/supabase/templates/root/supabase/migrations/V1__schema.sql.example +12 -0
- package/stacks/supabase/templates/root/supabase/seed.sql +1 -0
- package/stacks/supabase/templates/root/tsconfig.json +32 -0
- 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,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
|
+
}
|
package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx
ADDED
|
@@ -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
|
+
}
|
package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx
ADDED
|
@@ -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
|
+
}
|
package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs
ADDED
|
@@ -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 @@
|
|
|
1
|
+
export * from './SomeFeature';
|