A fundamentals-first Node.js + Express application featuring session-based authentication, SQLite persistence, and a minimal server-rendered dashboard for task management.
This project intentionally prioritizes backend and web fundamentals over framework complexity.
- Email/password authentication (register, login, logout) using sessions and bcrypt
- Protected routes with session-based access control
- Task CRUD (create, list, update, delete)
- Task status management (
active,completed,archived) - Server-rendered dashboard using EJS
- Input validation and consistent error handling
- Lightweight
/healthendpoint for monitoring - SQLite persistence with a simple relational schema
Representative views highlighting semantic structure, responsive layout, and accessible UI patterns.
All interactions shown are keyboard-accessible and progressively enhanced.
- Node.js 24.x (LTS)
- Express
- EJS (server-side rendering)
- SQLite (
better-sqlite3) - Sessions:
express-session+session-file-store - Validation:
zod - Security / Ops:
bcrypt,helmet,morgan,dotenv
- Node.js 24.x
- npm (bundled with Node)
npm install
cp .env.example .env
Edit .env and set:
PORT=3000
SESSION_SECRET=your_secret_here
DB_PATH=.data/taskledger.db
npm run db:init
This creates the SQLite database and applies the schema.
Development:
npm run dev
Production:
npm start
npm run dev— run with nodemonnpm start— start servernpm run db:init— initialize database schema
GET /healthPOST /auth/registerPOST /auth/loginPOST /auth/logoutGET /tasksPOST /tasksPATCH /tasks/:idDELETE /tasks/:id
GET /ui/loginGET /ui/dashboardPOST /ui/tasksPOST /ui/tasks/:id/togglePOST /ui/tasks/:id/delete
- This project is designed to reflect real-world Express applications commonly found in existing production codebases.
- CommonJS modules are used intentionally for compatibility and simplicity.
- The UI is intentionally minimal and server-rendered to demonstrate classic request/response flows.
- Emphasis is placed on correctness, clarity, and maintainability over novelty.
- SQLite is used for persistence to keep the system self-contained and easy to inspect.
The live deployment includes a demo login option on the login screen.
- The demo account is created automatically on first use
- No credentials are exposed in the UI
- All data is persisted server-side using SQLite
- This allows visitors to explore the app without registering
This pattern is intentionally included to improve reviewability while keeping authentication mechanics explicit and controlled.
This project intentionally uses file-based sessions and SQLite to reflect common real-world Express setups. As a result, there are a few important behaviors worth calling out:
- When using
express-sessionwithsession-file-store, session persistence is asynchronous. - After successful login, the session must be explicitly saved before redirecting.
- Without calling
req.session.save(...), the browser may follow the redirect before the session file and cookie are fully written, resulting in a one-time401 Unauthorizedon the first dashboard load. - This is a common race condition in Express apps using file-based or async session stores.
- User sessions and the SQLite database are stored under
.data/. - Deleting this directory resets all users, sessions, and tasks.
- This behavior is intentional for local development and demo clarity.
- File-based session stores are convenient for demos but are not ideal for production.
- A production deployment would typically replace this with a centralized store (Redis, database-backed sessions, etc.) to avoid race conditions and scaling issues.
These behaviors are well-understood tradeoffs and are documented here to reflect real-world Express application concerns rather than abstracted or hidden behavior.
MIT

