.NET Academy

Capstone 1: design TaskFlow

Turn a product brief into requirements, an API, a data model and an architecture — before writing any code.

25 min read

You will learn

  • Turn a product brief into functional and non-functional requirements
  • Design the REST API and the data model
  • Draw the architecture and record key decisions
  • Produce a short design document to build from

The project

Time to put everything together. Over the three capstone lessons you'll design, build and ship TaskFlow — a task-management API, like a tiny Trello or Asana backend. It touches almost every topic of the course: REST design, EF Core, authentication, validation, testing, containers and CI/CD.

You'll build it on your own machine with the .NET SDK, Docker and an editor (VS Code, Visual Studio or Rider). Plan a few days; each lesson ends with a checklist. Mark the lesson complete when you've done it.

The brief

Small teams want to organize their work. A user signs up and creates projects. They invite other users to a project as members. Members create tasks with a title, description, status (To do / In progress / Done), optional due date and optional assignee. Members can comment on tasks. Users want to see "my open tasks across all projects", sorted by due date. When a task is assigned to someone, they should get an email notification. Only project members may see or change a project's tasks; only the project owner may delete the project or remove members.

Step 1 — Requirements

Write them down before anything else.

Functional (start from the brief; add anything you think is missing):

  • Register and log in; get a token.
  • Create, list, rename and delete projects; add and remove members.
  • Create, list (filter by status/assignee, paginate), update, assign and delete tasks.
  • Comment on tasks; list comments.
  • "My open tasks" across projects.
  • Email on assignment (asynchronously).

Non-functional — decide and justify:

  • Expected scale (e.g. 1,000 teams, 100 requests/s at peak) — keep it realistic.
  • Latency target (e.g. p95 < 200 ms for reads).
  • Security: every endpoint except registration/login requires authentication; authorization by project membership.
  • Data must not be lost (relational database with backups).

Step 2 — The API

Design resource-oriented endpoints, with methods and status codes. A starting point:

Method & pathPurposeSuccess
POST /auth/register, POST /auth/loginAccount, token201 / 200
GET /projects · POST /projectsMy projects · create200 · 201
GET /projects/{id} · PATCH · DELETERead · rename · delete (owner)200 · 200 · 204
POST /projects/{id}/members · DELETE /projects/{id}/members/{userId}Invite · remove201 · 204
GET /projects/{id}/tasks?status=&assignee=&limit=&after=List with filters + cursor paging200
POST /projects/{id}/tasksCreate task201 + Location
GET /tasks/{id} · PATCH /tasks/{id} · DELETE /tasks/{id}Read · update/assign · delete200 · 200 · 204
GET /tasks/{id}/comments · POST /tasks/{id}/commentsComments200 · 201
GET /me/tasks?status=openMy open tasks, by due date200

Decide: which errors each endpoint returns (400, 401, 403 vs 404 for non-members, 409), the shape of request/response DTOs, and how pagination works.

Step 3 — The data model

User (Id, Email [unique], DisplayName, PasswordHash or external Id, CreatedAt)
Project (Id, Name, OwnerId → User, CreatedAt)
ProjectMember (ProjectId → Project, UserId → User, Role, JoinedAt)   PK (ProjectId, UserId)
TaskItem (Id, ProjectId → Project, Title, Description, Status, DueDate?, AssigneeId? → User,
          CreatedById → User, CreatedAt, UpdatedAt, RowVersion)
Comment (Id, TaskId → TaskItem, AuthorId → User, Body, CreatedAt)

Think about: which indexes support your queries (TaskItem (ProjectId, Status), TaskItem (AssigneeId, Status, DueDate)), what happens to tasks when a project is deleted (cascade?), and how to prevent lost updates when two people edit a task (RowVersion).

You can prototype queries for a similar schema in the SQL sandbox from Track 7.

Step 4 — Architecture

Sketch the components and how they connect. A sensible version for this scale:

Client ──▶ ASP.NET Core API (stateless, 2+ instances behind a load balancer)
                │        └──▶ PostgreSQL (EF Core)
                │
                └──▶ Channel / queue ──▶ Background worker ──▶ Email provider (SMTP / SendGrid)

Then record the key decisions and their trade-offs — for example:

  • Minimal APIs or controllers? Vertical slices or layers?
  • Own JWT issuing with Identity, or an external identity provider?
  • In-process Channel<T> + BackgroundService for emails (simple, lost on crash) or a real queue / outbox (durable, more moving parts)?
  • Offset or cursor pagination?

Step 5 — Write the design document

Create docs/design.md in a new git repository:

# TaskFlow — design
 
## Requirements
Functional: …
Non-functional: scale, latency, security, durability …
 
## API
(table of endpoints, status codes, example request/response)
 
## Data model
(entities, relationships, indexes)
 
## Architecture
(diagram + one paragraph)
 
## Decisions
| Decision | Options considered | Choice | Why |
| --- | --- | --- | --- |
 
## Open questions / later

Keep it short

Two or three pages is plenty. The goal is to think before coding — and to have something to compare against when you're done.

Checklist

  • Functional and non-functional requirements written down
  • API table with methods, paths and status codes
  • Data model with keys, relationships and indexes
  • Architecture sketch and at least four recorded decisions
  • docs/design.md committed to a new git repository

When you're done, mark this lesson complete and continue to Capstone 2: build.

Finished reading? Mark the lesson as complete to track your progress.