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 & path | Purpose | Success |
|---|---|---|
POST /auth/register, POST /auth/login | Account, token | 201 / 200 |
GET /projects · POST /projects | My projects · create | 200 · 201 |
GET /projects/{id} · PATCH · DELETE | Read · rename · delete (owner) | 200 · 200 · 204 |
POST /projects/{id}/members · DELETE /projects/{id}/members/{userId} | Invite · remove | 201 · 204 |
GET /projects/{id}/tasks?status=&assignee=&limit=&after= | List with filters + cursor paging | 200 |
POST /projects/{id}/tasks | Create task | 201 + Location |
GET /tasks/{id} · PATCH /tasks/{id} · DELETE /tasks/{id} | Read · update/assign · delete | 200 · 200 · 204 |
GET /tasks/{id}/comments · POST /tasks/{id}/comments | Comments | 200 · 201 |
GET /me/tasks?status=open | My open tasks, by due date | 200 |
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>+BackgroundServicefor 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 / laterKeep 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.mdcommitted 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.