A professional-grade REST API for multi-user task management built with .NET 9, Clean Architecture, and PostgreSQL.
Demonstrate proficiency in:
- REST API Design
- Authentication with JWT
- Entity Framework Core persistence
- Clean Architecture patterns
- Docker containerization
- Unit testing
The project follows Clean Architecture with four distinct layers:
TaskFlow.Domain/ → Entities, Enums, Interfaces
TaskFlow.Application/ → DTOs, Services, Business Logic
TaskFlow.Infrastructure/ → EF Core, Repositories, JWT
TaskFlow.API/ → Controllers, Endpoints
| Category | Technology |
|---|---|
| Framework | .NET 9.0 |
| API | ASP.NET Core Web API |
| Database | PostgreSQL |
| ORM | Entity Framework Core |
| Authentication | JWT Bearer |
| Documentation | Swagger/OpenAPI |
| Container | Docker |
| Testing | xUnit + FluentAssertions |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register |
Register new user |
| POST | /api/auth/login |
Login and get JWT |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/projects |
List user's projects |
| POST | /api/projects |
Create project |
| GET | /api/projects/{id} |
Get project details |
| PUT | /api/projects/{id} |
Update project |
| DELETE | /api/projects/{id} |
Soft delete project |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/projects/{id}/tasks |
List tasks (filter by status) |
| POST | /api/projects/{id}/tasks |
Create task |
| GET | /api/projects/{id}/tasks/{taskId} |
Get task details |
| PUT | /api/projects/{id}/tasks/{taskId} |
Update task |
| PATCH | /api/projects/{id}/tasks/{taskId}/complete |
Mark task complete |
| DELETE | /api/projects/{id}/tasks/{taskId} |
Soft delete task |
- .NET 9.0 SDK
- Docker & Docker Compose
- PostgreSQL (optional, can use Docker)
-
Copy environment template:
cp .env.example .env
-
Edit
.envwith your values:POSTGRES_PASSWORD=YourSecurePassword123! JWT_SECRET_KEY=YourSuperSecretKeyThatIsAtLeast32CharactersLong! ALLOWED_ORIGINS=http://localhost:3000,https://yourdomain.com
-
Generate a secure JWT key:
# Linux/Mac openssl rand -base64 32 # Windows (PowerShell) [Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
# Build and start containers
docker-compose up --build
# API: http://localhost:5000
# Swagger: http://localhost:5000/swagger (development only)# Set environment variables (Linux/Mac)
export JWT_SECRET_KEY="YourSecretKey..."
export DATABASE_CONNECTION_STRING="Host=localhost;Database=taskflow;User=postgres;Password=..."
export POSTGRES_PASSWORD="YourPassword"
# Or on Windows (PowerShell)
$env:JWT_SECRET_KEY="YourSecretKey..."
$env:DATABASE_CONNECTION_STRING="Host=localhost;Database=taskflow;User=postgres;Password=..."
$env:POSTGRES_PASSWORD="YourPassword"
# Restore packages
dotnet restore
# Update database
dotnet ef database update
# Run
dotnet run --project TaskFlow.API
# Tests
dotnet test- No hardcoded secrets - All sensitive data via environment variables
- JWT with short expiration - 24-hour token lifetime
- Password hashing - BCrypt algorithm
- CORS protection - Configurable allowed origins
- Security headers - X-Content-Type-Options, X-Frame-Options, X-XSS-Protection
- Soft delete - Data marked as deleted, not physically removed
- Role-based access - User/Admin authorization
- Production-ready - Error details hidden in production
- JWT Authentication - Stateless token-based auth with 24h expiration
- Role-Based Authorization - User/Admin roles
- Soft Delete - Projects and tasks are marked as deleted, not physically removed
- Status Filtering - Filter tasks by Pending, InProgress, Completed
- RESTful Design - Proper HTTP verbs and status codes
TaskFlowAPI/
├── TaskFlow.Domain/ # Core business entities
│ ├── Entities/ # User, Project, TaskItem
│ ├── Enums/ # Role, TaskStatus
│ └── Interfaces/ # Repository interfaces
├── TaskFlow.Application/ # Business logic
│ ├── DTOs/ # Request/Response objects
│ └── Services/ # Auth, Project, Task services
├── TaskFlow.Infrastructure/ # Data access
│ ├── Data/ # DbContext
│ ├── Configurations/ # EF configurations
│ ├── Repositories/ # Repository implementations
│ └── Security/ # JWT service
├── TaskFlow.API/ # Web API
│ ├── Controllers/ # API controllers
│ └── Program.cs # App configuration
├── TaskFlow.Domain.Tests/ # Unit tests
├── docker-compose.yml # Docker services
├── .env.example # Environment template
└── README.md
# 1. Register
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"Pass1234!","name":"User"}'
# 2. Login (copy token from response)
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"Pass1234!"}'
# 3. Create Project (replace TOKEN)
curl -X POST http://localhost:5000/api/projects \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"My Project"}'
# 4. Create Task
curl -X POST http://localhost:5000/api/projects/1/tasks \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"First Task"}'# Run all tests
dotnet test
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"| Variable | Description | Example |
|---|---|---|
JWT_SECRET_KEY |
Secret key for JWT signing (min 32 chars) | YourSuperSecretKeyThatIsAtLeast32CharactersLong! |
DATABASE_CONNECTION_STRING |
PostgreSQL connection string | Host=postgres;Database=taskflow;User=postgres;Password=... |
POSTGRES_PASSWORD |
PostgreSQL password | YourSecurePassword123! |
JWT_ISSUER |
JWT issuer (optional) | TaskFlowAPI |
JWT_AUDIENCE |
JWT audience (optional) | TaskFlowAPI |
JWT_EXPIRATION_MINUTES |
Token expiration (optional) | 1440 |
ALLOWED_ORIGINS |
CORS allowed origins (optional) | http://localhost:3000,https://yourdomain.com |
- Set secure environment variables
- Use HTTPS (configure reverse proxy like Nginx)
- Set
ASPNETCORE_ENVIRONMENT=Production - Configure your domain in
ALLOWED_ORIGINS - Use strong
JWT_SECRET_KEY(64+ characters recommended) - Enable auto-restart with
restart: unless-stopped
MIT License