Skip to content

feat(shared): wire Wolverine durable inbox/outbox per ADR-009#58

Merged
phuongnse merged 4 commits into
mainfrom
feat/wolverine-postgres-persistence
May 22, 2026
Merged

feat(shared): wire Wolverine durable inbox/outbox per ADR-009#58
phuongnse merged 4 commits into
mainfrom
feat/wolverine-postgres-persistence

Conversation

@phuongnse

@phuongnse phuongnse commented May 22, 2026

Copy link
Copy Markdown
Owner

Summary

First implementation step toward the ADR-009 Wolverine durable inbox/outbox rollout. Configures PersistMessagesWithPostgresql(..., "wolverine") in Axis.Api.Program, adds a ConnectionStrings:Wolverine entry (same database as the modules), and auto-provisions the dedicated schema in Development + Testing via AddResourceSetupOnStartup(). No DbContext is enlisted yet — the existing in-memory bus.PublishAsync in Axis.Shared.Infrastructure.Persistence.UnitOfWork stays until each module integrates via .IntegrateWithWolverine() in follow-up PRs. Also pins Npgsql 9.0.4 centrally to resolve a transitive version conflict surfaced by WolverineFx.Postgresql.

Linked spec

Requirements & rules followed

  • Spec → code — matches ADR-009: dedicated wolverine schema, fully-qualified table names, dev auto-setup + prod scripted migration. PROGRESS.md Shared Kernel note flipped from "decided" to "partial — schema wired, DbContext enlistment pending"
  • Gate 0 — N/A: cross-cutting infra step, no new ACs
  • Gate 1dotnet build 0/0, all unit-test projects green, dotnet format --verify-no-changes green. Testcontainers integration tests deferred to CI (local Docker not available)
  • Gate 2docs/PROGRESS.md, docs/epics/E01-platform-foundation/features/F01-tenant-registration.md updated in same PR; ./scripts/check-doc-drift.sh green
  • Gate 3 — no new durable rule; ADR-009 already captures the contract
  • No new TODO / FIXME / placeholder / stub

Summary by CodeRabbit

  • New Features

    • Enabled durable PostgreSQL persistence for Wolverine messaging (inbox/outbox) and added a dedicated Wolverine connection.
    • Auto-provisioning of the Wolverine schema in development and testing.
  • Documentation

    • Progress and design notes updated to reflect Wolverine persistence status, tenant provisioning decisions, and rollout considerations.
  • Chores

    • Central package version updated for Npgsql to 9.0.4; Wolverine Postgres package added.
  • Tests

    • Test fixtures now include configuration for the Wolverine connection string.

Review Change Stack

Configure WolverineFx.Postgresql to persist envelopes in the dedicated
`wolverine` schema in the primary application database. The schema is
auto-provisioned on startup in Development and Testing via
AddResourceSetupOnStartup; production runs a scripted SQL migration.

Adds a new ConnectionStrings:Wolverine entry (same database as the
modules) and pins Npgsql 9.0.4 centrally to resolve a transitive
version conflict surfaced by WolverineFx.Postgresql.

No DbContext is enlisted yet — the existing in-memory PublishAsync
in Axis.Shared.Infrastructure.Persistence.UnitOfWork stays until each
module integrates via .IntegrateWithWolverine() in follow-up PRs. The
PROGRESS.md Shared Kernel note reflects this partial state.
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Wires Wolverine durable inbox/outbox to PostgreSQL wolverine schema: adds package refs and central Npgsql version, requires a Wolverine connection string, configures persistence and dev/test auto-provisioning, updates app settings and tests, and amends docs/feature notes.

Changes

Wolverine PostgreSQL Persistence

Layer / File(s) Summary
Package Dependencies
Directory.Packages.props, src/Axis.Api/Axis.Api.csproj
Npgsql version 9.0.4 is centrally managed, and WolverineFx.Postgresql and Npgsql package references are added to the API project.
Wolverine Persistence Configuration
src/Axis.Api/Program.cs
Program startup now requires a Wolverine connection string, configures Wolverine to persist durable inbox/outbox to PostgreSQL schema wolverine, adds required using imports, and registers AddResourceSetupOnStartup() for Development/Testing to auto-create the schema and tables on startup.
Connection Strings and Test Setup
src/Axis.Api/appsettings.json, tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs
Wolverine connection string is added to application settings alongside the existing WorkflowEngine connection, and the test fixture is updated to set ConnectionStrings__Wolverine env var, add it to in-memory config before host build, and clear it on dispose.
Progress and Feature Notes
docs/PROGRESS.md, docs/epics/E01-platform-foundation/features/F01-tenant-registration.md
Wolverine durable inbox/outbox status is updated from "not configured" to "partial" with notes on current PostgreSQL persistence configuration, pending DbContext integration, and tenant provisioning decisions (async provisioning, deterministic tenant schema naming, and transition to durable outbox).

Sequence Diagram

sequenceDiagram
  participant Program
  participant WolverineConfig
  participant PostgreSQL
  participant ResourceSetup
  Program->>WolverineConfig: Read ConnectionStrings:Wolverine
  Program->>WolverineConfig: Configure UseWolverine(...).PersistMessagesWithPostgresql(schema: "wolverine")
  WolverineConfig->>PostgreSQL: Store durable inbox/outbox messages
  Program->>ResourceSetup: AddResourceSetupOnStartup() if Env ∈ {Development, Testing}
  ResourceSetup->>PostgreSQL: Create `wolverine` schema and tables
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code with a curious squeak,
Schemas planted wolverine strong and sleek,
Durable hops now nest in Postgres' care,
Tests set the path, configs all aware,
A rabbit cheers — messages travel fair.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: wiring Wolverine durable inbox/outbox persistence with a reference to the relevant ADR-009 decision record.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wolverine-postgres-persistence

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/epics/E01-platform-foundation/features/F01-tenant-registration.md`:
- Around line 113-115: The Implementation status callout for US-003 is missing
the "Decisions" line; update the callout block (the one containing
"Implementation status — Domain: …", "Gaps vs spec", and "Deferred (PR `#50`
follow-up)") to add a "Decisions:" entry summarizing the chosen design (e.g.,
durable retry policy deferred to Wolverine persistence per ADR-009, Admin
assignment on verify, and async provisioning via ProvisionTenantMessage handled
by ProvisionTenantHandler), and mention the pending
IdentityDbContext.IntegrateWithWolverine() rollout where relevant so the callout
includes Implementation status, Gaps vs spec, Deferred follow-ups, and Decisions
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: deb41ffd-016a-4a97-a02d-17a167566d67

📥 Commits

Reviewing files that changed from the base of the PR and between 31ecb14 and dc56e8f.

📒 Files selected for processing (7)
  • Directory.Packages.props
  • docs/PROGRESS.md
  • docs/epics/E01-platform-foundation/features/F01-tenant-registration.md
  • src/Axis.Api/Axis.Api.csproj
  • src/Axis.Api/Program.cs
  • src/Axis.Api/appsettings.json
  • tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs

phuongnse added 3 commits May 22, 2026 18:59
CI surfaced two issues on PR #58:

1. Integration tests failed with "Failed to setup resource Envelope
   Storage of type Wolverine — Connection refused at 127.0.0.1:5432".
   Root cause: `builder.Configuration.GetConnectionString("Wolverine")`
   was read eagerly into a local before
   `WebApplicationFactory.ConfigureAppConfiguration` applied the test
   Testcontainer override. Move the read into the UseWolverine lambda
   so resolution happens at host-build time against the live
   ConfigurationManager.

2. CodeRabbit flagged the US-003 callout for missing the `Decisions:`
   line required by CLAUDE.md's "Definition of done" template. Add
   the line covering async provisioning dispatch, the
   `tenant_{orgId:N}` schema-name format, and the planned move to
   durable Wolverine outbox once IdentityDbContext is enlisted.
WebApplicationFactory.ConfigureAppConfiguration on IWebHostBuilder
does not reach the WebApplicationBuilder.Configuration that Program.cs
reads during host build (the order is wrong relative to Wolverine's
PersistMessagesWithPostgresql call). Setting the connection string
as an env var works because the default config provider reads it
before the IWebHostBuilder hook runs.

The env var is cleared in DisposeAsync to avoid polluting other
test fixtures.
EF Core's EnsureCreatedAsync uses a heuristic: if any user table exists
in the target database, skip schema creation. Wolverine's
AddResourceSetupOnStartup hosted service ran before the fixture's
IdentityDbContext.EnsureCreatedAsync call and created
wolverine.outgoing_envelopes (and friends) in the default postgres
database, so EF Core then skipped creating the OpenIddict tables.

Point Wolverine at axis_wolverine_test (alongside the per-module test
DBs) so the two schema-creation paths no longer share a database.
Production keeps the single-database layout per ADR-009.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs`:
- Line 73: The in-memory configuration for "ConnectionStrings:Wolverine" is
being set to _postgres.GetConnectionString() causing a mismatch with the
environment variable that points to _wolverineConnectionString; update the code
that seeds the in-memory config (in ApiTestFixture where you build the test
configuration / ConfigureAppConfiguration) to use _wolverineConnectionString
instead of calling _postgres.GetConnectionString(), ensuring the in-memory
config key "ConnectionStrings:Wolverine" and the
Environment.SetEnvironmentVariable call both reference the same
_wolverineConnectionString value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 42e60d57-4a6a-49d1-9de5-08b19b8f7ac5

📥 Commits

Reviewing files that changed from the base of the PR and between 9f341bf and ecae598.

📒 Files selected for processing (1)
  • tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs

// during host build, which runs before WebApplicationFactory's
// ConfigureAppConfiguration hook is applied to builder.Configuration.
// Set it via env var so the default config provider picks it up.
Environment.SetEnvironmentVariable("ConnectionStrings__Wolverine", _wolverineConnectionString);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where Wolverine connection string is consumed and whether this fixture value can override it.

set -euo pipefail

echo "== Locate Wolverine connection string reads =="
rg -n -C3 'ConnectionStrings:Wolverine|GetConnectionString\s*\(\s*"Wolverine"\s*\)|PersistMessagesWithPostgresql' --type=cs

echo
echo "== Inspect Program startup wiring =="
fd -i 'Program.cs' src tests | xargs -r rg -n -C5 'PersistMessagesWithPostgresql|ConnectionStrings|Wolverine'

echo
echo "== Inspect fixture config block for mismatch =="
rg -n -C4 'ConnectionStrings:Wolverine|ConnectionStrings__Wolverine' tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs

Repository: phuong-labs/axis

Length of output: 7006


Synchronize in-memory ConnectionStrings:Wolverine config with the dedicated test database value.

Line 88 should use _wolverineConnectionString instead of _postgres.GetConnectionString(). The environment variable on line 73 correctly points to the dedicated Wolverine test DB (axis_wolverine_test), but the in-memory config falls back to the shared DB. This inconsistency risks tests using the wrong database if configuration resolution precedence changes or if the value is read again after in-memory config is applied.

Fix
                    ["ConnectionStrings:Wolverine"] = _postgres.GetConnectionString(),
+                   ["ConnectionStrings:Wolverine"] = _wolverineConnectionString,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Api/Axis.Api.Tests/Helpers/ApiTestFixture.cs` at line 73, The in-memory
configuration for "ConnectionStrings:Wolverine" is being set to
_postgres.GetConnectionString() causing a mismatch with the environment variable
that points to _wolverineConnectionString; update the code that seeds the
in-memory config (in ApiTestFixture where you build the test configuration /
ConfigureAppConfiguration) to use _wolverineConnectionString instead of calling
_postgres.GetConnectionString(), ensuring the in-memory config key
"ConnectionStrings:Wolverine" and the Environment.SetEnvironmentVariable call
both reference the same _wolverineConnectionString value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant