Skip to content
Personal project

A production-grade task manager, built in the open to prove the standard I hold my work to

An authenticated project-and-task SaaS — Angular front to back against a Clean Architecture .NET API — built as an open portfolio piece rather than a client deliverable.

Currently building 3 min read
Role
Solo — product, architecture, build, deploy
Duration
Ongoing (2026)
Team size
1
Client type
Personal project — open portfolio piece
Stack
  • Angular
  • ASP.NET Core
  • PostgreSQL

Context

TaskFlow is an authenticated web app for planning and tracking work — projects, tasks, and their state over time. It exists to be looked at as much as used: an end-to-end system I own outright, so I can show the full shape of a production build — architecture, testing, and deploy — without an NDA in the way.

The problem

A portfolio of anonymized client work proves I can build, but it can never be opened, cloned, or read line by line. I needed one system a prospective client can actually inspect — real auth, real data, real deploy — that demonstrates the standard the NDA-bound work is held to.

The interesting constraint is self-imposed: hold a solo side project to the same architectural discipline as a team system — enforced layering, a tested domain, and a pipeline — without that discipline becoming ceremony that stalls the build.

Constraints

  • One developer, part-time — every abstraction has to earn its keep or it gets cut.
  • Open by default: the code is meant to be read, so structure and naming carry weight they would not in a private repo.
  • Single deploy artifact, hosted cheaply — no managed cloud services standing in for design decisions.

What I did

Layered the API on Clean Architecture

Domain, Application, Infrastructure, and API as separate projects with dependencies pointing inward — the same structure the Portfolio API mirrors — so business rules stay independent of EF Core, the web framework, and any one database.

Modeled the domain with real invariants

Entities and value objects enforce their own consistency rather than trusting callers, so an invalid task state cannot be constructed regardless of which handler reaches it.

Drove writes and reads down separate paths

Commands run through a validated handler pipeline; list/read queries take a thinner path built for the shape the UI actually renders, instead of forcing every read back through the write model.

Built the Angular client zoneless and standalone

Signals for state, standalone components, and SSR-friendly rendering — the same front-end architecture as this site — so the client stays fast and the whole thing is one coherent system, not two disconnected halves.

Key decisions & tradeoffs

Chose Clean Architecture with four projects over a single-project layered MVC app

Because
the point of the project is to demonstrate architecture that holds up under change; enforced boundaries make the intent legible to anyone reading the repo
Tradeoff
more moving parts and indirection up front than a solo CRUD app strictly needs — justified here because being read is a feature, not a side effect

Chose an explicit validated handler pipeline for writes over validation scattered across controllers

Because
every command hits the same validation and error-shaping boundary, so the API answers consistently and controllers stay thin
Tradeoff
a small amount of pipeline boilerplate per command, in exchange for one place to reason about how every write behaves

Chose a zoneless, signal-based Angular client over the default zone.js change-detection model

Because
change detection becomes explicit and cheap, which keeps the app fast and the data flow easy to follow
Tradeoff
gives up some of the "it just re-renders" ergonomics of zones, so state ownership has to be deliberate

Results

4 enforced layers

Architecture

Validated command pipeline

Write path

Zoneless · signal-driven

Front end

In active development

Status

What I’d do differently

The honest lesson so far is that architecture is cheap to add and expensive to remove: a couple of the boundaries earn themselves back the first time a change stays contained to one layer, and one or two are heavier than a solo project needs. When it ships, this section gets rewritten with what actually held up under real use — not what I hoped would.

Stack

  • Angular
  • ASP.NET Core
  • PostgreSQL

Next case study

Next case study

Suggu CLI — safe .NET workspace automation

Suggu is a cross-platform .NET 10 productivity CLI for creating, inspecting, and automating filesystem and .NET solution work. It combines guided workflows, diagnostics, static endpoint tracing, and project-owned rulebooks—useful directly in the terminal and as a reliable execution layer for Codex or Claude Code.