A full-stack, multi-user task management application built with ASP.NET Core, Entity Framework Core, Vue 3, and TypeScript.
Users can register, sign in, and manage a private task workspace with server-side search, filtering, sorting, pagination, and dashboard summaries.
- JWT-based authentication with ASP.NET Core password hashing
- Authentication token stored in an
HttpOnly,SameSite=Strictcookie - Per-user authorization checks on every task read and write
- RESTful CRUD endpoints with DTO and service layers
- Server-side pagination, search, filtering, and allow-listed sorting
- Dashboard summaries generated with an aggregate database query
- Request validation with field-level Problem Details responses
- Centralized exception handling and structured logging
- SQLite for zero-setup local development
- SQL Server provider and migration support
- Responsive Vue 3 interface with loading, empty, validation, and API error states
- ASP.NET Core integration tests using isolated temporary databases
- GitHub Actions CI for backend tests and frontend security/build checks
| Layer | Technology |
|---|---|
| Backend | ASP.NET Core 10 Web API |
| Authentication | JWT Bearer, HttpOnly cookies, ASP.NET Core PasswordHasher |
| Data Access | Entity Framework Core 10 |
| Databases | SQLite for local development, SQL Server support |
| Frontend | Vue 3, TypeScript, Axios, Vite |
| Testing | xUnit, ASP.NET Core WebApplicationFactory, isolated SQLite |
| CI | GitHub Actions |
flowchart LR
UI["Vue 3 + TypeScript"] -->|"REST API"| API["ASP.NET Core API"]
API --> Controllers["Auth and Task Controllers"]
Controllers --> Services["Service Layer"]
Services --> EF["Entity Framework Core"]
EF --> DB[("SQLite / SQL Server")]
The controllers handle HTTP and authentication concerns, while the service layer contains account and task behavior. DTOs define the public API contract, and Entity Framework Core manages persistence.
Every task query includes the authenticated UserId. If one user attempts to access another user's task—even with a valid task ID—the API returns 404.
task-management-system/
├── .github/
│ └── workflows/
│ └── ci.yml
├── backend/
│ ├── TaskManager.Api/
│ │ ├── Configuration/
│ │ ├── Controllers/
│ │ ├── Data/
│ │ ├── DTOs/
│ │ ├── Infrastructure/
│ │ ├── Migrations/
│ │ ├── Models/
│ │ ├── Services/
│ │ └── Program.cs
│ ├── TaskManager.Api.Tests/
│ └── TaskManager.sln
└── frontend/
└── task-manager-web/
├── src/
│ ├── assets/
│ ├── services/
│ ├── types/
│ ├── App.vue
│ └── main.ts
└── package.json
- Registration, login, logout, and a current-user session endpoint
- Case-insensitive duplicate email prevention
- JWT validation for signature, issuer, audience, lifetime, and expiration
Authorization: Bearersupport for non-browser clients- Independent task status changes
- Status, priority, and due-date range filters
- Overdue and due-today calculations
- Vue 3 pages for registration, login, the task dashboard, and create/edit forms
- .NET 10 SDK
- Node.js 20.19+ or 22.12+
- npm
Local development uses SQLite, so SQL Server and Docker are not required.
git clone https://github.com/Tofuhsu/task-management-system.git
cd task-management-systemEnter the API project:
cd backend/TaskManager.ApiGenerate and store a local JWT signing key with .NET user secrets:
JWT_KEY=$(openssl rand -base64 48)
dotnet user-secrets set "Jwt:SigningKey" "$JWT_KEY"
unset JWT_KEYThe signing key is stored outside the repository and must not be committed.
dotnet restore
dotnet build
dotnet runThe API defaults to:
http://localhost:5100
Swagger is available in Development at:
http://localhost:5100/swagger
The application creates a local SQLite database automatically.
Open a second terminal:
cd frontend/task-manager-web
cp .env.example .env.local
npm ci
npm run devOpen:
http://localhost:5173
Register an account and create your first task.
The integration test suite starts the real ASP.NET Core application in memory and uses a unique temporary SQLite database.
It does not require:
- A running API
- A local JWT secret
- SQL Server
- Access to the development
taskmanager.db
Run the tests with:
cd backend
dotnet test TaskManager.slnThe test suite verifies:
- Unauthenticated users cannot access protected task endpoints.
- Registration returns a secure
HttpOnly,SameSite=Strictcookie. - Incorrect passwords are rejected.
- Duplicate emails are rejected regardless of letter case.
- One user cannot read, update, change, or delete another user's task.
Expected result:
Total tests: 5
Passed: 5
Failed: 0
Skipped: 0
GitHub Actions runs automatically on every push and pull request to main.
- Restores NuGet packages
- Builds the .NET solution in Release mode
- Runs all integration tests
- Installs dependencies with
npm ci - Runs
npm audit - Performs TypeScript type checking
- Creates a production Vite build
The CI workflow is located at:
.github/workflows/ci.yml
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/auth/register |
Register an account and create an authentication cookie |
POST |
/api/auth/login |
Verify credentials and refresh the authentication cookie |
GET |
/api/auth/me |
Return the currently authenticated user |
POST |
/api/auth/logout |
Expire the authentication cookie |
All task endpoints require authentication.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks |
Search, filter, sort, and paginate the user's tasks |
GET |
/api/tasks/{id} |
Get one owned task |
GET |
/api/tasks/summary |
Get dashboard summary counts |
POST |
/api/tasks |
Create a task |
PUT |
/api/tasks/{id} |
Replace editable task fields |
PATCH |
/api/tasks/{id}/status |
Update task status |
DELETE |
/api/tasks/{id} |
Delete a task |
Example query:
GET /api/tasks?page=1&pageSize=10&search=backend&status=Todo&priority=High&sortBy=DueDate&sortDirection=ascSupported sorting fields:
CreatedAtTitleDueDatePriorityStatus
The maximum page size is 100.
Invalid requests return 400 application/problem+json with field-level messages and a request trace ID.
Example:
{
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"PageSize": [
"The field PageSize must be between 1 and 100."
]
},
"traceId": "00-..."
}Expected authentication and account errors return:
401 Unauthorized409 Conflict
Unexpected errors return a safe 500 response, while the original exception is logged by the server.
- Passwords are stored only as salted hashes.
- Plaintext passwords are never persisted or logged.
- JWT signature, issuer, audience, lifetime, and expiration are validated.
- Browser JavaScript cannot read the authentication token because it is stored in an
HttpOnlycookie. - Authentication cookies use
SameSite=Strict. - Cookies use the
Secureflag outside Development. - CORS uses an explicit origin allow-list.
- Task IDs are always queried together with the authenticated
UserId. - Login errors do not reveal whether the email or password was incorrect.
- Local JWT secrets and SQLite database files are excluded from Git.
This account system is suitable for a portfolio application. A public production deployment should additionally consider managed OpenID Connect or OAuth, email verification, password recovery, login rate limiting, key rotation, and deployment-specific CSRF protection.
The application uses SQLite in local Development but also includes SQL Server support.
To use SQL Server:
- Set
DatabaseProvidertoSqlServer. - Provide
ConnectionStrings__DefaultConnection. - Apply the migrations:
dotnet ef database updateThe authentication migration is designed for a fresh database. It intentionally stops if an older SQL Server database already contains tasks without owners, because those records require an explicit ownership migration.
IdEmailPasswordHashCreatedAt
IdUserIdTitleDescriptionStatusPriorityDueDateIsCompletedCreatedAtUpdatedAt
Each task belongs to exactly one user. Deleting a user also deletes that user's tasks through a cascade relationship.
- Login rate limiting
- Email verification and password recovery
- Managed OpenID Connect authentication option
- Docker Compose development environment
- Cloud deployment
- Documented performance and load-test measurements
- Expanded unit and integration test coverage