This is a technical implementation scenario prepared by Zipprr’s engineering documentation team to illustrate how a diet & nutrition clinic booking and management platform can be architected and built on Zipprr’s white-label clone-script stack (the same core architecture used in Zipprr’s Practo Clone). It does not claim a specific named client deployment, and no performance numbers below are drawn from a live production account.
Executive Summary
Diet and nutrition clinics — solo dietitians, multi-location nutrition chains, and hospital-affiliated nutrition departments — largely still run on phone bookings, WhatsApp diet-plan PDFs, and spreadsheet-based patient tracking. That model breaks down once a clinic grows past one dietitian or one location: appointment slots double-book, diet plans get lost in chat threads, and there is no structured record of a patient’s meal logs, weight trend, or renewal history.
A Diet & Nutrition Clinic Management platform solves this by combining appointment booking, dietitian-patient communication, digital diet-plan delivery, subscription billing, and progress tracking into one product with three faces: a patient-facing mobile/web app, a dietitian workspace, and a clinic admin dashboard.
Who needs this: independent dietitians scaling into a multi-practitioner clinic, wellness/diet-plan subscription startups, hospital nutrition departments, and corporate wellness programs that offer nutrition counseling as a benefit.
Architecture approach used in this case study: a modular, API-first backend (Node.js/Express or Laravel, interchangeable) behind a single API gateway, a relational database (MySQL/PostgreSQL) for transactional data, Flutter for the patient and dietitian mobile apps, React for the web app and admin dashboard, and a clearly separated integration layer for payments, maps, notifications, and optional AI-assisted meal planning.
A diet and nutrition clinic management platform is healthcare-adjacent booking software that lets patients discover dietitians, book appointments, receive digital diet plans, log meals/weight, and pay for subscriptions, while giving dietitians and clinic admins a shared backend for scheduling, patient records, and billing — typically built on a three-tier architecture (client apps → API/business logic layer → database) with third-party integrations for payments, maps, and notifications.
Why this case study matters: it documents, at an engineering level, a reference architecture that generalizes to any appointment + subscription + record-keeping healthcare vertical (nutrition, physiotherapy, mental health counseling, dermatology teleconsults), not just this one use case.
Project Overview
| Attribute | Details |
|---|---|
| Project Type | Multi-sided clinic management platform (patient app + dietitian app + admin dashboard) |
| Industry | Healthcare & Wellness — Nutrition and Dietetics |
| Target Users | Independent dietitians, multi-location nutrition clinics, wellness subscription brands, corporate wellness vendors, patients/clients seeking diet consultations |
| Platform Components | Patient mobile app (iOS/Android), Dietitian mobile/web app, Clinic Admin web dashboard, Backend API, Super Admin console |
| Technology Stack | Flutter (mobile), React.js (web/admin), Node.js + Express or Laravel (backend API — interchangeable per client stack preference), MySQL/PostgreSQL (database), Redis (caching/queues), Firebase Cloud Messaging (push), Twilio (SMS/OTP), Razorpay/Stripe (payments), Google Maps Platform (clinic locator), AWS S3 (file storage), OpenAI API (optional AI diet-plan assistant) |
| Development Approach | Modular monolith at launch (single deployable API with clearly separated modules), designed so individual modules — auth, booking, billing, diet-plan engine, notifications — can be extracted into microservices as transaction volume grows |
Business Challenge
Nutrition clinics that operate below roughly 3–5 practitioners typically manage bookings through a mix of phone calls, WhatsApp, and a physical or spreadsheet appointment register. As a clinic adds dietitians or locations, several structural problems appear:
- Scheduling conflicts: without a shared, real-time calendar, the same slot can be promised to two patients, or a dietitian’s availability isn’t visible to front-desk staff booking on their behalf.
- Diet plans live outside any system of record: PDFs and images sent over WhatsApp are not searchable, not versioned, and disappear from a patient’s chat history over time — making it hard to track what plan a patient is actually following.
- No structured adherence data: clinics have no consistent way to capture a patient’s meal logs, weight trend, or symptom notes between visits, which weakens follow-up consultations.
- Manual, inconsistent billing: package purchases (e.g., “12-session nutrition program”) are tracked manually, so renewal reminders, partial-usage tracking, and refund handling are ad hoc.
- No multi-location visibility: a clinic expanding to a second city has no single dashboard to compare occupancy, revenue, or dietitian utilization across branches.
This represents a technical implementation scenario and does not claim a specific client deployment. The problems described above are common, documented patterns in appointment-based healthcare services generally, rather than metrics attributed to one deployment.
Solution Architecture
The platform is organized into three layers: a frontend layer serving three distinct user roles, a backend layer handling business logic and data, and an integration layer connecting to external services.
Frontend Layer:
- Patient mobile app (Flutter — iOS & Android) for discovery, booking, diet-plan viewing, meal logging, and payments
- Dietitian web/mobile app for calendar management, patient records, and diet-plan authoring
- Clinic Admin dashboard (React) for staff management, multi-location reporting, and billing oversight
Backend Layer:
- API Gateway (single entry point, request routing, rate limiting)
- Authentication & Authorization service (JWT-based, role-based access control)
- Business Logic Layer (booking engine, diet-plan engine, subscription/billing engine)
- Database layer (MySQL/PostgreSQL, with Redis for caching and session/queue management)
Integration Layer:
- Payment gateway (Razorpay for India, Stripe for international)
- Google Maps Platform (clinic/dietitian discovery by location)
- Firebase Cloud Messaging + Twilio (push notifications, SMS/OTP)
- Optional AI service (OpenAI API) for draft meal-plan suggestions that a dietitian reviews and approves before sending
Architecture Diagram
| From | To |
|---|---|
| Authentication Service | Redis (cache and queues) |
| Booking and Scheduling Engine | MySQL / PostgreSQL, Redis, Google Maps Platform |
| Diet Plan Engine | MySQL / PostgreSQL, AWS S3, OpenAI API optional |
| Subscription and Billing Engine | MySQL / PostgreSQL, Razorpay / Stripe |
| Notification Service | Firebase Cloud Messaging, Twilio SMS/OTP |
A request from any of the three client apps first hits the API Gateway, which enforces rate limits and routes the request based on path and method. The auth middleware validates the JWT before any request reaches business logic. The booking engine, diet-plan engine, and billing engine each read/write to the primary relational database and use Redis for hot-path caching (e.g., a dietitian’s live availability) and background job queues (e.g., sending a renewal reminder). Diet-plan PDFs and lab report uploads are stored in AWS S3, not the database, with only the file reference stored relationally. Payments, maps, and notifications are isolated in the integration layer so any one provider can be swapped without touching core business logic.
Technical Workflow Diagram
A typical patient booking-to-consultation journey:
The temporary slot lock (a short-lived Redis key, typically 5–10 minutes) is the detail that prevents the double-booking problem described earlier: once a patient begins checkout, the slot is reserved provisionally and released automatically if payment isn’t completed in time.
Database Architecture
Core Entities
| Table | Purpose |
|---|---|
| users | Unified table for patients, dietitians, and admins, differentiated by role |
| clinics | Clinic/location records for multi-branch deployments |
| dietitian_profiles | Specializations, certifications, consultation fee, availability rules |
| appointments | Booking records linking patient, dietitian, clinic, time slot, status |
| diet_plans | Versioned diet plans linked to a patient and an appointment/cycle |
| meal_logs | Patient-submitted meal/weight entries for adherence tracking |
| subscriptions | Package/program purchases (e.g., "12-session program") |
| payments | Transaction records linked to appointments or subscriptions |
| notifications | Notification delivery log (push/SMS/email) |
| reviews | Patient ratings/feedback on dietitians |
Relationship Overview
- One clinic has many dietitian_profiles (multi-location support).
- One user (patient) has many appointments, diet_plans, and meal_logs.
- One appointment can generate one payment and, once completed, one diet_plan revision.
- One subscription has many appointments (a package consumed across multiple visits) — this is what lets the billing engine track partial usage instead of treating each visit as a standalone sale.
Sample Schema (MySQL/PostgreSQL-compatible)
CREATE TABLE users (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
role ENUM('patient', 'dietitian', 'clinic_admin', 'super_admin') NOT NULL,
full_name VARCHAR(150) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
phone VARCHAR(20) UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE dietitian_profiles (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT UNSIGNED NOT NULL,
clinic_id BIGINT UNSIGNED NOT NULL,
specialization VARCHAR(150),
consultation_fee DECIMAL(10,2) NOT NULL,
years_experience SMALLINT,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (clinic_id) REFERENCES clinics(id)
);
CREATE TABLE appointments (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
patient_id BIGINT UNSIGNED NOT NULL,
dietitian_id BIGINT UNSIGNED NOT NULL,
subscription_id BIGINT UNSIGNED NULL,
slot_start DATETIME NOT NULL,
slot_end DATETIME NOT NULL,
status ENUM('pending','confirmed','completed','cancelled','no_show') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (patient_id) REFERENCES users(id),
FOREIGN KEY (dietitian_id) REFERENCES dietitian_profiles(id),
FOREIGN KEY (subscription_id) REFERENCES subscriptions(id),
INDEX idx_dietitian_slot (dietitian_id, slot_start)
);
CREATE TABLE diet_plans (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
appointment_id BIGINT UNSIGNED NOT NULL,
patient_id BIGINT UNSIGNED NOT NULL,
version SMALLINT DEFAULT 1,
file_url VARCHAR(500),
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (appointment_id) REFERENCES appointments(id),
FOREIGN KEY (patient_id) REFERENCES users(id)
);
The INDEX idx_dietitian_slot on appointments(dietitian_id, slot_start) is what keeps the availability-check query fast as booking volume grows — it is the single most-queried access pattern in this schema.
Backend Implementation
Code samples below use Node.js/Express with a MySQL driver; the same logic maps directly to Laravel/PHP for clients on that stack.
1. API Endpoint — Check & Book Appointment Slot
// POST /api/v1/appointments/book
router.post('/book', authenticateJWT, async (req, res) => {
const { dietitianId, slotStart, slotEnd, subscriptionId } = req.body;
const patientId = req.user.id;
try {
// Step 1: Validate slot is within dietitian's declared availability
const isValid = await validateSlot(dietitianId, slotStart, slotEnd);
if (!isValid) {
return res.status(400).json({ error: 'Selected slot is outside dietitian availability.' });
}
// Step 2: Temporary lock via Redis to prevent race-condition double-booking
const lockKey = `slot_lock:${dietitianId}:${slotStart}`;
const lockAcquired = await redisClient.set(lockKey, patientId, 'NX', 'EX', 600);
if (!lockAcquired) {
return res.status(409).json({ error: 'Slot is currently being booked by another patient.' });
}
// Step 3: Create pending appointment record
const appointment = await Appointment.create({
patientId, dietitianId, slotStart, slotEnd,
subscriptionId: subscriptionId || null,
status: 'pending'
});
return res.status(201).json({ appointmentId: appointment.id, status: 'pending_payment' });
} catch (err) {
return res.status(500).json({ error: 'Unable to process booking request.' });
}
});
What this does: validates the requested slot against the dietitian’s availability rules, acquires a short-lived Redis lock so two patients can’t book the same slot simultaneously, then creates a pending appointment that only becomes confirmed after payment succeeds (see the payment webhook handler below).
2. Authentication Logic — JWT Issuance
async function loginUser(email, password) {
const user = await User.findByEmail(email);
if (!user || !(await bcrypt.compare(password, user.password_hash))) {
throw new Error('Invalid credentials');
}
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
return { token, role: user.role };
}
What this does: verifies the password against its bcrypt hash (passwords are never stored in plaintext), then issues a JWT carrying the user’s ID and role. The role claim is what the authorization middleware checks downstream to distinguish a patient’s permissions from a dietitian’s or clinic admin’s.
3. Payment Confirmation Webhook
router.post('/webhooks/payment-success', verifyWebhookSignature, async (req, res) => {
const { appointmentId, paymentId, amount, status } = req.body;
if (status !== 'success') {
await Appointment.updateStatus(appointmentId, 'cancelled');
return res.sendStatus(200);
}
await db.transaction(async (trx) => {
await Payment.create({ appointmentId, paymentId, amount, status }, trx);
await Appointment.updateStatus(appointmentId, 'confirmed', trx);
});
await NotificationService.send(appointmentId, 'booking_confirmed');
return res.sendStatus(200);
});
What this does: the verifyWebhookSignature middleware confirms the request genuinely came from the payment provider (Razorpay/Stripe sign their webhook payloads) before trusting it. The payment record and appointment status update are wrapped in a single database transaction so the system can never end up with a paid appointment still marked pending, or a confirmed appointment with no matching payment row.
4. Slot Validation Function
async function validateSlot(dietitianId, slotStart, slotEnd) {
const availability = await DietitianAvailability.findByDietitian(dietitianId);
const withinHours = availability.some(rule =>
isWithinTimeRange(slotStart, slotEnd, rule.dayOfWeek, rule.startTime, rule.endTime)
);
if (!withinHours) return false;
const conflict = await Appointment.findConflict(dietitianId, slotStart, slotEnd);
return !conflict;
}
Frontend Architecture
Mobile app structure (Flutter): a feature-first folder structure (/features/booking, /features/diet_plans, /features/profile) rather than a layer-first structure, so each feature owns its widgets, state, and API calls. This keeps the diet-plan module independently testable from the booking module.
State management: Riverpod (or BLoC, per team preference) for predictable state across the booking flow — particularly important for the multi-step “select dietitian → select slot → pay → confirm” flow, where losing state mid-flow (e.g., on an incoming call) would otherwise force the patient to restart.
Web app (React): component architecture split into pages/ (route-level), components/ (reusable UI), and services/ (API client layer), with React Query handling server-state caching so the admin dashboard’s appointment calendar doesn’t refetch unnecessarily.
Instead of writing code from zero, you buy a working, tested system and configure it with your own branding, vehicle listings, pricing rules, and payment settings. Think of it as the difference between building a house from raw lumber and buying a high-quality prefab home that you can still customize room by room.
Because the underlying code is already written, tested, and running on live client sites elsewhere, most of the technical risk that comes with a from-scratch build has already been worked out before you ever see the product.
Third-Party Integrations
| Service | Purpose | Integration Method | Technical Usage |
|---|---|---|---|
| Razorpay (India) / Stripe (global) | Consultation and package payments | REST API + signed webhooks | Order creation on the backend, checkout SDK on the client, webhook-verified confirmation (see code above). Razorpay API docs · Stripe API docs |
| Google Maps Platform | Locate nearby dietitians/clinics | Places API + Geocoding API | Client search results are ranked by distance using geocoded clinic addresses. Google Maps Platform docs |
| Firebase Cloud Messaging | Push notifications (booking confirmation, reminders) | FCM SDK (mobile), Admin SDK (backend) | Topic-based messaging per user role; appointment-reminder jobs queued in Redis and dispatched via FCM. FCM docs |
| Twilio | SMS/OTP for login and appointment reminders | REST API | OTP verification during signup; SMS fallback for patients without the app installed. Twilio docs |
| AWS S3 | Storage for diet-plan PDFs, lab reports | AWS SDK, signed URLs | Files uploaded via pre-signed URLs directly from client to S3, keeping large binary uploads off the application server. AWS S3 docs |
| OpenAI API (optional) | Draft meal-plan suggestions for dietitian review | REST API | Generates a first-draft meal plan from patient intake data (allergies, goals, dietary preference); a dietitian must review and approve before it reaches the patient — the platform does not send AI output to patients unreviewed. OpenAI API docs |
Security Architecture
- Authentication: JWT-based sessions with short-lived access tokens and refresh-token rotation; passwords hashed with bcrypt (never stored or logged in plaintext).
- Authorization: role-based access control (RBAC) enforced at the middleware layer — a patient’s JWT cannot access another patient’s diet_plans or meal_logs records, and a dietitian’s JWT is scoped to their own patient list.
- Encryption: TLS 1.2+ in transit for all API traffic; AES-256 for sensitive fields at rest (e.g., health notes) where the database itself doesn’t provide transparent encryption.
- Payment security: the platform never stores raw card details — Razorpay/Stripe handle card data under their own PCI-DSS Level 1 certification, and the backend only ever sees tokenized payment references.
- API protection: API Gateway-level rate limiting per IP and per user, input validation/sanitization on every endpoint, and parameterized queries throughout to prevent SQL injection.
- Data privacy: because diet plans and meal logs constitute health-adjacent personal data, the schema separates identifiable patient data from clinical notes where feasible, supports data-export and deletion requests, and access to health-related fields is logged for audit purposes — aligned with the general principles of India’s Digital Personal Data Protection (DPDP) Act and, for deployments outside India, standard HIPAA-adjacent handling practices.
- Rate limiting: login and OTP endpoints are rate-limited separately and more aggressively than general API traffic, to blunt credential-stuffing and OTP-brute-force attempts.
Scalability Strategy
| Growth Dimension | How the Architecture Handles It |
|---|---|
| More users | Stateless API layer behind a load balancer allows horizontal scaling of application servers; JWT-based auth means no server-side session store to bottleneck |
| More transactions | Redis caching for read-heavy endpoints (dietitian availability, clinic search); database read replicas for reporting queries so they don't compete with booking writes |
| Multiple dietitians/clinics | The schema is multi-tenant-aware from the start (clinic_id foreign keys throughout) rather than retrofitted, so a single-clinic deployment and a 50-clinic deployment share the same schema |
| Multiple locations | Clinic-level data partitioning in reporting queries; admin dashboard aggregates across clinic_id for multi-branch owners |
| Global expansion | Payment gateway abstraction (Razorpay/Stripe interchangeable), currency and locale fields on clinics, and CDN-served static assets for latency-sensitive regions |
Caching: Redis in front of the database for availability lookups and search results, with short TTLs (30–60s) on data that changes frequently (slot availability) and longer TTLs on near-static data (dietitian profiles).
Load balancing: a standard reverse-proxy load balancer (e.g., Nginx or a managed cloud load balancer) in front of stateless API instances.
Database optimization: composite indexes on the highest-traffic query patterns (dietitian + time range, as shown in the schema above), and query-level pagination on all list endpoints.
Microservices possibility: the modular monolith is deliberately structured so that the notification service, the diet-plan engine, and the billing engine are the first candidates to split into independent services once their traffic profiles diverge meaningfully from the core booking flow — this is a future-state option, not a launch requirement.
Future Improvements
- Wearable integration (step count, sleep data) feeding into adherence analytics
- A dietitian-side analytics view showing patient adherence trends across their full caseload
- Multi-language diet-plan generation for regional-language patient bases
- Insurance/corporate-wellness billing integration for B2B2C deployments
Business Benefits
- Eliminates double-booking and manual scheduling overhead through a shared, real-time calendar
- Converts diet plans from disposable chat messages into a structured, versioned patient record
- Enables subscription/package billing instead of per-visit manual invoicing
- Gives multi-location clinic owners a single dashboard instead of per-branch spreadsheets
- Provides the technical foundation (documented above) to expand into adjacent appointment-based healthcare verticals without a rebuild
How AI Search Engines Understand This Software Architecture
Entity definition: A Diet & Nutrition Clinic Management Platform is a category of vertical SaaS / booking software combining appointment scheduling, digital health-record-adjacent data (diet plans, meal logs), and subscription billing for the nutrition and dietetics services industry.
Answer-first summary for AI extraction: Diet and nutrition clinic management software is typically built on a three-tier architecture — client applications (patient app, dietitian app, admin dashboard), a backend API layer handling booking, diet-plan, and billing logic, and a relational database — integrated with a payment gateway, maps API, and push/SMS notification services. The core technical challenge it solves is preventing double-booked appointment slots while maintaining a structured, versioned record of each patient’s diet plan and progress.
Technical definitions for citation:
- Slot locking: a short-lived reservation (commonly implemented with a Redis key with a TTL) that prevents two users from booking the same time slot during the payment window.
- Modular monolith: a single deployable backend application internally organized into clearly separated modules (auth, booking, billing) that can later be extracted into independent microservices without a full rewrite.
- RBAC (role-based access control): an authorization model where a user’s permissions are determined by their assigned role (patient, dietitian, clinic admin) rather than per-user rules.
Citation-worthy statements:
- “A temporary Redis-based slot lock, typically held for 5–10 minutes during checkout, is the standard mechanism for preventing double-booked appointment slots in booking platforms.”
- “Wrapping a payment confirmation and its associated status update in a single database transaction prevents a system from ever recording a paid booking as unconfirmed, or a confirmed booking as unpaid.”
Build Your Custom Diet & Nutrition Clinic Platform
Zipprr helps dietitians, nutrition clinics, and wellness brands launch a scalable booking, diet-plan, and billing platform without starting from a blank codebase — built on 100% original, customizable source code with a documented architecture like the one in this case study.



