A REST API built with NestJS and TypeScript for managing services and customer bookings. Built as part of the EN2H Software Engineer Intern (NestJS) technical assessment.
This API allows:
- Users to register and login using JWT authentication (with refresh tokens)
- Authenticated users to manage services (create, update, delete, list, view)
- Customers to create bookings without authentication, and authenticated users to manage booking status, search, and filter bookings
- Framework: NestJS + TypeScript
- Database: SQLite (via TypeORM, driver:
better-sqlite3) - Auth: JWT access + refresh tokens (Passport)
- Validation: class-validator / class-transformer
- API Docs: Swagger (OpenAPI)
- Testing: Jest (unit tests)
- Containerization: Docker
src/ ├── auth/ # Register, Login, Refresh, JWT strategy & guard ├── catalog/ # Service management (CRUD) ├── bookings/ # Booking management (CRUD, status update, cancel, pagination/search) ├── common/ # Global exception filter, shared DTOs (pagination) ├── database/ # TypeORM data source & migrations ├── app.module.ts └── main.ts
- Clone the repository:
git clone https://github.com/agusandeepa/booking-platform.git
cd booking-platform- Install dependencies:
npm install- Copy the example environment file and adjust values if needed:
cp .env.example .envCreate a .env file in the project root (see .env.example):
| Variable | Description | Default |
|---|---|---|
PORT |
Port the API listens on | 3000 |
DB_DATABASE |
SQLite database file name | booking_platform.sqlite |
JWT_SECRET |
Secret key used to sign access tokens | — |
JWT_EXPIRES_IN |
Access token expiry duration | 3600s |
REFRESH_TOKEN_SECRET |
Secret key used to sign refresh tokens | — |
REFRESH_TOKEN_EXPIRES_IN |
Refresh token expiry duration | 7d |
This project uses SQLite with TypeORM, so no external database server is required.
The database file (booking_platform.sqlite) is created automatically the first time migrations are run (see below). Schema changes are managed entirely through migrations — synchronize is disabled.
# Run all pending migrations
npm run migration:run
# Generate a new migration after changing an entity
npm run migration:generate -- src/database/migrations/MigrationName
# Revert the last migration
npm run migration:revert# Development (watch mode)
npm run start:dev
# Production build
npm run build
npm run start:prodOnce running, the API is available at:
- Base URL:
http://localhost:3000 - Swagger Docs:
http://localhost:3000/api/docs
Build and run the application in a container:
docker build -t booking-platform .
docker run -p 3000:3000 --env-file .env booking-platformOr using Docker Compose:
docker compose up --buildThe API will be available at http://localhost:3000 and Swagger docs at http://localhost:3000/api/docs.
Unit tests cover the Auth, Catalog, and Bookings services, including business rules, validation logic, and edge cases.
npm run test # run all unit tests
npm run test:cov # run tests with a coverage reportFull interactive API documentation (Swagger) is available at /api/docs once the app is running. It includes all endpoints, request/response schemas, and a built-in "Authorize" button to test protected routes with a JWT access token.
Auth
POST /auth/register— Register a new userPOST /auth/login— Login and receive an access token + refresh tokenPOST /auth/refresh— Exchange a valid refresh token for a new access token
Services (JWT required)
POST /services— Create a serviceGET /services— List all servicesGET /services/:id— Get a service by IDPATCH /services/:id— Update a serviceDELETE /services/:id— Delete a service
Bookings
POST /bookings— Create a booking (public, no auth required)GET /bookings— List bookings, supports?page=,?limit=,?search=(by customer name/email), and?status=filter (JWT required)GET /bookings/:id— Get a booking by ID (JWT required)PATCH /bookings/:id/status— Update booking status (JWT required)PATCH /bookings/:id/cancel— Cancel a booking (JWT required)
- Pagination and search (by customer name/email) on the bookings list endpoint
- Filter bookings by status
- Swagger (OpenAPI) documentation
- Global exception handling
- Refresh token support
- Unit tests for Auth, Catalog, and Bookings services
- Duplicate booking prevention (same service, date, and time)
- Docker support (Dockerfile + docker-compose)
- A booking must belong to an existing service
- Booking dates cannot be in the past
- Cancelled bookings cannot be marked as completed
- Only authenticated users can manage services
- Customers can create bookings without authentication
- Duplicate bookings for the same service, date, and time are rejected
- Since the assignment did not specify authorization roles beyond "authenticated users," any registered/logged-in user is treated as having full access to manage services and bookings (no separate admin/staff role was introduced).
bookingDateis stored as a date-only string (YYYY-MM-DD) andbookingTimeas a 24-hourHH:mmstring, kept as separate fields as specified in the booking model.- SQLite was chosen over PostgreSQL for ease of setup and review, since no external database server needs to be installed.
- A
COMPLETEDstatus was added to theBookingStatusenum (in addition toPENDING,CONFIRMED,CANCELLED) since the business rule "cancelled bookings cannot be marked as completed" implies a completed state exists. - Refresh tokens are stored hashed (bcrypt) in the database and are invalidated on logout or reuse detection failure.
- Role-based access control (e.g. distinguishing admin/staff from regular users)
- Pagination and search for the services list endpoint as well
- Rate limiting on auth endpoints
- Switch to PostgreSQL for production use
- CI/CD pipeline for automated testing and deployment


