NestJS service that manages users, products, and a transaction history.
- Runtime: Node.js + NestJS
- Database: PostgreSQL (Docker Compose)
- ORM: TypeORM
- Migrations: TypeORM migrations (
src/migrations/*) - Validation:
class-validator+ globalValidationPipe
docker compose up --build- API:
http://localhost:3000 - Postgres:
localhost:5435(container port5432)
curl -i http://localhost:3000/docker compose up -d postgres.env (example)
PORT=3000
DB_HOST=localhost
DB_PORT=5435
DB_USER=embed
DB_PASS=embed
DB_NAME=assignmentnpm install
npm run migration:run
npm run start:devnpm run migration:generatenpm run migration:runnpm run migration:revertnpm testE2E tests (if present):
npm run test:e2eBase URL: http://localhost:3000
- All request/response bodies are JSON.
- IDs in routes are integers (invalid IDs return
400). - Validation errors return
400with a structured error body. - Not found resources return
404.
Create a user.
Request body:
{
"firstName": "Ada",
"lastName": "Lovelace",
"email": "ada@example.com"
}Responses:
201 Created→ created user400 Bad Request→ validation error
Example:
curl -i -X POST http://localhost:3000/users \
-H 'Content-Type: application/json' \
-d '{"firstName":"Ada","lastName":"Lovelace","email":"ada@example.com"}'List all users.
Responses:
200 OK→ array of users
Example:
curl -i http://localhost:3000/usersGet a single user.
Responses:
200 OK→ user404 Not Found
Example:
curl -i http://localhost:3000/users/1Update a user (partial update).
Request body (any subset):
{ "firstName": "Grace" }Responses:
200 OK→ updated user400 Bad Request→ validation error404 Not Found
Delete a user.
Responses:
204 No Content404 Not Found
Create a product.
Request body:
{
"name": "iPhone 15",
"description": "256GB",
"price": 999.99,
"stockQuantity": 10
}Responses:
201 Created→ created product400 Bad Request→ validation error
Example:
curl -i -X POST http://localhost:3000/products \
-H 'Content-Type: application/json' \
-d '{"name":"iPhone 15","description":"256GB","price":999.99,"stockQuantity":10}'List all products.
Responses:
200 OK
Get a single product.
Responses:
200 OK404 Not Found
Adjust product stock by a delta (positive or negative). Implemented as an atomic DB transaction with row locking.
Request body:
{
"productId": 1,
"delta": -2
}Rules:
deltamust not be0- final stock must not be negative
Responses:
200 OK→ updated product400 Bad Request→ invalid delta / insufficient stock404 Not Found
Example:
curl -i -X PUT http://localhost:3000/products/adjust \
-H 'Content-Type: application/json' \
-d '{"productId":1,"delta":-2}'Returns a minimal product status view.
Response body:
{
"productId": 1,
"stockQuantity": 10,
"inStock": true
}Responses:
200 OK404 Not Found
Example:
curl -i http://localhost:3000/status/1Create a transaction. On create/update, product stock is adjusted inside a DB transaction with pessimistic_write locks.
Request body:
{
"userId": 1,
"productId": 1,
"quantity": 2
}Notes:
unitPriceis captured from the product at the time of purchase (snapshot).
Responses:
201 Created→ created transaction400 Bad Request→ insufficient stock / validation error404 Not Found→ product not found
Example:
curl -i -X POST http://localhost:3000/transactions \
-H 'Content-Type: application/json' \
-d '{"userId":1,"productId":1,"quantity":2}'List all transactions.
Responses:
200 OK
Example:
curl -i http://localhost:3000/transactionsGet a single transaction.
Responses:
200 OK404 Not Found
Update a transaction. Handles stock adjustments safely:
- If quantity increases → requires additional stock
- If quantity decreases → returns stock
- If product changes → returns stock to old product, deducts from new product
Responses:
200 OK400 Bad Request→ insufficient stock / invalid quantity404 Not Found
Delete a transaction.
Responses:
204 No Content404 Not Found
- Stock changes are enforced using DB transactions + row locks for correctness under concurrency.
- Transaction
unitPriceis stored as a snapshot (product price may change later).