Skip to content

CSHeHu/shoppinglist

Repository files navigation

Coverage Status

Shopping List Application

Lightweight Node.js shopping list app with a small EJS frontend and an API backend. Key design points:

  • Session-based authentication (server-side sessions stored in MongoDB via connect-mongo).
  • Separate dedicated users database and least-privilege DB users created at MongoDB first-boot.
  • Docker Compose stack with optional nginx reverse-proxy for local HTTPS during development.

🚀 Features

  • Session-based login/logout with a minimal admin bootstrap flow (scripts/populate-admin.js).
  • Public read access for the shopping list (GET /data) and protected modifying endpoints for authenticated users (POST, PATCH, DELETE on /data).
  • Dedicated users DB (USER_DB_NAME) and dedicated app DB user for data access.
  • Minimal EJS-rendered frontend plus an API-first design for fetch/XHR usage.
  • Local HTTPS in development via nginx + mkcert (optional) and a Compose-friendly DB bootstrap (entrypoint + one-shot admin populator).
  • Tests for controllers (see tests/).

🌐 API Endpoints

This app exposes a small set of endpoints for the UI and API clients. All modifying /data requests require an authenticated session; GET /data is public.

/data

Method Description
GET Fetch all shopping list items. Responds with a JSON array. (Public)
POST Add a new item. Requires Content-Type: application/json and JSON body: { name, amount, finished }. (Requires session)
PATCH Update an item. Requires Content-Type: application/json and JSON body: { _id, name, amount, finished }. (Requires session)
DELETE Delete an item by _id (query param) or delete all items if _id not provided. (Requires session)

/users

Method Path Description
GET /users/login Render the login page (HTML form).
POST /users/login Authenticate user. Expects application/x-www-form-urlencoded or JSON { email, password }. On success sets a server-side session. Returns JSON for API clients.
POST /users/logout Destroy the current session (log out).
GET /users/me Return the currently authenticated user's public info (requires session).

Notes:

  • Unauthenticated modifying requests return HTTP 401 JSON; the frontend handles 401 by redirecting the browser to /users/login.
  • The server returns JSON error objects for API clients; HTML form flows receive normal browser navigations.

🗂️ Project Structure

.
├── bin
├── config
├── controllers
├── docker
│   └── nginx
│       └── conf.d
├── middleware
├── models
├── public
│   └── stylesheets
├── routes
├── scripts
├── services
├── certs/                    
└── views

⚙️ Environment Variables

Create a .env file in the root directory with the following variables (example values shown):

API_SERVER=http://shoppinglist-app:3000

MONGO_INITDB_ROOT_USERNAME=adminroot
MONGO_INITDB_ROOT_PASSWORD=change_this_root_password

# App DB
MONGODB_DB=shoppinglistdb
MONGO_APP_USER=shoppinglist_app
MONGO_APP_PASSWORD=change_this_app_password

# Collection names
ITEM_COLLECTION_NAME=items
USER_COLLECTION_NAME=users

# Users DB
USER_DB_NAME=usersdb
USER_DB_USER=users_app
USER_DB_PASSWORD=change_this_users_password

# Initial root/admin user for the application
ROOT_EMAIL=[email protected]
ROOT_PASSWORD=change_this_admin_password

# Session secret used by express-session 
SESSION_SECRET=change_this_session_secret

#MongoDB connection host  
MONGODB_HOST=shoppinglist-mongo

🐳 Running the Application with Docker

  1. Build and start the containers:
  2. docker compose up --build
  3. Visit the app in your browser:
  4. https://youraddress

All dependencies are installed automatically inside the Docker container, so you don’t need to install anything on the host machine.

Database bootstrap & admin population

This project creates DB-level users during MongoDB first-boot using the mongo-init service (mongosh --eval entry). The application-level admin record is created by a short-lived one-shot service admin_user-populate which runs scripts/populate-admin.js.

How it works:

  • mongo-init creates two DB users (app DB and users DB) on first initialization only.
  • admin_user-populate connects with the dedicated USER_DB_USER to insert a hashed admin document into the users collection (idempotent upsert).

🔐 Local TLS (nginx + mkcert) for local dev

This repository uses nginx as a local reverse proxy for HTTPS in development. The proxy expects certificate files mounted at /etc/nginx/certs/cert.pem and /etc/nginx/certs/key.pem (the Compose file mounts your local ./certs directory). You can skip this part if you have some other certs and place them in /certs.

  1. Install mkcert (https://github.com/FiloSottile/mkcert) for your platform and install the local CA once:
# install mkcert (platform-specific), then run once:
mkcert -install
  1. Generate certs for localhost and loopback addresses:
mkdir -p certs
mkcert \
  localhost \
  127.0.0.1 \
  ::1 \
  shoppinglist \
  shoppinglist.local
  1. Start the stack and visit HTTPS locally:
docker compose up --build
# open https://localhost

Note about nginx configuration

  • This repo expects a local nginx config at docker/nginx/conf.d/default.conf (not committed).

Example nginx configuration

The following sample config proxies HTTPS requests to the Node.js app running in Docker. It expects certificate files at /etc/nginx/certs/cert.pem and /etc/nginx/certs/key.pem, and forwards traffic from localhost or shoppinglist.local to the backend service. HTTP requests are redirected to HTTPS.

See docker/nginx/conf.d/default.conf for your local setup.

server {
    listen 443 ssl;
    server_name localhost shoppinglist.local;

    ssl_certificate     /etc/nginx/certs/cert.pem;
    ssl_certificate_key /etc/nginx/certs/key.pem;

    location / {
        proxy_pass         http://shoppinglist-app:3000;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

# Optionally redirect HTTP to HTTPS
server {
    listen 80;
    server_name localhost shoppinglist.local;
    return 301 https://$host$request_uri;
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors