Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions backend/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
<!-- Persistence — Marten + Wolverine (event-sourcing + outbox) -->
<PackageVersion Include="Marten" Version="8.37.1" />
<PackageVersion Include="Marten.EntityFrameworkCore" Version="8.37.1" />
<PackageVersion Include="WolverineFx" Version="5.39.3" />
<PackageVersion Include="WolverineFx.EntityFrameworkCore" Version="5.39.3" />
<PackageVersion Include="WolverineFx.Marten" Version="5.39.3" />
<PackageVersion Include="Marten" Version="9.2.1" />
<PackageVersion Include="Marten.EntityFrameworkCore" Version="9.2.1" />
<PackageVersion Include="WolverineFx" Version="6.1.0" />
<PackageVersion Include="WolverineFx.EntityFrameworkCore" Version="6.1.0" />
<PackageVersion Include="WolverineFx.Marten" Version="6.1.0" />
<PackageVersion Include="WolverineFx.RuntimeCompilation" Version="6.1.0" />
<!-- Observability — OpenTelemetry -->
<PackageVersion Include="OpenTelemetry" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Text.Json;
using Marten.Schema;
using JasperFx;

namespace RunCoach.Api.Infrastructure.Idempotency;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using JasperFx.Events;
using JasperFx.Events.Daemon;
using JasperFx.Events.Projections;
using JasperFx.MultiTenancy;
using JasperFx.OpenTelemetry;
using Marten;
using Marten.EntityFrameworkCore;
using Marten.Services;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ namespace RunCoach.Api.Modules.Coaching.Onboarding;

/// <summary>
/// Inline single-stream projection that materializes the runner's in-flight onboarding state
/// into an <see cref="OnboardingView"/> Marten document (spec 13 § Unit 1, R01.4). Marten's
/// codegen wires each <c>Apply</c> overload below to the corresponding event type via
/// pattern-matching at startup; the document is upserted on the same <c>IDocumentSession</c>
/// as the event append, preserving atomicity for the per-turn handler.
/// into an <see cref="OnboardingView"/> Marten document (spec 13 § Unit 1, R01.4). Marten 9's
/// compile-time JasperFx source generator dispatches each <c>Apply</c>/<c>Create</c> convention
/// method below to its event type, which is why this class must be declared <c>partial</c>; the
/// document is upserted on the same <c>IDocumentSession</c> as the event append, preserving
/// atomicity for the per-turn handler.
/// </summary>
/// <remarks>
/// <para>
Expand All @@ -22,7 +23,7 @@ namespace RunCoach.Api.Modules.Coaching.Onboarding;
/// branch so the in-memory view stays in sync with the EF projection (DEC-060 / R-069).
/// </para>
/// </remarks>
public sealed class OnboardingProjection : SingleStreamProjection<OnboardingView, Guid>
public sealed partial class OnboardingProjection : SingleStreamProjection<OnboardingView, Guid>
{
/// <summary>
/// Initializes a new instance of the <see cref="OnboardingProjection"/> class. Marten's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ namespace RunCoach.Api.Modules.Training.Plan;
/// <summary>
/// Inline single-stream projection that materializes a Plan stream into a
/// <see cref="PlanProjectionDto"/> Marten document the frontend renders directly
/// (spec 13 § Unit 2, R02.3). Marten's codegen wires each <c>Apply</c> overload
/// below to its event type via pattern-matching at startup; the document is
/// (spec 13 § Unit 2, R02.3). Marten 9's compile-time JasperFx source generator
/// dispatches each <c>Apply</c>/<c>Create</c> convention method below to its event
/// type, which is why this class must be declared <c>partial</c>; the document is
/// upserted on the same <c>IDocumentSession</c> as the event append, preserving
/// atomicity for the calling handler (Unit 1 onboarding terminal-branch handler
/// in Slice 1, Unit 5 regenerate handler later).
Expand All @@ -28,7 +29,7 @@ namespace RunCoach.Api.Modules.Training.Plan;
/// <c>Apply</c> methods - no breaking changes for the Slice 1 frontend.
/// </para>
/// </remarks>
public sealed class PlanProjection : SingleStreamProjection<PlanProjectionDto, Guid>
public sealed partial class PlanProjection : SingleStreamProjection<PlanProjectionDto, Guid>
{
/// <summary>
/// Initializes a new instance of the <see cref="PlanProjection"/> class. Marten's
Expand Down
12 changes: 7 additions & 5 deletions backend/src/RunCoach.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@
// default retry pipeline and re-runs the handler, defeating the
// "first response wins" contract the marker exists to enforce.
//
// Note: `DocumentAlreadyExistsException` is a sibling — not a parent — of
// the two stream-collision exceptions in Marten's hierarchy, so the rule
// must be registered explicitly; the existing two registrations do not
// cover it transitively.
// Note: `DocumentAlreadyExistsException` is not a parent of the two
// stream-collision exceptions — Marten 9 relocated it to the shared
// `JasperFx` assembly (`JasperFx.DocumentAlreadyExistsException`) while the
// stream-collision pair stays in `Marten.Exceptions`, so no inheritance
// links them and the rule must be registered explicitly; the existing two
// registrations do not cover it transitively.
opts.OnException<Marten.Exceptions.ExistingStreamIdCollisionException>().MoveToErrorQueue();
opts.OnException<Marten.Exceptions.ConcurrentUpdateException>().MoveToErrorQueue();
opts.OnException<Marten.Exceptions.DocumentAlreadyExistsException>().MoveToErrorQueue();
opts.OnException<JasperFx.DocumentAlreadyExistsException>().MoveToErrorQueue();

// Must match Marten's `AddAsyncDaemon(DaemonMode.Solo)` — `HotCold` takes
// advisory locks that collide with `ApplyAllDatabaseChangesOnStartup`.
Expand Down
7 changes: 7 additions & 0 deletions backend/src/RunCoach.Api/RunCoach.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
<PackageReference Include="WolverineFx" />
<PackageReference Include="WolverineFx.EntityFrameworkCore" />
<PackageReference Include="WolverineFx.Marten" />
<!-- Wolverine 6 extracted runtime Roslyn code generation into this package.
Required because Development (dev runs + the integration-test host) boots
with CodeGeneration.TypeLoadMode.Auto (Program.cs), which compiles handler
and projection dispatch code at startup; without it the host throws
"No IAssemblyGenerator is registered". Production uses TypeLoadMode.Static
(pre-generated) and never invokes runtime compilation. -->
<PackageReference Include="WolverineFx.RuntimeCompilation" />
<!-- Observability -->
<PackageReference Include="OpenTelemetry" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FluentAssertions;
using JasperFx;
using Marten.Exceptions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand Down
Loading