A full-stack Notes application with a static frontend and an Express + PostgreSQL backend. The app supports user registration/login (JWT-based auth), creating, reading, updating and deleting notes, and per-user note storage.
Tech: Node.js, Express, PostgreSQL, vanilla JavaScript (client)
Highlights:
- Authentication: Register / login with JWT tokens.
- Notes CRUD: Create, read, update, delete notes (owners only).
- Server-side validation & rate limiting: Input validation, sanitization, and per-route rate limits.
- DB migrations: Managed with
node-pg-migrateunderserver/db/migrations.
Quick Links:
- Server docs:
server/README.md
Folder overview
notes-app/
client/— static frontend filesindex.htmljs/— frontend JavaScript modules (e.g.app.js,notesManager.js,loginManager.js, etc.)styles/,sounds/
server/— Express serverindex.js— server entrypointdb.js— Postgres pool and optional init helperroutes/—notes.js,users.jsmiddleware/— auth, validation, rate limiting, error handlingdb/—migrations/,init.sql
package.json— project scripts and deps
- Node.js >= 18
- PostgreSQL (local or remote)
- Clone the repository and change into the project folder:
cd "path\to\notes-app"- Install dependencies:
npm install- Create a
.envfile for the server. You can copy the server example if available:
copy server\.env.example server\.env
# then edit server\.env and fill the valuesThe server expects the following variables (set them in server/.env or your environment):
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME— Postgres connectionJWT_SECRET— secret used to sign JWT tokens (required)PORT— optional server port (defaults to 5000)ALLOWED_ORIGINS— comma-separated list of allowed CORS origins for the client (optional)NOTES_BODY_LIMIT,USER_BODY_LIMIT— per-route JSON body size limits (optional)RUN_DB_INIT— when set totruethe server will executeserver/db/init.sql(dangerous in production; prefer migrations)
From the project root notes-app:
npm run dev
# or to run without nodemon:
npm startMigrations live in server/db/migrations and are managed with node-pg-migrate.
# apply migrations
npm run migrate
# rollback last migration
npm run migrate:downBase path: /api
-
POST /api/users/register— register new user (body:email,password,name) -
POST /api/users/login— login (body:email,password) → returns{ user, token } -
DELETE /api/users/account— delete authenticated user's account (requiresAuthorization: Bearer <token>) -
GET /api/notes— list notes for authenticated user -
POST /api/notes— create note (body:title,content,formatting) -
GET /api/notes/:id— get a single note -
PUT /api/notes/:id— update a note -
DELETE /api/notes/:id— delete a note
All /api/notes routes require a valid JWT token in Authorization header.
For more details about request validation, rate limits, and error format, see server/README.md.
The client is a static front-end in client/. You can open client/index.html directly in your browser for local testing or serve it with any static server (e.g. VS Code Live Server or serve). Make sure ALLOWED_ORIGINS includes the origin you use for the frontend during development.
npm run admin:delete-user— runsserver/scripts/deleteUser.js(helper for admin tasks)
- Follow conventional PR workflow. Update or add migrations for schema changes. Keep secrets out of source control.
Project license: ISC (see package.json).
- Missing DB env vars: The server requires
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME. When any are missing the server logs a clear error. Checkserver/.env.exampleand ensureserver/.envis configured. - JWT secret required:
JWT_SECRETmust be set before starting the server; otherwise the server will refuse to start. - Dangerous init SQL:
server/db/init.sqlcan be destructive. The server only runs it whenRUN_DB_INIT=trueand only if explicitly requested; prefer using migrations (server/db/migrations) for schema changes. - Migrations fail: Ensure Postgres is reachable and credentials match. Use
npm run migrateand, if needed,npm run migrate:downto rollback. Check database permissions and that the DB specified inDB_NAMEexists. - CORS / ALLOWED_ORIGINS: If your frontend cannot talk to the API during development, add the frontend origin to
ALLOWED_ORIGINSin the server env (comma-separated list).
Common quick fixes:
- Ensure Postgres is running and the connection env vars are correct.
- Ensure
JWT_SECRETis set and different between environments. - Do not set
RUN_DB_INIT=trueon production or shared environments.
Replace TOKEN with the JWT returned from login/register. All examples assume the server runs at http://localhost:5000.
- Register:
curl -X POST http://localhost:5000/api/users/register \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"secret","name":"You"}'- Login (returns
token):
curl -X POST http://localhost:5000/api/users/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"secret"}'- Create note:
curl -X POST http://localhost:5000/api/notes \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Hello","content":"Note body"}'- List notes:
curl -X GET http://localhost:5000/api/notes \
-H "Authorization: Bearer TOKEN"- Get note:
curl -X GET http://localhost:5000/api/notes/NOTE_ID \
-H "Authorization: Bearer TOKEN"- Update note (partial):
curl -X PUT http://localhost:5000/api/notes/NOTE_ID \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Updated title"}'- Delete note:
curl -X DELETE http://localhost:5000/api/notes/NOTE_ID \
-H "Authorization: Bearer TOKEN"- Server docs:
server/README.md - Dangerous init SQL (dev-only):
server/db/init.sql - Migrations:
server/db/migrations - Open client in browser:
client/index.html - Package and scripts:
package.json