Skip to content

jin3107/TodoApp_BasicToModern

Repository files navigation

TodoApp Basic To Modern

.NET React Vite TypeScript MySQL Redis License

A full-stack Todo application that starts with familiar CRUD workflows and grows into a more production-oriented system: cookie-based authentication, OTP email verification, dashboard reporting, Redis caching, Quartz background jobs, Docker deployment, and a modern React interface.

This is a personal learning project. It is public for reference, but it is not currently maintained as a community contribution project.

Table Of Contents

Features

  • Todo list CRUD with search, pagination, and progress counts.
  • Todo item CRUD with priority, due date, completion status, and filtering.
  • Dashboard analytics with completion rate, overdue tasks, trends, and priority distribution.
  • Cookie-based authentication using AuthToken and RefreshToken HttpOnly cookies.
  • Email OTP flows for account verification and password changes.
  • Fixed OTP verification flow and optimized post-login redirect to the dashboard.
  • Refresh-token rotation and logout support.
  • Role-based authorization for admin-only reports/jobs.
  • Redis-backed caching for expensive report data, with memory-cache fallback.
  • Quartz.NET background jobs for reports, reminders, summaries, and cleanup.
  • Lazy-loaded React routes with authenticated-route preloading for a smoother login experience.
  • Responsive Ant Design UI for mobile, tablet, laptop, and desktop.
  • Polished Login/Register pages with auth illustrations, compact registration form layout, and route preload hints.
  • Shared SCSS tokens, mixins, and layout utilities for cleaner frontend styling.
  • Docker-ready backend, frontend, MySQL, Redis, and Nginx setup.

Tech Stack

Frontend

  • React 19
  • TypeScript
  • Vite
  • React Router
  • Ant Design
  • Axios
  • Day.js
  • SCSS

Backend

  • .NET 8
  • ASP.NET Core Web API
  • ASP.NET Core Identity
  • Entity Framework Core
  • MySQL
  • Redis / Distributed Cache
  • Quartz.NET
  • MailKit
  • Serilog

Infrastructure

  • Docker Compose
  • Nginx reverse proxy
  • MySQL 8
  • Redis 7

Architecture

The backend follows a layered structure:

  • Todo.API: controllers, middleware configuration, CORS, auth, Swagger, Redis, Quartz.
  • Todo.Services: business handlers for auth, todos, reports, cache, and background jobs.
  • Todo.Repositories: repository abstractions and implementations.
  • Todo.Models: EF Core entities, configurations, DbContext, and migrations.
  • Todo.DTOs: request and response contracts.
  • Todo.Commons: shared enums and helpers.
  • MayNghien.Infrastructures: shared infrastructure helpers.

The frontend is feature-oriented:

  • src/routes: lazy route definitions.
  • src/routes/preload.ts: preloads authenticated route chunks from auth pages.
  • src/pages: route-level pages.
  • src/apis: API wrappers.
  • src/components: reusable UI components.
  • src/commons: shared frontend utilities and enums.
  • src/interfaces: typed request/response contracts.
  • src/layouts: shared layout shells.

Project Structure

TodoApp_BasicToModern/
├── TodoApp.Client/
│   ├── src/
│   │   ├── apis/
│   │   ├── commons/
│   │   ├── components/
│   │   ├── configs/
│   │   ├── interfaces/
│   │   ├── layouts/
│   │   ├── pages/
│   │   └── routes/
│   ├── Dockerfile
│   ├── package.json
│   └── vite.config.ts
├── TodoApp.Server/
│   └── src/
│       ├── MayNghien.Infrastructures/
│       ├── Todo.API/
│       ├── Todo.Commons/
│       ├── Todo.DTOs/
│       ├── Todo.Models/
│       ├── Todo.Repositories/
│       ├── Todo.Services/
│       └── src.sln
├── nginx/
├── .env.example
├── docker-compose.yml.example
├── LICENSE.txt
└── README.md

Getting Started

Prerequisites

  • .NET 8 SDK
  • Node.js 18 or newer
  • MySQL 8
  • Redis 7, optional but recommended for report caching
  • Docker Desktop, optional

Backend

From the repository root:

cd TodoApp.Server/src
dotnet restore

Configure local secrets from Todo.API:

cd Todo.API
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=TodoApp_BToM;User=root;Password=your_password;"
dotnet user-secrets set "Jwt:Key" "replace-with-a-long-random-secret"
dotnet user-secrets set "Jwt:Issuer" "https://localhost:7196"
dotnet user-secrets set "Jwt:Audience" "https://localhost:7196"

Optional Redis cache for development:

dotnet user-secrets set "RedisSettings:Enabled" "true"
dotnet user-secrets set "ConnectionStrings:RedisConnection" "localhost:6379,abortConnect=false,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,connectRetry=3,keepAlive=60"

Run migrations:

cd ..
dotnet ef database update --project Todo.Models --startup-project Todo.API

Start the API:

dotnet run --project Todo.API

Default local API URLs:

  • HTTP API: http://localhost:5133
  • HTTPS API: https://localhost:7196
  • Swagger: https://localhost:7196/swagger

Frontend

cd TodoApp.Client
npm install
npm run dev

The client defaults to relative API routes. For direct backend calls, create a local .env in TodoApp.Client if needed:

VITE_API_BASE_URL=https://localhost:7196

During Vite development, vite.config.ts proxies these relative routes to http://localhost:5133:

  • /authentication
  • /todo-items
  • /todo-lists
  • /reports
  • /jobs

Configuration

Keep real secrets out of Git.

Use these files as templates only:

  • .env.example
  • docker-compose.yml.example
  • nginx/conf.d/todoapp.conf.example

Create local files when needed:

Copy-Item .env.example .env
Copy-Item docker-compose.yml.example docker-compose.yml
Copy-Item nginx/conf.d/todoapp.conf.example nginx/conf.d/todoapp.conf

Recommended local secret storage:

  • Backend development: dotnet user-secrets
  • Docker deployment: .env
  • Production server: environment variables or a secret manager

Gmail SMTP

Gmail requires an App Password, not your normal Gmail password.

dotnet user-secrets set "EmailSettings:SmtpServer" "smtp.gmail.com"
dotnet user-secrets set "EmailSettings:SmtpPort" "587"
dotnet user-secrets set "EmailSettings:SmtpUsername" "your-email@gmail.com"
dotnet user-secrets set "EmailSettings:SmtpPassword" "your-gmail-app-password"
dotnet user-secrets set "EmailSettings:FromEmail" "your-email@gmail.com"
dotnet user-secrets set "EmailSettings:FromName" "TodoApp"
dotnet user-secrets set "EmailSettings:RecipientEmail" "recipient@example.com"

Docker

Copy examples first:

Copy-Item .env.example .env
Copy-Item docker-compose.yml.example docker-compose.yml

Edit .env, then start services:

docker compose up -d

For local development with only Redis:

docker run -d --name todoapp-redis -p 127.0.0.1:6379:6379 redis:7-alpine redis-server --appendonly yes

Useful commands:

docker compose ps
docker compose logs -f backend
docker compose logs -f redis
docker compose down

API Overview

Authentication

Method Route Description
POST /authentication/login Login and set auth cookies
POST /authentication/register Register a user and send verification OTP
POST /authentication/send-otp Send OTP for email verification or password change
POST /authentication/verify-otp Verify OTP
POST /authentication/change-password Change password after OTP verification
POST /authentication/refresh-token Refresh auth cookies
POST /authentication/logout Revoke session and clear cookies

Todo Lists

Method Route Description
POST /todo-lists/search Search todo lists
GET /todo-lists/{id} Get list by id
POST /todo-lists Create list
PUT /todo-lists Update list
DELETE /todo-lists/{id} Delete list

Todo Items

Method Route Description
POST /todo-items/search Search todo items
GET /todo-items/{id} Get item by id
POST /todo-items Create item
PUT /todo-items Update item
DELETE /todo-items/{id} Delete item

Reports And Jobs

Method Route Description
POST /reports/progress Get dashboard progress report
POST /reports/snapshot Create daily snapshot, admin only
POST /jobs/trigger/daily-report Trigger daily report, admin only
POST /jobs/trigger/weekly-summary Trigger weekly summary, admin only
POST /jobs/trigger/task-reminder Trigger reminder job, admin only
POST /jobs/pause/{jobName} Pause a Quartz job, admin only
POST /jobs/resume/{jobName} Resume a Quartz job, admin only
GET /jobs/scheduler/info Scheduler info, admin only

Troubleshooting

Login succeeds but the app returns to /login

Check whether RefreshToken is stored and sent by the browser. In development, cookie settings depend on whether requests are made through HTTP proxy or direct HTTPS backend calls.

Also verify:

  • withCredentials: true is enabled in Axios.
  • Backend was restarted after cookie configuration changes.
  • Old localhost cookies were cleared.
  • AllowedOrigins includes the frontend origin when calling the API directly.

Login succeeds but redirect feels slow

The client preloads authenticated route chunks from Login/Register and skips an immediate duplicate refresh check right after a successful login. If the redirect still feels slow, check:

  • Network latency of POST /authentication/login.
  • Whether the dashboard report endpoint is cold and waiting for DB/cache work.
  • Browser DevTools network waterfall for large chunks such as charts or antd.
  • Redis availability when report caching is enabled.

Dashboard report times out

/reports/progress is an expensive endpoint on cache miss.

Recommended checks:

  • Ensure Redis is running if RedisSettings:Enabled=true.
  • Ensure the Redis connection string matches whether Redis uses a password.
  • Restart backend after changing user-secrets.
  • Check API logs for slow DB queries or Redis connection errors.

Gmail OTP fails with 535 5.7.8

Gmail rejected SMTP authentication. Use a Gmail App Password and restart the backend after updating user-secrets.

Docker Redis password mismatch

If Redis is started with --requirepass, the backend connection string must include:

password=your_redis_password

If Redis is only bound to 127.0.0.1 for local development, running without a password is acceptable for this project.

What's Changed

v1.0.0

  • Added authentication API wrappers on the React client.
  • Added Login, Register, and Change Password pages.
  • Added auth illustrations and aligned Login/Register image/form layout.
  • Compact Register form into a desktop grid while preserving mobile stacking.
  • Added cookie-based private routing and lazy-loaded route boundaries.
  • Added authenticated-route preloading from auth pages for faster post-login navigation.
  • Avoided an unnecessary immediate refresh-token request right after successful login.
  • Added OTP-based registration verification and password-change flow.
  • Fixed OTP handling and login redirect behavior on the React client.
  • Refined the React UI for mobile, tablet, laptop, and desktop breakpoints.
  • Extracted shared SCSS tokens, mixins, page shells, cards, and utility classes.
  • Replaced deprecated Sass @import usage and split large frontend vendor chunks.
  • Added Redis-backed progress report caching with memory fallback.
  • Optimized progress report generation to reduce in-memory work.
  • Improved local development cookie behavior for direct HTTPS API calls and proxy-based HTTP calls.
  • Updated Docker example configuration for Redis password and localhost port exposure.
  • Stopped tracking local docker-compose.yml; use docker-compose.yml.example as the template.
  • Cleaned up Ant Design warnings for Spin, Card, and static message usage.

Earlier

  • Todo list and todo item CRUD.
  • Dashboard analytics and progress reporting.
  • Quartz.NET background jobs for reports, reminders, summaries, and cleanup.
  • MySQL persistence with EF Core migrations.
  • Docker and Nginx deployment templates.

Security Notes

  • Do not commit .env, docker-compose.yml, appsettings.Development.json, SMTP credentials, JWT secrets, or database passwords.
  • Rotate any credential that was pasted into chat, terminal logs, or committed history.
  • Use Gmail App Passwords for SMTP.
  • Keep admin-only endpoints behind role checks and network controls.

License

This project is licensed under the MIT License.

Author

Built by Rainy.

About

A comprehensive full-stack Todo application built with modern technologies, featuring a React TypeScript frontend and .NET Core backend with advanced features like caching, background jobs, and detailed reporting.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors