Skip to content

Persistence#252

Merged
DigiBanks99 merged 5 commits intomainfrom
feat/peristence
Apr 15, 2026
Merged

Persistence#252
DigiBanks99 merged 5 commits intomainfrom
feat/peristence

Conversation

@DigiBanks99
Copy link
Copy Markdown
Owner

@DigiBanks99 DigiBanks99 commented Apr 15, 2026

PR 252 - Persistence Layer Infrastructure (Issue #242 - Foundation Only)

Summary

This PR implements the core persistence infrastructure for Menlo, establishing the foundation for EF Core + PostgreSQL integration. It delivers the basic application layer framework (DbContext, DI, interceptors, and slice interfaces) and validates the approach with a complete User persistence example.

Status: Partially implements Issue #242. This PR establishes the persistence layer infrastructure and patterns; additional work is required to extend to all bounded contexts and complete documentation updates. See "What's Missing" section.

What's Implemented

✅ Persistence Infrastructure

  • MenloDbContext scoped DbContext with snake_case naming convention
  • ServiceCollectionExtensions with AddMenloApplication() DI setup
  • AuditingInterceptor - automatic audit field population (created_at, created_by, updated_at, updated_by)
  • SoftDeleteInterceptor - transparent soft-delete handling (is_deleted, deleted_at, deleted_by)
  • ReflectiveAuditStampFactory - reflection-based audit context resolution with HTTP principal capture

✅ Domain Contracts (Menlo.Lib)

  • ISoftDeletable interface (IsDeleted, DeletedAt, DeletedBy)
  • ISoftDeleteStampFactory interface
  • User entity updated to implement ISoftDeletable

✅ User Persistence - Complete Example

  • IUserContext slice interface for Auth bounded context
  • UserEntityTypeConfiguration with shared.users table, UUID mapping, audit + soft-delete support
  • 3 migrations: InitialCreate, AddUserEntity, AddSoftDeleteToUsers

✅ Integration Testing

  • TestContainers-based PostgreSQL fixtures (real database, no in-memory EF)
  • UserContextIntegrationTests, SoftDeleteIntegrationTests, PersistenceInterceptorIntegrationTests, MigrationSmokeTests

✅ Deployment Integration

  • Aspire PostgreSQL provisioning in local dev
  • MigrateDatabaseAsync() on API startup (fail-fast on schema errors)
  • SSL configurable per environment (required production, disabled local)

User Story Coverage

Implemented: 26 of 35 stories from Issue #242

  • Stories 1-24: ✅ Core infrastructure, User persistence, auditing, soft-delete, interceptors, testing, migrations
  • Stories 25: ⚠️ Partial (tests exist but not all combinations verified)
  • Stories 31-35: ✅ Stakeholder value and deployment

What's NOT in This PR (Blocks Full #242 Closure)

Story 6: Money → numeric(18,4) Mapping ❌

  • Budget and Financial aggregates cannot be persisted without this
  • Requires decimal value converter configuration in MenloDbContext
  • Blocker for: Budget, Financial, and any Money-based entities

Story 29: Documentation Updates ❌

  • docs/requirements/repo-structure/specifications.md - add Menlo.Application
  • docs/requirements/repo-structure/implementation.md - update creation steps
  • Repo structure diagram - add Menlo.Application

Story 30: C4 Component Diagram ❌

  • Update docs/diagrams/c4-component-diagram.md
  • Remove per-repository pattern references
  • Show Menlo.Application as central layer
  • Show slice interfaces pattern

Design Decisions

One DbContext: MenloDbContext implements all slice interfaces. Single scoped instance per request with shared change tracking.

Slice Interfaces as API: Feature code depends on IUserContext, never MenloDbContext. Enforces domain boundaries at type system level.

Real PostgreSQL Testing: All persistence tests use Testcontainers with actual PostgreSQL. No in-memory EF Core.

Fail-Fast Migrations: MigrateDatabaseAsync() on startup. Bad schema changes never deploy silently.


Commits

Commit Content
755f048 MenloDbContext, DI, interceptor setup, TestContainers fixtures
161dbdf ReflectiveAuditStampFactory (also fixes #246)
702684c User persistence via IUserContext
57e4777 SoftDeleteInterceptor + migration
24b26b4 Code formatting

Testing

  • Menlo.Application.Tests pass with real PostgreSQL
  • Migrations apply to clean container
  • User save/load via IUserContext works
  • Soft-deleted users excluded from queries
  • Audit fields auto-populated
  • API starts with migrations applied

Follow-Up Work Required

  1. Story 6: Add Money → numeric(18,4) value converter (blocks Budget context)
  2. Stories 29-30: Update documentation and C4 diagram
  3. Future Bounded Contexts: Budget, Planning, Financial, Events, Household

Related: #242, #246, #251
Partially implements: #242

…ence work)

Component: Issue #242 [Foundation]
- Implements core MenloDbContext infrastructure and DI registration
- Establishes migration framework and schema management foundation
- Adds TestContainers fixtures for persistence integration testing
- Enables all downstream persistence features (audit, soft-delete, entity configs)

This commit provides the essential infrastructure that enables the subsequent audit,
soft-delete, and entity persistence features to integrate into the application.
…tStampFactory

Component: Issue #242 [Audit Infrastructure - Part 1]
Related: Issue #246

- Adds HttpContextAuditStampFactory for capturing current user context
- Implements ReflectiveAuditStampFactory using reflection for DI resolution
- Registers IAuditStampFactory in AddMenloApplication for AuditingInterceptor
- Falls back to system actor when IHttpContextAccessor is unavailable

This commit enables the AuditingInterceptor to transparently capture who made
changes (created_by, updated_by) and when changes were made (created_at, updated_at)
by providing a concrete implementation of the audit stamp factory.
Component: Issue #242 [User Persistence Context]

- Adds IUserContext slice interface exposing DbSet<User>
- Implements UserEntityTypeConfiguration with PostgreSQL mapping (shared.users table)
- Maps User aggregate with UUID PK, audit stamps, and soft-delete support
- Enables feature code to use IUserContext without direct MenloDbContext dependency

This commit demonstrates the persistence pattern for bounded contexts by providing
the first concrete slice interface. The User entity is persisted with full audit trail
and soft-delete support as specified in Issue #242.
Component: Issue #242 [Soft-Delete Infrastructure]

- Implements SoftDeleteInterceptor via EF Core SaveChangesInterceptor
- Automatically captures soft-delete stamps (deleted_at, deleted_by)
- Applies global query filter to exclude soft-deleted entities by default
- Fully transparent; feature code never calls Delete() directly

This commit completes the soft-delete infrastructure specified in Issue #242 by
adding the interceptor and query filter that transparently handle deletions.
Combined with the audit infrastructure, User entities now have full lifecycle tracking.
Supporting commit for Issue #242 persistence layer implementation.
Formatting pass across all affected files to normalize code style
and ensure consistency with project conventions.
@DigiBanks99 DigiBanks99 merged commit fb360b3 into main Apr 15, 2026
10 of 11 checks passed
@DigiBanks99 DigiBanks99 deleted the feat/peristence branch April 15, 2026 14:35
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.

feat(persistence): Transparent auditing via AuditingInterceptor

1 participant