Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
283 changes: 232 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,264 @@
# 🏠 Property Viewing Scheduler – Backend Challenge
# 🏠 Property Viewing Scheduler API

A NestJS-based backend service for managing property viewings in a real estate platform. This service allows potential buyers or renters to schedule property viewings while ensuring no scheduling conflicts occur.

## 📋 Swagger Documentation

You can access the Swagger documentation at `http://localhost:3000/api`.
<img src="./assets/image.png" alt="Swagger Documentation">

## 📋 Table of Contents
- [Features](#-features)
- [Tech Stack](#-tech-stack)
- [Getting Started](#-getting-started)
- [API Documentation](#-api-documentation)
- [Data Models](#-data-models)
- [Authentication](#-authentication)
- [Testing](#-testing)
- [Environment Configuration](#-environment-configuration)
- [Deployment](#-deployment)
- [Contributing](#-contributing)

## ✨ Features

### Core Functionality
- ✅ Schedule property viewings with automatic conflict detection
- ✅ View available time slots for properties
- ✅ Property management (CRUD operations)
- ✅ User authentication and authorization
- ✅ Input validation and error handling

### Security
- JWT-based authentication
- Role-based access control (User, Agent)
- Request validation and sanitization

## 🛠 Tech Stack

- **Runtime**: Node.js
- **Framework**: [NestJS](https://docs.nestjs.com/)
- **Database**: MongoDB with Mongoose ODM
- **Authentication**: JWT
- **Testing**: Jest (unit + e2e)
- **Language**: TypeScript

## 🚀 Getting Started

### Prerequisites
- Node.js (v16 or later)
- npm or yarn
- MongoDB (local or remote)

### Installation

1. **Clone the repository**
```bash
git clone <repository-url>
cd backend-task
```

2. **Install dependencies**
```bash
npm install
```

3. **Set up environment variables**
Create a `.env` file in the root directory with the following variables:
```env
MONGODB_URI=mongodb://localhost:27017/property-viewings
JWT_SECRET=your_jwt_secret_key
JWT_EXPIRES_IN=3600
```

4. **Run the application**
```bash
# Development mode
npm run start:dev

# Production mode
npm run build
npm run start:prod
```

The application will be available at `http://localhost:3000` by default.

## 📚 API Documentation

### Authentication

#### Login
```http
POST /auth/login
Content-Type: application/json

{
"username": "user@example.com",
"password": "password123"
}
```

Welcome to the technical challenge for the Backend Engineer role at Sakneen.
**Response**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

The goal is to evaluate not only your proficiency with **NestJS + Mongoose**, but also your ability to make thoughtful **design decisions**, identify **edge cases**, and handle **uncertainty** — just like in real-world software projects.
### Properties

---
#### Get All Properties
```http
GET /properties
Authorization: Bearer <token>
```

## 🚀 Task Overview
#### Get Available Time Slots
```http
GET /properties/:id/available-slots?date=2025-08-01
Authorization: Bearer <token>
```

You're tasked with implementing a **property viewing reservation feature** for a real estate platform. Potential buyers or renters can request to view available properties, by reserving a slot to view the property, so each request must respect certain conditions and availability logic.
### Property Viewings

---
#### Schedule a Viewing
```http
POST /property-viewings
Authorization: Bearer <token>
Content-Type: application/json

## 🧱 Core Requirements
{
"propertyId": "507f1f77bcf86cd799439011",
"scheduledTime": "2025-08-01T14:30:00Z",
"durationMinutes": 30
}
```

### Domain Concepts (minimum)
#### Cancel a Viewing
```http
DELETE /property-viewings/:id
Authorization: Bearer <token>
```

You will likely need to represent the following:
## 🗄 Data Models

### Property
```typescript
{
_id: ObjectId,
title: string,
description: string,
address: {
street: string,
city: string,
state: string,
zipCode: string,
country: string
},
price: number,
bedrooms: number,
bathrooms: number,
area: number, // in square meters
type: 'APARTMENT' | 'HOUSE' | 'OFFICE' | 'LAND',
status: 'AVAILABLE' | 'PENDING' | 'SOLD' | 'RENTED',
features: string[],
images: string[],
agentId: string,
createdAt: Date,
updatedAt: Date
}
```

- **Property Viewing**
Represents a reserved scheduled viewing by a potential customer.
### Property Viewing
```typescript
{
_id: ObjectId,
propertyId: ObjectId,
userId: string,
agentId: string,
scheduledTime: Date,
durationMinutes: number,
status: 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED',
notes: string,
createdAt: Date,
updatedAt: Date
}
```

Other supporting entities or concepts may be needed — define and structure them as you see fit.
---
## 🔐 Authentication

### Essential Functionalities
The API uses JWT (JSON Web Tokens) for authentication. Include the JWT token in the `Authorization` header for protected routes:

At a minimum, your solution should allow:
```
Authorization: Bearer <token>
```

- [ ] Scheduling a viewing on a property
- [ ] Ensuring viewing times do not conflict for the same property
- [ ] Fetching available time slots for a property on a given day/week/month
### Available Roles
- **User**: Can view properties and schedule viewings
- **Agent**: Can manage properties and view scheduled viewings

---
## 🧪 Testing

## 🎁 Bonus (Optional but Valued)
Run the test suite with:

You may choose to implement any of the following enhancements:
```bash
# Unit tests
npm run test

- [ ] Authentication & role separation (e.g., user vs. agent)
- [ ] Handling agent unavailability (blocking out time ranges)
- [ ] Email confirmation mock (real or simulated)
- [ ] Any thing needs fixing in the existing APIS ... ?
# E2E tests
npm run test:e2e

Use these to showcase architectural thinking — don’t overbuild unless it adds clarity or value.
# Test coverage
npm run test:cov
```

---
## ⚙️ Environment Configuration

## 📦 Tech Stack
The application can be configured using environment variables:

Your solution should use:
| Variable | Description | Default |
|----------|-------------|---------|
| `PORT` | Application port | 3000 |
| `JWT_SECRET` | Secret key for JWT signing | (required) |
| `JWT_EXPIRES_IN` | JWT expiration time | 1h |

- [NestJS](https://docs.nestjs.com/)
- [Mongoose](https://mongoosejs.com/) + [MongoDB](https://www.mongodb.com/)
- TypeScript
- Jest (for unit + e2e testing)
## 🚀 Deployment

---
### Prerequisites
- Node.js
- MongoDB
- PM2 (recommended for production)

## 💾 Running the Project
### Steps
1. Build the application:
```bash
npm run build
```

```bash
# 1. Clone the repo
2. Start the application:
```bash
npm run start:prod
```

# 2. Install dependencies
npm install
3. For production, use a process manager like PM2:
```bash
npm install -g pm2
pm2 start dist/main.js --name "property-viewing-api"
```

# 3. Start the app
npm run start:dev
```
---
## 🤝 Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## Data
## 📄 License

- There is a seed script that seeds the mongo memory server with some different properties
- It runs at application bootstrapping process
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---
## 👏 Acknowledgments

## 📬 Submission Guidelines
- Make a PR on the our Github repo with your adjustments as needed
- Try to follow a readable/reviewable structure for your PR
- NestJS community for the awesome framework
- MongoDB for the flexible NoSQL database
- All contributors who have helped improve this project
Binary file added assets/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading