⚠ Demo notice, please read
This is a learning and portfolio project, not a production service.
- Do not use a real email address. The email is only a login identifier. It is not verified: no confirmation email is sent, and no emails are ever sent at all.
- Do not use a real password (or one you use anywhere else). Use something throwaway.
- There is no multi-factor authentication (MFA), no password reset, and no account recovery.
- Any email-like string works, for example
demo@example.com.
- Data may be wiped at any time, and nothing here is private or secure storage.
- The backends run on free hosting tiers, so the first request after inactivity can take 30+ seconds while the server wakes up. If login seems stuck, wait a moment and try again.
The learning purpose
One simple Task Tracker, built four times on four backend frameworks, all driven by this same frontend. The point isn't the app, it's comparing how each ecosystem solves the same problems.
Many tutorials teach one framework in isolation. I wanted to learn what is universal about backend development and what is framework-specific, so I built the same application in sequence on Node.js (Express), ASP.NET Core, Django and Spring Boot. Rebuilding the same thing meant my effort went into how each framework does things rather than what to build, so patterns like routing, middleware, ORMs, validation and authentication became easy to compare.
What stayed the same in every stack
- REST endpoints for tasks (create, read, update, delete)
- User signup and login, returning a JWT
- Tasks belong to users; a user only sees and modifies their own tasks
- Another user's task returns 404 (not 403), so its existence isn't leaked
- Input validation, with errors returned as
{ "error": "message" }
- A PostgreSQL database, a
/health endpoint, and CORS for this frontend
- Containerised or managed deployment on Render
What differed between stacks
- Express is minimal and flexible; you assemble the structure yourself.
- ASP.NET Core is strongly typed and "batteries included", with built-in dependency injection and identity.
- Django is opinionated: ORM, auth, admin and settings conventions get you far with little code.
- Spring Boot has the most ceremony, but dependency injection and the security filter chain make the structure explicit and consistent at scale.
How it works
┌──────────────────────┐ ┌───────────────────────────┐
│ Frontend (Netlify) │ │ Backend (one at a time) │
│ Plain HTML / JS │ HTTPS │ Express | ASP.NET | │
│ Stack switcher │ ─────► │ Django | Spring Boot │
└──────────────────────┘ JSON └─────────────┬─────────────┘
│
┌───────▼────────┐
│ PostgreSQL │
└────────────────┘
- Pick a backend. The stack switcher at the top chooses which deployed API this page talks to.
- Sign up / log in. The page calls
POST /auth/signup and POST /auth/login; login returns a token (a JWT).
- Store the token. It is kept in the browser's
localStorage (see Limitations).
- Call the API. Task requests send
Authorization: Bearer <token>.
- Authorise. Each backend validates the token, identifies the user, and scopes every query to that user.
- Respond. Success returns JSON; failures return
{ "error": "..." } with a suitable status code.
The shared API contract
A task has id, title, completed and created_at.
The four backend repositories
Each repository has its own setup instructions and environment-variable list.
Known limitations (deliberate trade-offs)
- JWT stored in
localStorage. This keeps the project simple and identical across stacks, but any XSS bug could expose the token. A production app should use HttpOnly cookies.
- No email verification, MFA, or password reset. The email is just a unique username.
- No automated tests or CI pipeline yet.
- No rate limiting on login or signup.
- Free-tier hosting, so cold starts and no uptime guarantees.
- Breadth over depth. The goal was to understand each stack well enough to explain it and build a working CRUD API, not to master any single one.
Possible future improvements
Security hardening
- Move the token to an HttpOnly, Secure cookie with CSRF protection
- Short-lived access tokens plus refresh-token rotation and server-side revocation
- Rate limiting, brute-force protection, and security headers (CSP, HSTS)
- Optional real email verification, password reset, and MFA
Quality and engineering practice
- Automated unit and integration tests per backend (including "user B cannot access user A's task")
- CI with GitHub Actions, managed database migrations, structured logging and monitoring
- OpenAPI/Swagger documentation for every stack
Product and architecture
- Go deeper on one stack: pagination, filtering, due dates, categories
- Rebuild the frontend in a framework such as React or Vue
- A custom domain so frontend and API are same-site