Multi-tenant scheduling platform with smart slot management, payment integration, and automated notifications
Service-based businesses face scheduling challenges:
A comprehensive multi-tenant platform that automates scheduling, payments, and notifications for service businesses like doctors, salons, and consultants.
```mermaid graph TB A[React Frontend] β>|API Calls| B[Express Backend] B β>|CRUD| C[MongoDB] B β>|Send SMS| D[AWS SNS] B β>|Process Payment| E[Stripe API] F[Slot Manager] β>|Check Availability| C B β>|Use| F G[Cron Jobs] β>|Trigger| H[Reminder Service] H β>|Send| D
style A fill:#61DAFB
style B fill:#000000
style C fill:#47A248
style E fill:#008CDD \`\`\`
``` appointment-booking-system/ βββ backend/ β βββ controllers/ β β βββ appointmentController.js # Booking logic β β βββ userController.js # User management β β βββ paymentController.js # Stripe integration β βββ models/ β β βββ Appointment.js # Appointment schema β β βββ User.js # User schema β β βββ Business.js # Business schema β βββ services/ β β βββ slot_manager.js # Smart slot algorithm β β βββ sms_service.js # AWS SNS integration β β βββ payment_service.js # Stripe wrapper β βββ routes/ β β βββ api.js # API routes β βββ server.js # Express server βββ frontend/ β βββ src/ β β βββ components/ β β β βββ Calendar.jsx # Booking calendar β β β βββ ServiceList.jsx # Available services β β β βββ BookingForm.jsx # Appointment form β β β βββ Dashboard.jsx # Admin dashboard β β βββ pages/ β β β βββ Home.jsx β β β βββ Booking.jsx β β β βββ Admin.jsx β β βββ App.jsx β βββ package.json βββ README.md ```
Clone and install ```bash git clone https://github.com/Abhinandansinha01/portfolio.git cd appointment-booking-system/backend npm install ```
Configure environment variables ```bash
cat > .env « EOF PORT=5000 MONGODB_URI=mongodb://localhost:27017/appointments STRIPE_SECRET_KEY=sk_test_your_stripe_key AWS_ACCESS_KEY_ID=your_aws_key AWS_SECRET_ACCESS_KEY=your_aws_secret AWS_REGION=us-east-1 SNS_TOPIC_ARN=arn:aws:sns:us-east-1:123456789:appointments JWT_SECRET=your_jwt_secret EOF ```
Start MongoDB ```bash
mongod βdbpath /data/db ```
Run backend ```bash npm run dev
```
Navigate and install ```bash cd ../frontend npm install ```
Configure API endpoint ```bash
echo βREACT_APP_API_URL=http://localhost:5000/apiβ > .env echo βREACT_APP_STRIPE_PUBLIC_KEY=pk_test_your_public_keyβΒ Β» .env ```
Run frontend ```bash npm start
```
The core innovation of this system is the intelligent slot management:
```javascript // slot_manager.js class SlotManager { constructor(business) { this.business = business; this.bufferTime = business.bufferTime || 15; // minutes }
async getAvailableSlots(date, serviceId) { const service = await Service.findById(serviceId); const duration = service.duration; const businessHours = this.business.hours[date.getDay()];
// Generate all possible slots
const allSlots = this.generateTimeSlots(
businessHours.start,
businessHours.end,
duration + this.bufferTime
);
// Get existing bookings for the date
const bookings = await Appointment.find({
businessId: this.business._id,
date: date,
status: { $ne: 'cancelled' }
});
// Filter out booked slots
const availableSlots = allSlots.filter(slot => {
return !this.hasConflict(slot, duration, bookings);
});
return availableSlots; }
hasConflict(slot, duration, bookings) { const slotStart = new Date(slot); const slotEnd = new Date(slotStart.getTime() + duration * 60000);
return bookings.some(booking => {
const bookingStart = new Date(booking.startTime);
const bookingEnd = new Date(booking.endTime);
// Check for overlap
return (slotStart < bookingEnd && slotEnd > bookingStart);
}); }
generateTimeSlots(start, end, interval) { const slots = []; let current = new Date(`2000-01-01T${start}`); const endTime = new Date(`2000-01-01T${end}`);
while (current < endTime) {
slots.push(current.toTimeString().slice(0, 5));
current = new Date(current.getTime() + interval * 60000);
}
return slots; } } \`\`\`
```javascript // payment_service.js const createPaymentIntent = async (amount, customerId) => { const paymentIntent = await stripe.paymentIntents.create({ amount: amount * 100, // Convert to cents currency: βusdβ, customer: customerId, payment_method_types: [βcardβ], metadata: { type: βappointment_depositβ } });
return paymentIntent.client_secret; }; ```
```javascript // sms_service.js const sendSMS = async (phoneNumber, message) => { const params = { Message: message, PhoneNumber: phoneNumber, MessageAttributes: { βAWS.SNS.SMS.SMSTypeβ: { DataType: βStringβ, StringValue: βTransactionalβ } } };
await sns.publish(params).promise(); };
// Notification templates const templates = { confirmation: (name, date, time) => `Hi ${name}! Your appointment is confirmed for ${date} at ${time}. Reply CANCEL to cancel.`,
reminder: (name, hours) => `Hi ${name}! Reminder: Your appointment is in ${hours} hours. See you soon!`,
cancellation: (name) => `Hi ${name}, your appointment has been cancelled. Your refund will be processed in 5-7 days.` }; ```
```javascript const appointmentSchema = new Schema({ businessId: { type: ObjectId, ref: βBusinessβ, required: true }, customerId: { type: ObjectId, ref: βUserβ, required: true }, serviceId: { type: ObjectId, ref: βServiceβ, required: true }, date: { type: Date, required: true }, startTime: { type: Date, required: true }, endTime: { type: Date, required: true }, status: { type: String, enum: [βpendingβ, βconfirmedβ, βcompletedβ, βcancelledβ], default: βpendingβ }, payment: { amount: Number, status: String, stripePaymentId: String }, notes: String, createdAt: { type: Date, default: Date.now } }); ```
```javascript // Business schema const businessSchema = new Schema({ name: String, slug: { type: String, unique: true }, logo: String, hours: { monday: { start: String, end: String }, tuesday: { start: String, end: String }, // β¦ other days }, services: [{ type: ObjectId, ref: βServiceβ }], stripeAccountId: String, settings: { bufferTime: Number, cancellationPolicy: String, depositPercentage: Number } }); ```
Contributions are welcome! Please feel free to submit a Pull Request.
This project is open source and available under the MIT License.
Abhinandan Sinha