June 1, 2023

eProcess

Workflow-Driven Sales Management Platform — configurable multi-step approval flows with an event-sourced backend on PostgreSQL + Marten.

Involvement Details

Stack

Next.js 15 · React 19 · ASP.NET Core 9 · PostgreSQL · Marten (event store)

Event Sourcing Architecture

  • Designed and implemented an event-sourced backend using Marten on PostgreSQL, where all state changes are persisted as immutable domain events rather than mutable rows
  • Aggregates replay from events at runtime, giving the system a full audit trail and the ability to time-travel to any historical state
  • Async projection daemons rebuild read models in the background, keeping query-side views eventually consistent without blocking the write path

Configurable Workflow Engine

  • Built a multi-step workflow engine where admins define steps, field definitions, and transition rules through a configuration UI — no code changes required to ship new approval flows
  • Each workflow instance tracks field values, designer tasks, internal drafts, and approval decisions across an arbitrary number of steps
  • Workflow versions are immutable; in-flight jobs always run against the version they were started on, preventing mid-flight schema drift

DashboardJobView — Single-Hop Read Model

  • Designed and implemented a MultiStream projection (DashboardJobView) that aggregates job state, current step, assignee, and status into a single denormalised Marten document
  • Eliminated a 3-hop database query (jobs → step_instances → assignments) previously required to render the dashboard, replacing it with a single document fetch
  • Projection is maintained in real time by an async daemon, so the dashboard always reflects the latest job state without on-demand joins

Slim StepInstances Optimization

  • Identified that DashboardJobView documents were storing full embedded arrays of StepInstance objects, causing documents to balloon as workflows added steps and fields
  • Replaced the StepInstances dictionary with four slim denormalised fields (CurrentStepId, CurrentStepName, CurrentAssigneeId, CurrentAssigneeName), cutting per-document payload to only what the dashboard actually renders
  • Achieved an estimated 60–85% reduction in per-document size for workflows with 5+ steps, improving Marten fetch and serialisation throughput proportionally
  • Implemented a ToColumnKey() helper to normalise step and field identifiers into stable, collision-resistant keys for cross-version projection safety
  • Maintained backwards compatibility: StepInstances is synthetically reconstructed from the slim fields on read for any consumers that still depend on the legacy shape

$ ls ./related

More Web Projects

PersonalWeb

Social Media Query App

An interactive app where users can ask questions with two options, and admins respond by selecting the best choice to provide instant clarity and decisions.

PersonalWeb

Memorial Media App

Unites family and friends during crises, celebrating journeys of life by preserving cherished moments.