Skip to content

Getting Started

_david edited this page Sep 26, 2026 · 2 revisions

Getting Started

Requirements

  • Node.js >=20.19.0 <23.0.0 (Node 24+ breaks jsonwebtoken's dependency chain — see Deployment)
  • npm (uses package-lock.json)
  • A MongoDB instance (Atlas or self-hosted) — or use Docker, see below
  • Redis (optional — falls back to an in-memory store for rate limiting and token blacklist if REDIS_URL is unset or unreachable)

Setup

git clone https://github.com/datvt243/resume-nodejs-api.git
cd resume-nodejs-api
npm install
npm run env:setup   # cp .env.example .env, then fill in real values

Environment variables

NODE_ENV=development
LOCAL_PORT=3001              # prod uses 3008
MONGO_URI=...                # full URI, or use MONGOBD_USER + MONGOBD_PASSWORD
MONGOBD_USER=...
MONGOBD_PASSWORD=...
TOKEN_SECRET=...             # 32+ chars, signs access tokens
TOKEN_REFRESH=...            # signs refresh tokens
TOKEN_EXP_IN=...             # access token expiry (e.g. 3h)
TOKEN_REFRESH_EXP_IN=...     # optional, defaults to 7d — refresh token expiry
SESSION_SECRET=...
REDIS_URL=redis://localhost:6379   # optional; fallback to in-memory if absent/unreachable
MONGO_MAX_POOL_SIZE=10       # optional
MONGO_MIN_POOL_SIZE=2        # optional
CORS_ORIGIN=...              # comma-separated allow-list, REQUIRED for the httpOnly cookie
                              # auth flow (credentials:true can't combine with a wildcard origin);
                              # unset in dev reflects the caller's origin, unset in prod fails closed

Commands

npm run dev                  # ts-node + nodemon hot reload (port 3001)
npm run build                # tsc + copy views/public → dist/
npm start                    # build + NODE_ENV=production node dist/server.js
npm test                     # jest --passWithNoTests

npm run env:setup            # cp .env.example .env
npm run env:dev              # cp .env.development .env
npm run env:prod             # cp .env.production .env
npm run copy                 # copy views + public to dist/ (post-build fix, runs automatically as part of build)

npm run migrate:localize-text  # one-off migration: wraps existing plain-string CV content
                                # into { vi, en } — see Data Models. Idempotent, safe to re-run.

There is no npm run lint script despite .eslintrc.cjs existing in the repo — don't assume it works.

Running with Docker instead

No local Node/Mongo install needed:

docker compose up --build

→ http://localhost:3001/health — dev mode, hot reload, insecure built-in dev secrets, no .env required, includes a MongoDB 7 container with a persistent volume.

For a production-shaped image (compiled, real secrets required):

cp .env.example .env   # fill in real TOKEN_SECRET/TOKEN_REFRESH/SESSION_SECRET/CORS_ORIGIN
docker compose -f docker-compose.prod.yml up -d --build

→ http://localhost:3008/health

Redis is intentionally not containerized in either stack — the app already falls back to in-memory.

Verifying it's running

curl http://localhost:3001/health
# {"status":"ok","timestamp":"...","uptime":...}

Swagger UI is available at http://localhost:3001/api-docs (raw spec at /api-docs.json).

A note on Node version managers (nvm)

If you use nvm and also have Node installed via Homebrew, make sure your shell's nvm sourcing happens after any Homebrew PATH export in your shell rc file — otherwise nvm use silently has no effect and you'll run whatever Homebrew's node resolves to, which can be newer than this project's supported range.

Clone this wiki locally