Skip to content

raphaelfeitoza/simple-task-manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Simple Task Manager

A small full-stack task manager: ASP.NET Core (C#) API + React (TypeScript) frontend, with real per-user auth and ownership enforcement, SQLite persistence, and timezone-aware due dates.

Project Structure

simple-task-manager/
├── README.md
├── backend/
│   ├── TodoApi/            # ASP.NET Core Web API — controllers, services, repositories, EF Core models/migrations
│   └── TodoApi.Tests/      # xUnit unit tests (Unit/) and integration tests (Integration/)
└── frontend/               # React + TypeScript SPA (Vite)
    └── src/
        ├── api/            # fetch wrapper + shared types
        ├── auth/           # AuthContext, login/register forms
        └── tasks/          # task list view, shared task form, task row

Setup

Backend

cd backend/TodoApi
dotnet run
  • Runs on http://localhost:5080 by default (see Properties/launchSettings.json if you want the HTTPS profile instead).
  • Applies EF Core migrations automatically on startup (Database.Migrate()), creating todo.db (SQLite) next to the project on first run. No manual migration step needed.
  • JWT signing secret lives in appsettings.json under Jwt:Secret. It's a placeholder development-only value checked into source for convenience — in a real deployment this would move to an environment variable or dotnet user-secrets and be rotated.

Frontend

cd frontend
npm install && npm run dev
  • Runs on http://localhost:5173 (Vite default), configured via CORS on the backend to allow that origin.
  • Copy .env.example to .env if the backend isn't at http://localhost:5080.

Tests

cd backend/TodoApi.Tests
dotnet test

Two suites, split by folder:

  • Unit/Services/TaskService/AuthService tested in isolation with mocked repositories (Moq), no database involved. Fast (~200ms for the whole suite).
  • Integration/ — real integration tests against WebApplicationFactory + a temp SQLite file per test class (not EF InMemory) — see "What Was Built" for why. Exercises ownership, validation, and the auth+timezone happy path end-to-end over HTTP.

Run just one suite with dotnet test --filter "FullyQualifiedName~Unit" or ~Integration.

What Was Built

  • Auth: register/login with hashed passwords (PasswordHasher<User>), JWT bearer tokens, [Authorize] on every task endpoint.
  • Data model: UserTaskList (one per user, enforced by a unique index) → TaskItem. The list layer is invisible in the UI for now; it's there so "multiple lists per user" is a schema no-op later instead of a migration.
  • Task CRUD: create/read (list + get-by-id)/update/delete, all resolved through the current user's list — a task lookup never bypasses list-based ownership scoping, even for the get-by-id endpoint.
  • Ownership enforcement: every task read/write is scoped to TaskListRepository.GetByUserIdAsync(currentUserId). A task that exists but belongs to someone else returns 404, not 403 — this avoids confirming the row exists at all.
  • Timezone-aware due dates: the client sends a plain calendar date (dueDate) plus its IANA timezone id (timeZoneId, from Intl.DateTimeFormat().resolvedOptions().timeZone). The backend computes local midnight in that timezone and converts it to a UTC instant via TimeZoneInfo.ConvertTimeToUtc. That UTC instant is the only thing stored. Display re-derives the calendar date from that instant using the viewing browser's current timezone.
  • Persistence: SQLite via EF Core (not EF InMemory) — data survives a backend restart.
  • Repository layer: a real generic IRepository<T> / BaseRepository<T> (abstract), with IUserRepository (+ GetByEmailAsync) and ITaskListRepository (+ GetByUserIdAsync) adding entity-specific query methods. ITaskRepository doesn't need any extra methods, since every task lookup goes through the owning TaskList, never a bare task ID.
  • Frontend: React + TypeScript (Vite), client-side routing (login/register/tasks), an AuthContext storing the JWT in localStorage, and optimistic-feeling UI updates (list state updates from the response, no full refetch needed after create/edit/delete/toggle). Create and edit share a single TaskForm component: the create form is hidden behind an "Add Task" button, and only one form (add or edit) is ever open at a time. Loading and error states are covered for create/edit/delete;

Assumptions

  • One task list per user. Not a UI concept yet — every user's list is auto-created on register and never surfaced. The unique index on TaskList.UserId is what actually enforces this, not just app-level convention.
  • Cross-timezone display is expected behavior, not a bug. If a task's due date was set while the browser was in one timezone and later viewed from another, the displayed date reflects the current browser's timezone at read time, because only the UTC instant is stored. E.g., a task due "Aug 1" set from New York, viewed from Tokyo, could show as Aug 1 or Aug 2 depending on the exact UTC offset difference — this is correct per the stored instant, not a translation bug.
  • JWTs don't rotate or refresh. A 7-day expiry is hardcoded; there's no refresh-token flow.
  • No rate limiting or lockout on login/register. not fine for a real deployment with a real attack surface.

Deliberately Left Out

  • Password reset / email verification
  • Roles or multi-tenancy beyond per-user ownership (no admin, no shared lists)
  • Multiple lists per user (schema supports it; no UI or endpoint surfaces it)
  • Pagination, sorting, or filtering on the task list
  • Refresh tokens / token revocation

Next steps

  • Add a PATCH /api/tasks/{id}/complete endpoint instead of routing toggle-complete through the full PUT, to avoid resending the whole task body for a one-field change.
  • Surface the TaskList layer in the UI (multiple named lists per user) — the schema is already there.
  • Add a few frontend component tests (React Testing Library) around the validation and error-display paths, which are currently only covered by manual/E2E verification, not automated frontend tests.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors