A RESTful API for managing text notes, built with Node.js, Express, and NoSQL databases. The application follows a database-agnostic architecture, allowing for easy switching between database vendors (currently supports CouchDB and MongoDB).
Vadim Starichkov | GitHub | LinkedIn
Created as part of a modern Node.js development practices demonstration
- Create, read, update, and delete text notes
- Recycle bin functionality - Move notes to recycle bin instead of immediate deletion
- Restore notes from recycle bin or permanently delete them
- RESTful API design
- Simple and intuitive web UI with tabs for Notes and Recycle Bin
- Database-agnostic architecture
- Multiple database implementations (CouchDB, MongoDB)
- Environment-based configuration
- Easy switching between database vendors
The application follows a layered architecture with a clear separation of concerns:
- Model Layer: Database-agnostic data models
- Repository Layer: Interface for data access with specific implementations
- API Layer: Express routes for handling HTTP requests
This design allows for easy switching between database vendors by implementing a new repository that adheres to the repository interface.
These are the versions this sample app is coming with:
- Node.js (v22.16 or higher)
- npm or pnpm
- One of the following databases:
- CouchDB (v3.4.3 or higher)
- MongoDB (v7.0.21 or higher)
Stable work on lower versions is not guaranteed.
-
Clone the repository:
git clone https://github.com/starichkov/nodejs-simple-notes-app.git cd nodejs-simple-notes-app
-
Install dependencies:
npm install
-
Configure environment variables: Create a
.env
file in the root directory with the following content:# Database Vendor Selection (couchdb or mongodb) DB_VENDOR=couchdb # CouchDB Configuration COUCHDB_URL=http://admin:password@localhost:5984 COUCHDB_DB_NAME=notes_db # MongoDB Configuration MONGODB_URL=mongodb://localhost:27017 MONGODB_DB_NAME=notes_db # Server Configuration HOST=0.0.0.0 PORT=3000
Adjust the values according to your environment. Set
DB_VENDOR
to eithercouchdb
ormongodb
to select the database vendor.
The application includes separate Docker Compose configurations for easy deployment with different database backends. This is the recommended way to run the application locally for development and testing.
- docker-compose.couchdb.yml: Runs the application with CouchDB
- docker-compose.mongodb.yml: Runs the application with MongoDB
IMPORTANT: For security reasons, this application requires explicit database credentials. No default passwords are provided.
You must create a .env
file with your own secure credentials before running any Docker Compose setup:
# Copy the template file
cp env.template .env
# Edit the .env file with your own secure credentials
# The .env file is automatically ignored by git for security
Required .env
file content:
# MongoDB Configuration (all required)
MONGODB_USERNAME=your_mongodb_user
MONGODB_PASSWORD=your_secure_mongodb_password
MONGODB_DATABASE=your_notes_database
# CouchDB Configuration (all required)
COUCHDB_USERNAME=your_couchdb_user
COUCHDB_PASSWORD=your_secure_couchdb_password
COUCHDB_DATABASE=your_notes_database
Security Notes:
- Use strong, unique passwords
- Never use default credentials like
admin/password
- Keep your
.env
file secure and never commit it to version control - The application will fail to start if any credentials are missing
# Start the application with CouchDB
docker compose -f docker-compose.couchdb.yml up -d
# Stop the application
docker compose -f docker-compose.couchdb.yml down
# Start the application with MongoDB
docker compose -f docker-compose.mongodb.yml up -d
# Stop the application
docker compose -f docker-compose.mongodb.yml down
Each Docker Compose setup includes:
- Database service: Either CouchDB (port 5984) or MongoDB (port 27017)
- Notes application: The Node.js API server (port 3000)
- Health checks: Automatic health monitoring for both services
- Data persistence: Named volumes for database data
- Network isolation: Services communicate through a private network
Run the following command to execute tests and get a coverage report:
npm run test:coverage
Then open report file from coverage/lcov-report/index.html
.
Or, alternatively, use an existing custom script:
npm run test:coverage:open
A test script is provided to validate both setups:
# Make the script executable (first time only)
chmod +x test-docker-setups.sh
# Test both database setups
./test-docker-setups.sh
# Test only CouchDB setup
./test-docker-setups.sh couchdb
# Test only MongoDB setup
./test-docker-setups.sh mongodb
Before committing changes, validate your setup locally:
# Quick validation (recommended before commits)
./validate-ci.sh quick
# Full integration tests
./validate-ci.sh full
# GitHub Actions workflow validation only
./validate-ci.sh workflows-only
Our simple CI pipeline automatically:
- 🧪 Runs unit tests with coverage reporting
- 🔧 Tests both database backends (CouchDB and MongoDB) with Docker Compose
- ⚡ Provides fast feedback (~6-8 minutes total)
- 🛡️ Uses secure credentials (generated per test run)
Single Workflow:
- Build: Unit tests + coverage → Docker Compose tests (parallel)
- Triggers: PRs and pushes to main branch
- Simple & Fast: Essential testing only, no complexity
See GITHUB_ACTIONS.md for detailed CI documentation.
The test scripts will:
- Start the specified database setup
- Wait for services to be healthy
- Test all API endpoints (health, CRUD operations)
- Verify the web UI is accessible
- Clean up by stopping the services
Once started with either setup, the application will be available at:
- Web UI: http://localhost:3000
- API: http://localhost:3000/api/notes
- Health Check: http://localhost:3000/health
Start the server:
npm start
The server will be available at http://localhost:3000.
Once the server is running, you can:
- Access the web UI by opening http://localhost:3000 in your browser
- Use the API endpoints directly with tools like curl, Postman, or your own client
GET /api/notes
GET /api/notes/recycle-bin
Note: The /api/notes/trash
endpoint is still available for backward compatibility but is deprecated.
GET /api/notes/:id
POST /api/notes
Content-Type: application/json
{
"title": "Note Title",
"content": "Note content goes here"
}
PUT /api/notes/:id
Content-Type: application/json
{
"title": "Updated Title",
"content": "Updated content"
}
DELETE /api/notes/:id
POST /api/notes/:id/restore
DELETE /api/notes/:id/permanent
GET /api/notes/recycle-bin/count
DELETE /api/notes/recycle-bin
POST /api/notes/recycle-bin/restore-all
GET /health
The application includes a simple and intuitive web UI for managing notes. The UI is accessible at the root URL of the application:
http://localhost:3000/
- Tab Navigation: Switch between "Notes" and "Recycle Bin" views
- Notes View: View all active notes in a responsive grid layout
- Recycle Bin View: View deleted notes with restore/permanently delete options
- Create new notes with a modal form
- Edit existing notes
- Recycle Bin Operations:
- Move notes to recycle bin (soft delete) with confirmation
- Restore notes from recycle bin back to active status
- Permanently delete notes from recycle bin (with strong confirmation)
- Responsive design that works on desktop and mobile devices
The UI is built with vanilla JavaScript, HTML, and CSS, with no external dependencies. It communicates with the API endpoints described above.
The application is designed to easily switch between database vendors. Currently, it supports CouchDB and MongoDB.
The simplest way to switch between database vendors is to change the DB_VENDOR
environment variable in your .env
file:
# To use CouchDB
DB_VENDOR=couchdb
# To use MongoDB
DB_VENDOR=mongodb
The application will automatically use the appropriate repository implementation based on this setting.
To add support for a new database vendor:
- Create a new repository implementation that extends the
NoteRepository
class - Implement all required methods (findAll, findById, create, update, delete)
- Update the server initialization in
notes-api-server.js
to use the new repository
Example of adding a new repository implementation:
// 1. Create a new repository file (e.g., src/db/new-vendor-note-repository.js)
import { NoteRepository } from './note-repository.js';
import { Note } from '../models/note.js';
export class NewVendorNoteRepository extends NoteRepository {
// Implement all required methods
}
// 2. Update notes-api-server.js to use the new repository
import { NewVendorNoteRepository } from './db/new-vendor-note-repository.js';
// In the repository selection code:
if (DB_VENDOR === 'new-vendor') {
noteRepository = new NewVendorNoteRepository(NEW_VENDOR_URL, NEW_VENDOR_DB_NAME);
}
TemplateTasks is a developer-focused initiative by Vadim Starichkov, currently operated as sole proprietorship in Finland.
All code is released under open-source licenses. Ownership may be transferred to a registered business entity in the future.
This project is licensed under the MIT License - see the LICENSE file for details.
If you use this code in your own projects, attribution is required under the MIT License:
Based on nodejs-simple-notes-app by Vadim Starichkov, TemplateTasks
https://github.com/starichkov/nodejs-simple-notes-app
Copyright © 2025 Vadim Starichkov, TemplateTasks