Skip to content

taherelhares/TaskManagement

Repository files navigation

Task Management System API

A RESTful API for managing tasks and users with role-based access control. Built with .NET 9 as part of a back-end developer assessment.

What This Does

This is a task management system where admins can create and manage tasks, assign them to users, and control access. Regular users can view tasks assigned to them and update the status. Everything is secured with JWT authentication.

Tech Stack

  • . NET 9
  • Entity Framework Core (In-Memory Database)
  • JWT Bearer Authentication
  • FluentValidation (using SharpGrip.FluentValidation.AutoValidation. Mvc)
  • xUnit for testing
  • Swagger for API documentation

Project Structure

The project follows clean architecture with four main layers:

  • TaskManagement. Domain - Contains the core entities like User, TaskItem, and enums
  • TaskManagement. Application - Business logic, service interfaces, and DTOs
  • TaskManagement.Infrastructure - Database context, repositories, and token service
  • TaskManagement.Api - Controllers and API configuration
  • TaskManagement.Tests - Unit tests for the service layer

Getting Started

Prerequisites

You'll need . NET 9 SDK installed. You can download it from Microsoft's website if you don't have it.

Running the Application

  1. Clone the repository
  2. Navigate to the project directory
  3. Run these commands:
dotnet restore
dotnet run --project TaskManagement. Api. csproj

The application will start and you can access Swagger UI at https://localhost:7193/swagger (or just go to https://localhost:7193 and it redirects automatically).

Authentication

The API uses JWT tokens for authentication. Here's how to get started:

Getting a Token

Make a POST request to /api/auth/token with this body:

{
  "userId": 1
}

You'll get back a token that looks like this:

{
  "token":   "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Using the Token

In Swagger, click the Authorize button at the top and enter Bearer {your-token}.

If you're using Postman or curl, add this header to your requests:

Authorization: Bearer {your-token}

Test Users

The database is seeded with two users when the app starts:

Admin User

Regular User

There are also 3 pre-seeded tasks assigned to these users.

API Endpoints

Users

  • POST /api/users - Create a new user (Admin only)
  • GET /api/users - List all users (Admin only)
  • GET /api/users/{id} - Get a specific user (Admin or the user themselves)
  • PUT /api/users/{id} - Update user details (Admin or the user themselves)
  • DELETE /api/users/{id} - Delete a user (Admin only, soft delete)

Tasks

  • POST /api/tasks - Create a new task (Admin only)
  • GET /api/tasks - List all tasks (Admin only)
  • GET /api/tasks/{id} - Get a specific task (Admin or assigned user)
  • PUT /api/tasks/{id} - Update task (Admin can update everything, users can only update status on their tasks)
  • DELETE /api/tasks/{id} - Delete a task (Admin only)

Access Control

The system has two roles with different permissions:

Admin can:

  • Do everything - full CRUD on users and tasks
  • View all tasks regardless of assignment
  • Assign tasks to any user
  • Update all fields on any task

Regular User can:

  • View and update their own profile
  • View only tasks assigned to them
  • Update only the status field on their assigned tasks
  • Cannot create or delete anything

All of this is enforced through authorization attributes on the controllers and additional checks in the controller methods.

Running Tests

The project has unit tests for the service layer. To run them:

dotnet test

The tests use xUnit and Moq for mocking dependencies. I've written tests for both TaskService and UserService covering the main CRUD operations and validation logic.

Example Usage

Here are some quick examples to get you started:

Create a new user (as admin):

POST /api/users
Content-Type: application/json
Authorization: Bearer {admin-token}

{
  "userName":  "newuser",
  "email": "newuser@example.com",
  "role":  1
}

Create a task (as admin):

POST /api/tasks
Content-Type: application/json
Authorization:  Bearer {admin-token}

{
  "title": "Complete documentation",
  "description": "Write comprehensive API documentation",
  "assignedUserId": 2,
  "status": "NotStarted"
}

Update task status (as regular user):

PUT /api/tasks/{id}
Content-Type: application/json
Authorization: Bearer {user-token}

{
  "status": "Completed"
}

Implementation Notes

A few things worth mentioning about the implementation:

  • Users are soft-deleted (IsActive flag) instead of being removed from the database
  • The in-memory database gets seeded automatically on startup
  • JWT key is configurable in appsettings. json (defaults to a dev key if not set)
  • Repository pattern is used with a generic base repository
  • Services are registered with scoped lifetime in the DI container
  • Task status and user roles are handled as enums for type safety
  • Input validation is handled with FluentValidation - I used SharpGrip.FluentValidation.AutoValidation.Mvc instead of the deprecated FluentValidation. AspNetCore package
  • All request models have corresponding validators that run automatically before the controller actions

Configuration

You can modify the JWT secret key in appsettings.json:

{
  "Jwt": {
    "Key":  "your-secret-key-here"
  }
}

For development, it defaults to a basic key if none is provided.

Known Limitations

Since this is using an in-memory database, all data is lost when the application stops. The database gets re-seeded each time you restart.

The authentication is simplified for the assessment - in production you'd want proper username/password authentication with hashing, not just user IDs.

Contact

If you have any questions about the implementation, feel free to reach out.

Repository: https://github.com/taherelhares/TaskManagement

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages