Modern workflow automation platform — Zapier/Make/n8n-style — built as a portfolio-grade SaaS.
Status: Phase 3 — Execution engine complete. Workflows run end-to-end: webhook/manual/schedule triggers enqueue background jobs via Hangfire, the
WorkflowExecutorsteps through ordered actions (HTTP / save / notification) with variable templating, and the UI shows live execution timelines.
| Layer | Stack |
|---|---|
| Frontend | Next.js 15 · TypeScript · Tailwind · shadcn/ui · next-themes |
| Backend | ASP.NET Core 9 · Minimal APIs · Modular Monolith · EF Core 9 |
| Database | PostgreSQL 16 |
| Jobs | Hangfire (Postgres-backed) |
| Realtime | SignalR (added in Phase 5) |
| Auth | JWT + refresh-token rotation, multi-tenant via UserId scoping |
| Infra | Docker · Docker Compose · GitHub Actions CI |
| Deploy | Vercel (web) · Railway/Fly.io (api + db) |
The full technical plan lives in docs/PLAN.md (mirror of the approved plan file).
NexusFlow/
├── apps/
│ ├── web/ # Next.js 15 frontend
│ └── api/ # ASP.NET Core 9 modular monolith
│ ├── NexusFlow.Api/ # composition root
│ ├── NexusFlow.Shared/ # Result<T>, IClock, BaseEntity
│ ├── Modules/
│ │ ├── Auth/{Abstractions,Auth}
│ │ ├── Workflows/{Abstractions,Workflows}
│ │ ├── Executions/{Abstractions,Executions}
│ │ └── Integrations/{Abstractions,Integrations}
│ └── tests/NexusFlow.IntegrationTests
├── infra/
│ └── docker-compose.yml # postgres + api + web (+ optional pgadmin)
├── .github/workflows/ci.yml
└── docker-compose.yml # shim → infra/docker-compose.yml
Each backend module ships two projects: *.Abstractions (interfaces consumed cross-module) and the implementation. No module references another module's implementation — only its abstractions. This is the boundary that lets us extract to microservices later if needed.
- Docker Desktop or Docker Engine 24+
- (Optional, for local dev outside Docker) .NET 9 SDK, Node.js 20+
cp .env.example .env
docker compose up --buildWhen the stack is up:
| Service | URL |
|---|---|
| Web (Next.js) | http://localhost:3000 |
| API root | http://localhost:5080 |
| API Swagger | http://localhost:5080/swagger |
| Module health | http://localhost:5080/{auth,workflows,executions,integrations}/health |
| Postgres | localhost:5432 (user: nexusflow, db: nexusflow) |
| pgAdmin (optional) | http://localhost:5050 — start with docker compose --profile tools up |
API:
cd apps/api
dotnet restore
dotnet run --project NexusFlow.ApiWeb:
cd apps/web
npm install
npm run dev- Monorepo layout (
apps/web,apps/api,infra/) - ASP.NET Core 9 modular monolith with 4 modules registered and routed
-
Result<T>/Errortypes in the shared kernel, with HTTP/ProblemDetails translation - Centralized package versions via
Directory.Packages.props -
TreatWarningsAsErrors, .NET analyzers, nullable everywhere - Serilog structured logging
- Health checks (
/health/live,/health/ready) + per-module health - CORS configured from
Cors:AllowedOrigins - Swagger/OpenAPI in Development
- Multi-stage Dockerfiles (alpine runtime for both apps)
- Docker Compose with healthcheck-aware dependency on Postgres
- GitHub Actions CI: API build+test, web lint+typecheck+build
- Tailwind tokens aligned with Linear/Vercel aesthetic
- xUnit + Testcontainers wired against
WebApplicationFactory
-
User+RefreshTokendomain entities under the Auth module - EF Core 9
AuthDbContext+ initial migration (__ef_migrations_historynamespaced per module) - Auto-migrate on startup (skipped under
ASPNETCORE_ENVIRONMENT=Testing) - BCrypt password hashing (work factor 12)
- JWT issuance (
IJwtService) withSub/Email/Jticlaims - Refresh tokens: SHA-256 hashed at rest, 64-byte random, rotation on every refresh, single-use enforced via
replaced_by_token_id -
IRefreshTokenServicewith rotation + revocation chain - JWT auth middleware + fallback
RequireAuthenticatedUserpolicy -
ICurrentUserexposed viaHttpContextAccessor - Endpoints:
POST /auth/{register,login,refresh,logout}+GET /auth/me - FluentValidation request validators wired through a generic
ValidationFilter<T> - Strongly-typed errors via RFC 7807
ProblemDetails(detail,title,code) - Integration tests covering the full lifecycle + rejection of reused/revoked tokens
- Next.js Axios client with transparent refresh (single-flight, redirects to
/loginon failure) - Zustand
auth-store(register / login / logout / hydrate from token storage) -
/loginand/registerpages withreact-hook-form+zod - Protected
(app)layout withAuthGuard, premium sidebar, and/dashboardplaceholder - Sonner toasts for auth errors
-
Workflow+WorkflowStepdomain entities with rich behavior (Update,Activate/Deactivate,ReplaceSteps) -
WorkflowsDbContextwithjsonbcolumns for trigger/step configs and a unique(workflow_id, order_index)index - Initial migration (
__ef_migrations_historynamespaced under theworkflowsschema) -
IWorkflowReadercross-module abstraction exposed viaNexusFlow.Workflows.Abstractions - Endpoints:
GET/POST /workflows,GET/PUT/DELETE /workflows/{id},POST /workflows/{id}/{activate,deactivate} - Tenancy: every query scoped by
ICurrentUser.UserId→ cross-tenant access returns404 - FluentValidation for create/update +
JsonElementconfig payloads validated to be JSON objects - Integration tests: full CRUD lifecycle, cross-tenant isolation, anonymous → 401
- Premium UI:
/workflowslist with empty state,WorkflowCardwith hover actions (toggle/delete),/workflows/newand/workflows/[id]withStepEditor(reorder, JSON config, per-action samples) - Form layer: react-hook-form + zod (transform validates JSON to object) + Sonner toasts for success/error
-
Execution+StepExecution+WorkflowOutputdomain entities under the Executions module - EF Core
ExecutionsDbContext+ migration (__ef_migrations_historynamespaced underexecutions) - Templating engine (
{{ trigger.body.x }},{{ step1.output.field }}) — preserves typed values when the whole string is one template -
IActionHandlerstrategy contract + 3 real handlers (http_request,save_to_database,send_notification) + 2 stubs (Slack/Discord land in Phase 6) -
WorkflowExecutororchestrator: persistspending → running → succeeded/failedtransitions per execution and per step, captures input/output/duration - Hangfire (Postgres-backed) wired with workers,
IBackgroundJobClientfor fire-and-forget andIRecurringJobManagerfor cron schedules -
IExecutionScheduler(cross-module) creates pending execution + enqueuesWorkflowExecutor.RunAsync -
IScheduleRegistrar(cross-module) registers/removes Hangfire recurring jobs when workflows are activated/deactivated/updated/deleted - Public webhook endpoint
POST /hooks/{workflowId}/{secret}— validates secret, accepts JSON payload, enqueues - Authenticated manual trigger
POST /workflows/{id}/runs -
GET /executions[?workflowId=...]andGET /executions/{id}(scoped byUserId) - Schedules re-registered on app startup so cron jobs survive restarts
- Hangfire dashboard at
/hangfire(dev-only auth filter) - UI:
/executionslist with auto-refresh (5s), execution detail with step timeline (input/output/error per step, JSON expandable), live-polling while running - UI: workflow detail now shows Run now, View runs, and a copyable webhook URL when the trigger is a webhook
Production-ready. See docs/DEPLOY.md for a step-by-step guide targeting:
- Vercel (frontend) —
apps/webdeploys as a Next.js project - Railway (backend + Postgres) —
apps/api/Dockerfileships ready to deploy; managed Postgres plugin handles the database; persistent volume holds DataProtection keys - Fly.io as an alternative for the backend
Includes secret rotation, custom domain setup, Hangfire dashboard basic-auth credentials, and a smoke-test checklist.
See docs/PLAN.md for the full 9-phase plan. Post-MVP:
- Phase 9 — React Flow visual canvas to replace the linear step editor
- Conventional Commits (
feat:,fix:,chore:,refactor:,docs:,test:) - .NET:
TreatWarningsAsErrors=true,Nullable=enable, latest analyzers, central package management - TypeScript: strict mode, no
any, Prettier + Tailwind plugin formatting - Tests: xUnit + FluentAssertions for unit; Testcontainers +
WebApplicationFactoryfor integration; Playwright for E2E (Phase 4+) - Errors: RFC 7807 ProblemDetails on the wire;
Result<T>internally — no exceptions for business flow
MIT