Skip to content

Commit 884957b

Browse files
authored
Merge branch '15.3.0' into copilot/support-migration-of-events
2 parents 1d3e78f + e7cb309 commit 884957b

File tree

108 files changed

+3455
-330
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+3455
-330
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: 'kind/bug'
6+
assignees: ''
7+
---
8+
9+
## Describe the bug
10+
11+
A clear and concise description of what the bug is.
12+
13+
## Steps to reproduce
14+
15+
1. ...
16+
2. ...
17+
3. ...
18+
19+
## Expected behavior
20+
21+
A clear and concise description of what you expected to happen.
22+
23+
## Actual behavior
24+
25+
A clear and concise description of what actually happens.
26+
27+
## Environment
28+
29+
- OS: [e.g. Windows 11, Ubuntu 22.04, macOS 14]
30+
- .NET version: [e.g. 8.0.x]
31+
- Chronicle version: [e.g. 9.x.x]
32+
33+
## Additional context
34+
35+
Add any other context, logs, or screenshots about the problem here.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea or improvement for Chronicle
4+
title: ''
5+
labels: 'kind/feature'
6+
assignees: ''
7+
---
8+
9+
## Problem / motivation
10+
11+
A clear and concise description of the problem this feature would solve, or the motivation behind the request.
12+
For example: "I often run into a situation where..."
13+
14+
## Proposed solution
15+
16+
A clear and concise description of what you would like to happen.
17+
18+
## Alternatives considered
19+
20+
A description of any alternative solutions or features you have considered, and why the proposed solution is preferred.
21+
22+
## Additional context
23+
24+
Add any other context, mockups, or examples about the feature request here.

.github/copilot-instructions.md

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,58 +19,21 @@ When these instructions don't explicitly cover a situation, apply these values t
1919
- Always use American English spelling in all code, comments, and documentation (e.g. "color" not "colour", "behavior" not "behaviour").
2020
- Write clear and concise comments for each function.
2121
- Make only high confidence suggestions when reviewing code changes.
22-
- Always use the latest version C#, currently C# 13 features.
2322
- Never change global.json unless explicitly asked to.
2423
- Never change package.json or package-lock.json files unless explicitly asked to.
2524
- Never change NuGet.config files unless explicitly asked to.
26-
- Never leave unused using statements in the code.
2725
- Always ensure that the code compiles without warnings.
2826
- Always ensure that the code passes all tests.
2927
- Always ensure that the code adheres to the project's coding standards.
3028
- Always ensure that the code is maintainable.
31-
- Review Directory.Build.props and .editorconfig for all warnings configured as errors.
32-
- Never generate code that would violate these warning settings.
33-
- Always respect the project's nullable reference type settings.
3429
- Always reuse the active terminal for commands.
3530
- Do not create new terminals unless current one is busy or fails.
3631

37-
## Chronicle & Arc Key Conventions
38-
39-
These conventions exist because the frameworks rely on convention-based discovery. Breaking them doesn't just violate style — it breaks runtime behavior.
40-
41-
- `[EventType]` takes **no arguments** — the type name is used automatically. Adding a GUID or string argument is a common mistake from other frameworks; Chronicle does not use it.
42-
- `[Command]` records define `Handle()` directly on the record — never create separate handler classes. The framework discovers `Handle()` by convention; a separate class breaks that discovery.
43-
- `[ReadModel]` records define static query methods directly on the record. The proxy generator creates TypeScript hooks from these methods automatically.
44-
- Prefer `ConceptAs<T>` over raw primitives in all domain models, commands, events, and queries. This prevents accidental mix-ups (passing a `UserId` where an `AuthorId` was expected) and makes APIs self-documenting.
45-
- Use model-bound projection attributes (`[FromEvent<T>]`, `[SetFrom<T>]`, etc.) when possible; fall back to `IProjectionFor<T>` for complex cases.
46-
- For fluent projections, AutoMap is on by default — just call `.From<>()` directly.
47-
- Projections join **events**, never read models. This is fundamental to event sourcing: projections rebuild state from the event stream, not from other projections.
48-
- `IReactor` is a marker interface — method dispatch is by first-parameter event type, method name is descriptive.
49-
- All backend artifacts for a vertical slice go in a **single `.cs` file**. This keeps cohesion high and makes the scope of a slice immediately visible.
50-
51-
## Proxy Generation — Build Dependency
52-
53-
Commands and Queries generate TypeScript proxies at build time via `dotnet build`. This creates `.ts` files that the frontend imports (hooks, execute methods, change tracking). Until the backend compiles, **no proxy files exist** and frontend code cannot reference them.
54-
55-
**This is a hard sequencing constraint:**
56-
1. Backend C# code must be written and compile successfully first.
57-
2. `dotnet build` must complete — this generates the TypeScript proxy files.
58-
3. Only then can frontend React components import and use the generated proxies.
59-
60-
**When running parallel agents or sub-agents:** backend and frontend work for the same slice **cannot** run in parallel. The backend agent must finish and `dotnet build` must succeed before the frontend agent starts. Independent slices (no shared events) can have their backends worked on in parallel, but each slice's frontend still depends on its own backend build completing first.
61-
6232
## Development Workflow
6333

6434
- After creating each new file, run `dotnet build` (C#) or `yarn compile` (TypeScript) immediately before proceeding to the next file. Fix all errors as they appear — never accumulate technical debt.
6535
- Before adding parameters to interfaces or function signatures, review all usages to ensure the new parameter is needed at every call site.
6636
- When modifying imports, audit all occurrences — verify additions are used and removals don't break other files.
67-
- Never use placeholder or temporary types — use proper types from the start.
68-
- Review each file for lint compliance before moving on.
69-
- The user may keep Storybook running — do not try to stop it, suggest stopping it, or start your own instance.
70-
71-
## TypeScript Type Safety
72-
73-
- Never use `any` — use `unknown`, `Record<string, unknown>`, or proper generic constraints instead. See [TypeScript Conventions](./instructions/typescript.instructions.md) for detailed patterns.
7437

7538
## Detailed Guides
7639

@@ -90,3 +53,12 @@ These guides contain the full rules, examples, and rationale for each topic. The
9053
- [Dialogs](./instructions/dialogs.instructions.md)
9154
- [Reactors](./instructions/reactors.instructions.md)
9255
- [Orleans](./instructions/orleans.instructions.md)
56+
57+
## Header
58+
59+
All files should start with the following header:
60+
61+
```csharp
62+
// Copyright (c) Cratis. All rights reserved.
63+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
64+
```

.github/instructions/csharp.instructions.md

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,21 +131,6 @@ The framework discovers and wires dependencies by convention. Explicit registrat
131131
- Use `async`/`await` for asynchronous programming.
132132
- Use `Task` and `Task<T>` for asynchronous methods.
133133

134-
## File Header
135-
136-
Every C# file must start with:
137-
138-
```csharp
139-
// Copyright (c) Cratis. All rights reserved.
140-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
141-
```
142-
143-
## Generated Files
144-
145-
**Never edit generated files.** Files produced by code generators, scaffolding tools, or any other automated tool must not be modified by hand — in any language. Generated files are overwritten on the next build, so hand-edits are silently lost and create false confidence that a fix is in place.
146-
147-
- If the generated output is wrong, fix the **source** (the template, the generator configuration, or the source type) and rebuild.
148-
149134
## Chronicle & Arc — Key API Types
150135

151136
These are the building blocks. Each type has a specific role in the vertical slice architecture — using the right type in the right place means the framework handles discovery, wiring, and proxy generation automatically.
@@ -167,3 +152,9 @@ These are the building blocks. Each type has a specific role in the vertical sli
167152
| `EventContext` | Event metadata: `Occurred`, `SequenceNumber`, `CorrelationId`, `EventSourceId`, etc. |
168153
| `ISubject<T>` | Observable query return type — enables real-time WebSocket push |
169154
| `IMongoCollection<T>` | MongoDB collection — use `.Observe()` for reactive queries |
155+
156+
**Key conventions:**
157+
- Prefer `ConceptAs<T>` over raw primitives in all domain models, commands, events, and queries — prevents accidental mix-ups and makes APIs self-documenting. See [concepts.instructions.md](./concepts.instructions.md) for details.
158+
- Projections join **events**, never read models — projections rebuild state from the event stream, not from other projections.
159+
- For fluent projections, AutoMap is on by default — just call `.From<EventType>()` without manually mapping every property.
160+
- Use model-bound projection attributes (`[FromEvent<T>]`, `[SetFrom<T>]`, etc.) when possible; fall back to `IProjectionFor<T>` for complex cases.

.github/instructions/dialogs.instructions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ The Cratis dialog wrappers handle command execution, validation timing, loading
1818
- Pass the command constructor to `command={}`. `CommandDialog` handles instantiation, execution, and confirm/cancel buttons.
1919
- Use command form fields (`InputTextField`, `TextAreaField`, etc. from `@cratis/components/CommandForm`) for user-input values.
2020
- `CommandDialog` automatically disables confirm while the command executes.
21-
- Use `onBeforeExecute` only for values that cannot come from form fields (for example generated IDs).
21+
- Any value that must be present for the form to be considered valid (i.e. passes `validateRequiredProperties`) must be supplied via `initialValues`, **not** via `onBeforeExecute`.
22+
- `onBeforeExecute` fires only at execution time — the command is already validated before it runs, so values set there never influence `isValid` and the OK/Submit button will remain permanently disabled.
23+
- Use `initialValues` for injected context values (e.g. a parent entity id passed as a prop).
24+
- Use `onBeforeExecute` only for transformations that should not affect form validity (e.g. generated IDs).
2225
2326
```tsx
2427
import { DialogProps, DialogResult } from '@cratis/arc.react/dialogs';

.github/instructions/efcore.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
applyTo: "**/*Context*.cs, **/Database/**/*.cs, **/Migrations/**/*.cs"
2+
applyTo: "**/*.cs"
33
---
44

55
# Entity Framework Core Instructions

.github/instructions/pull-requests.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
applyTo: ".github/**"
2+
applyTo: "**/*"
33
---
44

55
# How to Do Pull Requests

.github/instructions/specs.csharp.instructions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,11 @@ public class and_name_already_exists(context context) : Given<context>(context)
239239

240240
- Don't break long `should_` method lines — prefer one-line lambda assertions.
241241
- Don't add blank lines between multiple `should_` methods.
242+
243+
## Entity Framework Core Specs
244+
245+
- Use SQLite in-memory database for specs involving `DbContext`.
246+
- `SaveChanges` / `SaveChangesAsync` are virtual and can be mocked with NSubstitute.
247+
- `DbSet` methods are virtual — mock as needed.
248+
- Pass options when substituting: `Substitute.For<YourDbContext>(options)`.
242249
- Simulate failures by mocking `SaveChanges` to throw exceptions.

.github/instructions/typescript.instructions.md

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
11
---
2-
applyTo: "**/*.ts, **/*.tsx"
2+
applyTo: "**/*.ts,**/*.tsx"
33
---
44

55
# TypeScript Conventions
66

77
TypeScript's type system is the primary tool for catching bugs before they reach production. Every rule here pushes toward maximum compiler coverage and self-documenting code. If the types are right, the code almost writes itself.
88

9-
## Variables and Naming
10-
11-
- Prefer `const` over `let` over `var`.
12-
- Never use shortened or abbreviated names for variables, parameters, or properties.
13-
- Use full descriptive names: `deltaX` not `dx`, `index` not `idx`, `event` not `e`, `previous` not `prev`, `direction` not `dir`, `position` not `pos`, `contextMenu` not `ctx`/`ctxMenu`.
14-
- The only acceptable short names are well-established domain terms (e.g. `id`, `url`, `min`, `max`).
15-
- Never leave unused import statements in the code.
16-
- Always ensure the code compiles without warnings — run `yarn compile` to verify (no output means success).
17-
18-
## Folder Structure and Naming
19-
20-
- Do not prefix a file, component, type, or symbol with the name of its containing folder or concept — use folder structure to provide that context instead.
21-
- Favor functional folder structure over technical folder structure.
22-
- Group files by the feature or concept they belong to, not by their technical role.
23-
- Avoid folders like `components/`, `hooks/`, `utils/`, `types/` at the feature level.
24-
259
## Enums over Magic Strings
2610

2711
String literal unions look concise but provide no refactoring support, no namespace, and no discoverability. Enums give you all three — plus `switch` exhaustiveness checking.
@@ -57,37 +41,9 @@ Each type gets its own file because it makes the codebase navigable — finding
5741
`any` disables the compiler — the one tool that catches bugs for free. Every `any` is a hole in the safety net. Use `unknown` and narrow with type guards instead.
5842

5943
- Never use `any` — use `unknown`, `Record<string, unknown>`, or proper generic constraints.
60-
- Use proper generic constraints: `<TCommand extends object = object>` not `= any`.
61-
- Use `unknown` as the default generic parameter: `<T = unknown>` not `<T = any>`.
6244
- Prefer `value as unknown as TargetType` over `value as any`.
63-
- For objects with dynamic properties: `(obj as unknown as { prop: Type }).prop`.
64-
65-
### Event Handlers
66-
45+
- Use `unknown` as default generic parameter instead of `any`.
6746
- React synthetic events (`React.MouseEvent<Element, MouseEvent>`) and DOM events (`MouseEvent`) are different types — don't mix them.
68-
- Convert between them: `nativeEvent as unknown as React.MouseEvent`.
69-
- Use `e.preventDefault?.()` instead of `(e as any).preventDefault?.()`.
70-
71-
### Generic React Components
72-
73-
- Use `React.ComponentType<Props>` for React component types.
74-
- For Storybook components with no props: `React.ComponentType<Record<string, never>>`.
75-
- When converting component imports in Storybook: always `as unknown as` to avoid type mismatch errors.
76-
- Properly type story args — never use `any`.
77-
78-
### External Libraries
79-
80-
- Use proper library types when available (e.g. PIXI types, not `any`).
81-
- Use specific property types: `{ canvas?: HTMLCanvasElement }` instead of `any`.
82-
- When library generics have strict constraints, thread types through `unknown`: `props.command as unknown as Constructor<Command<...>>`.
83-
- Extract tuple results explicitly rather than destructuring when type assertions are needed.
84-
85-
### Unknown Values
86-
87-
- Add type guards before using function parameters of unknown type: `if (typeof accessor !== 'function') return ''`.
88-
- Type parameters with fallbacks: `function<T = unknown>(accessor: ((obj: T) => unknown) | unknown)`.
89-
- Cast unknown objects to record before property access: `(obj as Record<string, unknown>).items`.
90-
- Use `String(value)` for string conversions; `new Date(value as string | number | Date)` for dates.
9147

9248
## Localised Strings
9349

@@ -146,22 +102,6 @@ For attribute strings (e.g. `title`, `placeholder`, `aria-label`):
146102
- **Never** use plain string literals for user-visible text in JSX or attribute props. This includes `label`, `header`, `placeholder`, `title`, `aria-label`, `emptyMessage`, and any visible text nodes.
147103
- Only constant, non-localised values are allowed as raw strings (CSS class names, `key` props, internal identifiers).
148104

149-
## File Header
150-
151-
Every TypeScript file must start with:
152-
153-
```typescript
154-
// Copyright (c) Cratis. All rights reserved.
155-
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
156-
```
157-
158-
## Generated Files
159-
160-
**Never edit generated files.** Files produced by the proxy generator (`dotnet build`), code scaffolding tools, or any other automated tool must not be modified by hand — in any language. Generated files are overwritten on the next build, so hand-edits are silently lost and create false confidence that a fix is in place.
161-
162-
- If the generated output is wrong, fix the **source** (the C# record, the template, or the generator configuration) and rebuild.
163-
- Generated TypeScript proxy files (commands, queries, observable queries) are always regenerated from C# sources. Never edit them directly.
164-
165105
## Arc Frontend Patterns
166106

167107
Arc's proxy generator bridges C# and TypeScript automatically — every `[Command]` and `[ReadModel]` becomes a TypeScript class with `.use()` hooks, `.execute()` methods, and change tracking. This is the foundation of full-stack type safety: change a C# record and the TypeScript proxy updates on the next `dotnet build`.
@@ -202,3 +142,46 @@ Wraps multiple command-using components, aggregating their `hasChanges` state an
202142
### CommandForm
203143

204144
Declarative form component with built-in field types, validation timing (`validateOn: blur|change|both`), and automatic server-side validation feedback.
145+
146+
## Variables and Naming
147+
148+
- Prefer `const` over `let` over `var` when declaring variables.
149+
- Never use shortened or abbreviated names for variables, parameters, or properties.
150+
- Use full descriptive names: `deltaX` not `dx`, `index` not `idx`, `event` not `e`, `previous` not `prev`, `direction` not `dir`, `position` not `pos`, `contextMenu` not `ctx`/`ctxMenu`.
151+
- The only acceptable short names are well-established domain terms (e.g. `id`, `url`, `min`, `max`).
152+
153+
## Imports and Compilation
154+
155+
- Never leave unused import statements in the code.
156+
- Always ensure that the code compiles without warnings — use `yarn compile` to verify (successful runs produce no output).
157+
- Review each file for lint compliance before finalizing.
158+
- Never use placeholder or temporary types — use proper types from the start.
159+
160+
## Folder Structure
161+
162+
- Do not prefix a file, component, type, or symbol with the name of its containing folder or the concept it belongs to. Instead, use folder structure to provide that context.
163+
- Favor functional folder structure over technical folder structure.
164+
- Group files by the feature or concept they belong to, not by their technical role.
165+
- Avoid folders like `components/`, `hooks/`, `utils/`, `types/` at the feature level.
166+
167+
## Advanced Type Safety
168+
169+
Additional patterns for common tricky scenarios:
170+
171+
**Storybook:**
172+
- Use `React.ComponentType<Record<string, never>>` for components with no props.
173+
- Always use `as unknown as` when converting component imports to avoid type mismatch errors.
174+
- Properly type story args — never use `any`.
175+
176+
**External libraries with strict generic constraints:**
177+
- Import necessary types (e.g. `Command` from `@cratis/arc/commands`) rather than asserting to `any`.
178+
- Use type assertions through `unknown`: `props.command as unknown as Constructor<Command<...>>`.
179+
- Extract tuple results explicitly rather than destructuring when type assertions are needed.
180+
- Use proper library types when available; use specific property types (e.g. `{ canvas?: HTMLCanvasElement }`) over `any`.
181+
182+
**Dynamic and generic types:**
183+
- Add type guards for unknown function parameters: `if (typeof accessor !== 'function') return ''`.
184+
- Type parameters with fallbacks: `function<T = unknown>(accessor: ((obj: T) => unknown) | unknown)`.
185+
- Cast arrays from `unknown` explicitly: `((obj as Record<string, unknown>).items || []) as string[]`.
186+
- Use `String(value)` for string conversions in generic contexts.
187+
- Use explicit Date parameter types: `new Date(value as string | number | Date)`.

0 commit comments

Comments
 (0)