https://github.com/angel-iscoding/ecommerce-api
Ecommerce API developed with Nest.js.
https://github.com/angel-iscoding/ecommerce-api
backend nestjs postgresql redis
Last synced: about 1 month ago
JSON representation
Ecommerce API developed with Nest.js.
- Host: GitHub
- URL: https://github.com/angel-iscoding/ecommerce-api
- Owner: angel-iscoding
- Created: 2024-11-06T19:28:19.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-10-30T11:46:48.000Z (7 months ago)
- Last Synced: 2026-04-13T21:39:18.138Z (about 2 months ago)
- Topics: backend, nestjs, postgresql, redis
- Language: TypeScript
- Homepage:
- Size: 1.3 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Ecommerce API (NestJS)
This repository contains an ecommerce backend built with NestJS. It uses PostgreSQL for persistent storage, Redis for caching/session/cart storage, Cloudinary for media, and TypeORM as the ORM.
This README documents the project's features, how to run it with Docker, environment variables, DB initialization, and common troubleshooting steps.
## Tech stack
- Node.js (NestJS)
- TypeScript
- TypeORM
- PostgreSQL
- Redis
- Cloudinary (file uploads)
- Jest (tests)
## Project features (high level)
- Inventory management (products, stock)
- Persistent shopping cart (backed by Redis)
- Authentication & Authorization (JWT + roles)
- Orders and order details
- Payments integration (PayPal)
- File uploads to Cloudinary
- Seeders / preloaders for categories and products
Each feature is organized in modules inside `src/` (for example `store-management`, `user-management`, `auth`, etc.).
## Docker (recommended)
The repository includes `docker-compose.yml` and a `Dockerfile` to run the whole stack (Postgres, Redis, API).
Quick start (development):
```bash
# Build images and start containers
docker compose up --build
# Tail logs
docker compose logs -f
```
Notes:
- The app exposes port `3000` inside the container and `docker-compose.yml` maps host `3000` to container `3000` by default.
- If this is the first time running, the Postgres container will create the database and user only if the data directory is empty. See "Database initialization" below for an idempotent setup.
## Environment variables
`docker-compose.yml` in this repository uses a small indirection: Docker-specific variables with the `DOCKER_` prefix are used to configure services, and the `app` service picks up translated variables for runtime. The compose file expects an `.env` with the following variables (examples):
Docker / Compose variables (put these in `.env`):
- DOCKER_POSTGRES_USER — Postgres initialization user (example: `ecommerce_user`)
- DOCKER_POSTGRES_PASSWORD — Postgres initialization password
- DOCKER_POSTGRES_DB — Postgres database name
- DOCKER_DB_HOST — host value injected into the app (typically `db`)
- DOCKER_DB_PORT — DB port (typically `5432`)
- DOCKER_REDIS_HOST — Redis host value injected into the app (typically `redis`)
The `db` service maps these Compose variables into Postgres environment variables:
- `POSTGRES_USER: ${DOCKER_POSTGRES_USER}`
- `POSTGRES_PASSWORD: ${DOCKER_POSTGRES_PASSWORD}`
- `POSTGRES_DB: ${DOCKER_POSTGRES_DB}`
The `app` service receives runtime variables from the same `.env` file (via `env_file`) and the compose file maps Docker variables into the app runtime variables. The app expects the following runtime variables (examples):
- DB_HOST — hostname used by TypeORM (set by compose to `${DOCKER_DB_HOST}`)
- DB_PORT — database port (set by compose to `${DOCKER_DB_PORT}`)
- POSTGRES_DB — database name (set by compose to `${DOCKER_POSTGRES_DB}`)
- POSTGRES_PASSWORD — DB password (set by compose to `${DOCKER_POSTGRES_PASSWORD}`)
- REDIS_HOST — Redis host (set by compose to `${DOCKER_REDIS_HOST}`)
- NODE_ENV — `development` or `production`
- APP_PORT — application port (3000)
- JWT_SECRET — secret used for signing JWT tokens (use a long random secret)
Example `.env` (update the values before running in production):
```ini
# Docker / compose variables (used to configure the db & redis services)
DOCKER_POSTGRES_USER=ecommerce_user
DOCKER_POSTGRES_PASSWORD=your_secure_password_here_change_this
DOCKER_POSTGRES_DB=ecommerce_db
DOCKER_DB_HOST=db
DOCKER_DB_PORT=5432
DOCKER_REDIS_HOST=redis
# Application runtime variables (the compose maps DOCKER_* -> app variables)
NODE_ENV=production
APP_PORT=3000
JWT_SECRET=replace_this_with_a_real_secret_min_32_chars
# If you need Redis auth
REDIS_PASSWORD=your_redis_password_here_change_this
```
Security: never commit real secrets; use Docker secrets, environment injection on CI, or a vault in production.
## Database initialization (idempotent)
This repository ships with a `src/config/typeorm.ts` that reads DB credentials from environment variables. To make DB initialization automatic and idempotent when using Docker Compose, there are two approaches:
1. Use Postgres' `/docker-entrypoint-initdb.d` mechanism:
- Create a directory `docker/init/` in the repo and place an SQL file such as `init.sql` with statements guarded by `DO $$ BEGIN ... EXCEPTION WHEN OTHERS THEN END $$;` or use `CREATE ROLE IF NOT EXISTS` / `CREATE DATABASE IF NOT EXISTS` patterns.
- Mount the folder into the `db` service in `docker-compose.yml` as `/docker-entrypoint-initdb.d`. Postgres will execute those scripts only when the data directory is empty (first-run).
2. Use a short `db-init` helper service that waits for Postgres and runs idempotent SQL (helps when you keep the data volume):
- Create a script like `docker/init/db-init.sh` which connects as `postgres` and runs `CREATE ROLE IF NOT EXISTS ...`, `ALTER DATABASE ... OWNER TO ...` and `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`.
- Have the `app` service depend on this `db-init` service or run the script as an init container.
Important: If a Postgres volume already exists, `/docker-entrypoint-initdb.d` scripts will NOT run. In that case either:
- Run the idempotent SQL script manually once (connect to the DB and run it), or
- Remove the volume to reinitialize the DB (data will be lost):
```bash
docker compose down
docker volume rm ecommerce-api_postgres-data
docker compose up --build
```
I included an example script and/or suggested steps in the project's root to help automate this (see `docker/init/` if added).
## Common troubleshooting
- "password authentication failed / role does not exist":
- Reason: the DB user in `.env` wasn't created because Postgres already had an initialized data directory.
- Fix: create the role manually in the Postgres container or use an idempotent init script (see above).
- `function uuid_generate_v4() does not exist`:
- Fix: create the `uuid-ossp` extension in the target database:
```bash
docker compose exec db psql -U postgres -d -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
```
- ESLint warnings about TypeScript version: the project uses TypeScript 5.9.x which may not be supported by the installed `@typescript-eslint` parser. If you see parser warnings, consider pinning a supported TS version, updating `@typescript-eslint` to a newer compatible version, or ignore the warning.
## Development
Run locally without Docker (requires Node and Postgres locally):
```bash
npm install
cp .env.example .env # edit .env
npm run start:dev
```
Notes on path aliases: the project uses `@` as a TypeScript path alias mapping to `src/`. This is configured in `tsconfig.json` and the Jest mapping is set in `package.json` so imports like `@/store-management/products/product.service` work.
## Seeds and preloaders
The project contains preloaders for categories and products (`src/utils/helpers/preload*`). These may throw errors if run multiple times against the same DB because they might not be fully idempotent. Consider modifying seeders to upsert or to skip existing entries.
## Next improvements (suggested)
- Add `docker/init/init.sql` or `docker/init/db-init.sh` with idempotent SQL to ensure DB users, DB and extensions exist on first-run without manual steps.
- Add `package-lock.json` to enable `npm ci` inside Docker and increase build reproducibility.
- Make seeders idempotent (use upsert or pre-checks).
- Add docker secrets or environment config for production.