A comprehensive backend API for connecting travelers with passionate local experts who offer authentic, personalized experiences. This platform empowers individuals to share their city's hidden gems, culture, and stories, allowing travelers to explore destinations like a local.
Postman Collection: Local Guide API Collection
- π Authentication: JWT-based authentication with refresh tokens, password reset, and OTP verification
- π₯ Role-based Access Control:
TOURIST,GUIDE, andADMINroles with appropriate permissions - π User Management: Complete profile management with role-specific fields (expertise, daily rate for guides, travel preferences for tourists)
- π― Tour Listings: Create, update, delete, and manage tour listings with images, pricing, and availability
- π Availability Management: Guides can set available dates/times for their tours
- π Booking System: Complete booking workflow with status management (Pending, Confirmed, Completed, Cancelled)
- π³ Payment Integration: Stripe integration for secure payment processing
- β Review & Rating: Post-tour review and rating system for guides
- β€οΈ Wishlist: Tourists can save favorite listings
- π Badge System: Automated badge assignment for guides (Super Guide, Newcomer, Foodie Expert, etc.)
- π Analytics & Stats: Comprehensive statistics for admins and guides
- π§ Email Notifications: OTP verification and password reset via email
- πΈ File Uploads: Cloudinary integration for image uploads
- π Advanced Search: Filter listings by city, category, price range, and more
β οΈ Global Error Handling: Comprehensive error management and validation- π§± Modular Architecture: Scalable and maintainable codebase structure
- π Security: Input validation, authentication middleware, and secure file handling
- Node.js + Express β Backend framework
- TypeScript β Type-safe development
- PostgreSQL + Prisma β Database with ORM
- Zod β Schema validation
- JWT β Authentication and authorization
- Stripe β Payment processing
- Cloudinary β Image storage and management
- Multer β File upload handling
- Node-cron β Scheduled tasks
- dotenv β Environment configuration
- ESLint β Code quality and linting
- Render β Deployment
# 1. Clone the repository
git clone <repository-url>
cd b5a8-server
# 2. Install dependencies
npm install
# 3. Configure environment variables
cp .env.example .env
# 4. Update .env with your configuration
PORT=5000
DATABASE_URL="postgresql://username:password@localhost:5432/local_guide_db"
NODE_ENV=development
# JWT
JWT_ACCESS_SECRET=your_access_secret
JWT_ACCESS_EXPIRES=3d
JWT_REFRESH_SECRET=your_refresh_secret
JWT_REFRESH_EXPIRES=10d
# BCRYPT
BCRYPT_SALT_ROUND=10
# SUPER ADMIN
SUPER_ADMIN_EMAIL=super@localguide.com
SUPER_ADMIN_PASSWORD=your_super_admin_password
# Express Session
EXPRESS_SESSION_SECRET=your_session_secret
# Frontend URL
FRONTEND_URL=http://localhost:3000
# CLOUDINARY
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# STRIPE
STRIPE_SECRET_KEY=your_stripe_secret_key
STRIPE_WEBHOOK_SECRET=your_stripe_webhook_secret
STRIPE_APPLICATION_FEE_PERCENTAGE=10
STRIPE_CURRENCY=usd
# 5. Prisma migration
npx prisma migrate dev
# 6. Generate Prisma client
npx prisma generate
# 7. Seed database (optional)
npm run db:seed
# 8. Start development server
npm run devπ€ Dummy Users for Testing
Email and password for some dummy users:
// ADMIN
email: super@next.com
password: ph@123456
// TOURIST
email: john.tourist@localguide.com
password: tourist123
// GUIDE
email: ahmed.guide@localguide.com
password: guide123
b5a8-server/
βββ src/
β βββ app/
β β βββ config/
β β β βββ cloudinary.config.ts
β β β βββ db.ts
β β β βββ env.ts
β β β βββ multer.config.ts
β β β βββ redis.config.ts
β β β βββ stripe.config.ts
β β βββ interfaces/
β β β βββ error.ts
β β β βββ error.types.ts
β β β βββ index.d.ts
β β β βββ pagination.ts
β β βββ middlewares/
β β β βββ checkAuth.ts
β β β βββ dbConnection.ts
β β β βββ globalErrorHandler.ts
β β β βββ notFound.ts
β β β βββ validateRequest.ts
β β βββ modules/
β β β βββ auth/
β β β β βββ auth.controller.ts
β β β β βββ auth.routes.ts
β β β β βββ auth.service.ts
β β β β βββ auth.validation.ts
β β β βββ user/
β β β β βββ user.constant.ts
β β β β βββ user.controller.ts
β β β β βββ user.routes.ts
β β β β βββ user.service.ts
β β β β βββ user.validation.ts
β β β βββ listing/
β β β β βββ listing.constant.ts
β β β β βββ listing.controller.ts
β β β β βββ listing.routes.ts
β β β β βββ listing.service.ts
β β β β βββ listing.validation.ts
β β β βββ availability/
β β β β βββ availability.constant.ts
β β β β βββ availability.controller.ts
β β β β βββ availability.routes.ts
β β β β βββ availability.service.ts
β β β β βββ availability.validation.ts
β β β βββ booking/
β β β β βββ booking.constant.ts
β β β β βββ booking.controller.ts
β β β β βββ booking.routes.ts
β β β β βββ booking.service.ts
β β β β βββ booking.validation.ts
β β β βββ payment/
β β β β βββ payment.constant.ts
β β β β βββ payment.controller.ts
β β β β βββ payment.cron.ts
β β β β βββ payment.routes.ts
β β β β βββ payment.service.ts
β β β β βββ payment.validation.ts
β β β β βββ payment.webhook.ts
β β β βββ review/
β β β β βββ review.constant.ts
β β β β βββ review.controller.ts
β β β β βββ review.routes.ts
β β β β βββ review.service.ts
β β β β βββ review.validation.ts
β β β βββ wishlist/
β β β β βββ wishlist.constant.ts
β β β β βββ wishlist.controller.ts
β β β β βββ wishlist.routes.ts
β β β β βββ wishlist.service.ts
β β β βββ badge/
β β β β βββ badge.constant.ts
β β β β βββ badge.controller.ts
β β β β βββ badge.routes.ts
β β β β βββ badge.service.ts
β β β βββ stats/
β β β β βββ stats.controller.ts
β β β β βββ stats.routes.ts
β β β β βββ stats.service.ts
β β β βββ otp/
β β β βββ otp.controller.ts
β β β βββ otp.routes.ts
β β β βββ otp.service.ts
β β β βββ otp.validation.ts
β β βββ routes/
β β β βββ index.ts
β β βββ utils/
β β βββ catchAsync.ts
β β βββ errorHelpers/
β β β βββ AppError.ts
β β β βββ handleClientError.ts
β β β βββ handleValidationError.ts
β β β βββ handleZodError.ts
β β βββ jwt/
β β β βββ jwt.ts
β β β βββ setCookie.ts
β β β βββ userTokens.ts
β β βββ paginationHelper.ts
β β βββ pick.ts
β β βββ seedDummyUsers.ts
β β βββ seedSuperAdmin.ts
β β βββ sendEmail.ts
β β βββ sendResponse.ts
β βββ app.ts
β βββ server.ts
βββ prisma/
β βββ migrations/
β βββ schema.prisma
β βββ prisma.config.ts
βββ sample-data/
β βββ availabilities-bookings-payments-reviews.ts
β βββ cleanAndSeed.ts
β βββ listings.ts
β βββ seedAll.ts
β βββ wishlists.ts
βββ postman/
β βββ Local_Guide_API.postman_collection.json
βββ docs/
β βββ LocalGuide.md
β βββ README.md
β βββ STRIPE_ENV_SETUP.md
β βββ STRIPE_INTEGRATION.md
βββ package.json
βββ tsconfig.json
| Role | Responsibilities |
|---|---|
TOURIST |
Search tours, book guides, write reviews, manage wishlist |
GUIDE |
Create and manage tour listings, set availability, accept bookings |
ADMIN |
Manage users, listings, bookings, view statistics, manage badges |
Base URL: /api/v1
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /auth/register |
Register user (Tourist/Guide) | No |
| POST | /auth/login |
Login user | No |
| POST | /auth/refresh-token |
Refresh JWT token | No |
| POST | /auth/logout |
Logout user | Yes |
| POST | /auth/forgot-password |
Request password reset | No |
| POST | /auth/change-password |
Change password | Yes |
| POST | /auth/reset-password |
Reset password with token | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /otp/send |
Send OTP to email | No |
| POST | /otp/verify |
Verify OTP | No |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /user/me |
Get logged-in user profile | Yes | Any |
| GET | /user/:id |
Get user by ID | No | - |
| GET | /user/top-rated-guides |
Get top rated guides | No | - |
| GET | /user/all-users |
Get all users (paginated) | Yes | ADMIN |
| PATCH | /user/:id |
Update user profile | Yes | Owner/Any |
| PATCH | /user/:id/block-user |
Block/unblock user | Yes | ADMIN |
| POST | /user/create-admin |
Create new admin | Yes | ADMIN |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /listings |
Get all listings (with filters) | No | - |
| GET | /listings/:id |
Get listing by ID | No | - |
| GET | /listings/featured-cities |
Get featured cities | No | - |
| GET | /listings/categories/distinct |
Get distinct categories with counts | No | - |
| GET | /listings/my/listings |
Get my listings (paginated) | Yes | GUIDE |
| POST | /listings |
Create new listing | Yes | GUIDE |
| PATCH | /listings/:id |
Update listing | Yes | GUIDE |
| DELETE | /listings/:id |
Delete listing | Yes | GUIDE |
Query Parameters for GET /listings:
page- Page number (default: 1)limit- Items per page (default: 10)city- Filter by citycategory- Filter by category (CULTURE, FOOD, ADVENTURE, etc.)minPrice- Minimum price filtermaxPrice- Maximum price filtersearch- Search in title/description
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /availabilities |
Get all availabilities | No | - |
| GET | /availabilities/:id |
Get availability by ID | No | - |
| GET | /availabilities/my/availabilities |
Get my availabilities | Yes | GUIDE |
| POST | /availabilities |
Create availability | Yes | GUIDE |
| POST | /availabilities/bulk |
Create bulk availabilities | Yes | GUIDE |
| PATCH | /availabilities/:id |
Update availability | Yes | GUIDE |
| DELETE | /availabilities/:id |
Delete availability | Yes | GUIDE |
Query Parameters for GET /availabilities:
listingId- Filter by listing IDpage- Page numberlimit- Items per page
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| POST | /bookings |
Create booking request | Yes | TOURIST |
| GET | /bookings/my-bookings |
Get my bookings | Yes | Any |
| GET | /bookings |
Get all bookings (admin) | Yes | ADMIN |
| GET | /bookings/:id |
Get booking by ID | Yes | Any |
| PATCH | /bookings/:id/status |
Update booking status | Yes | GUIDE |
Query Parameters for GET /bookings/my-bookings:
page- Page numberlimit- Items per pagetype- Filter by type (upcoming, past)status- Filter by status (PENDING, CONFIRMED, COMPLETED, CANCELLED)
Booking Status Values:
PENDING- Awaiting guide confirmationCONFIRMED- Guide accepted the bookingCOMPLETED- Tour completedCANCELLED- Booking cancelled
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| POST | /payments/confirm |
Confirm payment with Stripe | Yes | TOURIST |
| GET | /payments |
Get my payments | Yes | Any |
| GET | /payments/booking/:bookingId |
Get payment by booking ID | Yes | Any |
| GET | /payments/:id |
Get payment by ID | Yes | Any |
| POST | /payments/:id/release |
Release payment to guide | Yes | GUIDE |
Query Parameters for GET /payments:
page- Page numberlimit- Items per page
Note: Payment processing is handled via Stripe. The webhook endpoint /webhook handles Stripe events.
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /reviews |
Get all reviews | No | - |
| GET | /reviews/:id |
Get review by ID | No | - |
| GET | /reviews/my/reviews |
Get my reviews (as guide) | Yes | GUIDE |
| GET | /reviews/reviewable-bookings |
Get reviewable bookings | Yes | TOURIST |
| GET | /reviews/booking/:bookingId |
Get review by booking ID | No | - |
| GET | /reviews/guide/:guideId |
Get reviews by guide ID | No | - |
| POST | /reviews |
Create review | Yes | TOURIST |
| PATCH | /reviews/:id |
Update review | Yes | TOURIST |
| DELETE | /reviews/:id |
Delete review | Yes | TOURIST |
Query Parameters for GET /reviews:
listingId- Filter by listing IDpage- Page numberlimit- Items per page
Query Parameters for GET /reviews/my/reviews:
page- Page numberlimit- Items per pagesortBy- Sort field (createdAt, rating)sortOrder- Sort order (asc, desc)
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| POST | /wishlist |
Add listing to wishlist | Yes | TOURIST |
| GET | /wishlist |
Get my wishlist | Yes | TOURIST |
| GET | /wishlist/check/:listingId |
Check if listing in wishlist | Yes | TOURIST |
| DELETE | /wishlist/:listingId |
Remove from wishlist | Yes | TOURIST |
Query Parameters for GET /wishlist:
page- Page numberlimit- Items per page
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /badges/guide/:guideId |
Get guide badges | No | - |
| POST | /badges/guide/:guideId/recalculate |
Recalculate guide badges | Yes | ADMIN |
| POST | /badges/recalculate-all |
Recalculate all badges | Yes | ADMIN |
Badge Types:
SUPER_GUIDE- High ratings and many bookingsNEWCOMER- New guide on the platformFOODIE_EXPERT- Expertise in food toursCULTURE_MASTER- Expertise in cultural toursADVENTURE_SEEKER- Expertise in adventure tours
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /stats/overview |
Get overview statistics | Yes | ADMIN |
| GET | /stats/users |
Get user statistics | Yes | ADMIN |
| GET | /stats/tourists |
Get tourist statistics | Yes | ADMIN |
| GET | /stats/guides |
Get guide statistics | Yes | ADMIN |
| GET | /stats/listings |
Get listing statistics | Yes | ADMIN |
| GET | /stats/bookings |
Get booking statistics | Yes | ADMIN |
| GET | /stats/revenue |
Get revenue statistics | Yes | ADMIN |
| GET | /stats/profit |
Get profit statistics | Yes | ADMIN |
| GET | /stats/guide-info |
Get guide info and stats | Yes | GUIDE |
- id: Primary key
- name: User's full name
- email: Unique email address
- password: Hashed password
- phone: Optional phone number
- picture: Profile picture URL
- bio: User biography
- languages: Array of languages spoken
- role: User role (TOURIST, GUIDE, ADMIN)
- isActive: Account status (ACTIVE, INACTIVE, BLOCKED)
- isVerified: Email verification status
- isDeleted: Soft delete flag
- expertise: Array of expertise areas (Guide only)
- dailyRate: Daily rate for guides
- travelPreferences: Array of travel preferences (Tourist only)
- stripeCustomerId: Stripe customer ID (Tourist only)
- id: Primary key
- title: Tour listing title
- description: Tour description
- itinerary: Detailed itinerary
- tourFee: Tour fee amount
- durationDays: Maximum duration in days
- meetingPoint: Meeting point location
- maxGroupSize: Maximum group size
- city: City where tour is located
- category: Tour category (CULTURE, FOOD, ADVENTURE, etc.)
- images: Array of image URLs
- isActive: Listing active status
- guideId: Reference to Guide User
- id: Primary key
- startDateTime: Start date and time
- endDateTime: End date and time
- isAvailable: Availability status
- listingId: Reference to Listing
- id: Primary key
- date: Booking date
- numberOfGuests: Number of guests
- status: Booking status (PENDING, CONFIRMED, COMPLETED, CANCELLED)
- touristId: Reference to Tourist User
- listingId: Reference to Listing
- availabilityId: Reference to Availability
- id: Primary key
- amount: Payment amount
- currency: Payment currency
- status: Payment status
- paymentIntentId: Stripe payment intent ID
- bookingId: Reference to Booking
- touristId: Reference to Tourist User
- guideId: Reference to Guide User
- id: Primary key
- rating: Rating (1-5)
- comment: Review comment
- bookingId: Reference to Booking
- touristId: Reference to Tourist User
- guideId: Reference to Guide User
- listingId: Reference to Listing
- id: Primary key
- touristId: Reference to Tourist User
- listingId: Reference to Listing
- id: Primary key
- type: Badge type
- guideId: Reference to Guide User
All protected endpoints require tokens in the cookies:
cookie: accessToken=<access_token>
cookie: refreshToken=<refresh_token>
Access tokens expire after the configured time (default: 3 days). Use the refresh token endpoint to obtain a new access token.
{
"success": true,
"statusCode": 200,
"message": "Operation successful",
"data": {
// Response data
},
"meta": {
// Pagination metadata (if applicable)
"page": 1,
"limit": 10,
"total": 100,
"totalPages": 10
}
}{
"success": false,
"statusCode": 400,
"message": "Error message",
"errorDetails": {
// Detailed error information
},
"stack": "Error stack (development only)"
}Use the provided Postman collection to test all endpoints:
- Import
postman/Local_Guide_API.postman_collection.jsoninto Postman - Set the
base_urlvariable to your API URL (default:http://localhost:5000/api/v1) - Start with authentication endpoints to get access tokens
- Tokens are automatically saved to collection variables for subsequent requests
The application can be deployed to various platforms. Ensure all environment variables are properly configured in your deployment environment.
npm run buildnpm startFaisal Akbar