Medi_Meet: The Telemedicine App That Treats Appointments Like Financial Transactions
A deep dive into the verified-provider gate, credit ledger, and just-in-time video provisioning that make this Next.js platform feel more like a controlled marketplace than a simple booking tool.
- Medi_Meet is built like a healthcare ledger, where booking, verification, credits, and refunds all have to stay in balance.
- The booking flow is interesting because it stacks four gates before a visit is allowed to exist: provider status, patient solvency, schedule conflict, and video session creation.
- Cancellation is the clearest proof of maturity because the system updates both sides of the transaction together instead of pretending a refund is just a status change.
- The stack is modern, but the real design win is the state model, not the UI layer.
Why Medi_Meet Feels More Like a Ledger Than a Booking App
Most telemedicine apps start with access. Medi_Meet starts with enforcement. A consultation only happens if the doctor is verified, the patient has enough credits, the slot is free, and the video session is created at the right moment.
That makes the project feel less like a directory of doctors and more like a controlled marketplace. Every appointment is a transaction with rules attached, and the code treats those rules as part of the product.
The interesting part is not that the app has booking, chat, or video. It is that the repository turns healthcare coordination into a state machine with financial consequences.
The Booking Flow Has Four Gates
The core booking action is the best place to understand the repo. In `bookAppointment`, the request is not written immediately. It moves through a sequence of checks that protect the system from bad state before any record is committed.
// Simplified shape of the booking flow
if (doctor.status !== 'VERIFIED') throw new Error('Doctor not verified');
if (patient.credits < APPOINTMENT_CREDIT_COST) throw new Error('Insufficient credits');
if (hasScheduleConflict(patientId, startTime, endTime)) throw new Error('Time overlap detected');
const videoSessionId = await createVideoSession();
await prisma.appointment.create({ data: { videoSessionId, status: 'SCHEDULED' } });
await revalidatePath('/appointments');
The order matters. Verification comes first because trust is a precondition. Solvency comes next because the app is not offering free intent. Conflict detection comes after that because a valid buyer still cannot occupy the same slot twice.
Only then does Medi_Meet provision the video session and write the appointment. That is the right move for a system that wants the record, the credits, and the video token to agree with each other.
| Concern | Typical booking app | Medi_Meet | Why it matters |
|---|---|---|---|
| Provider trust | Shown as a profile label | Gated by verified status before booking | A bad actor never reaches the schedule |
| Payment model | Often implicit or external | Credits are checked before commit | The appointment only exists if the user can pay |
| Time conflicts | Resolved after save or by UI hints | Blocked in the booking action | The database stays clean |
| Video access | Static link or always-on room | Session is created just in time | Access is narrower and easier to control |
Clerk Is Not the Identity Source of Truth
Medi_Meet uses Clerk for authentication, but it does not stop there. The app still creates a local user row and ties that user to its own business records.
That bridge matters because identity in a marketplace is never just login. The local database becomes the place where permissions, credits, and appointment history are attached to an authenticated person.
In other words, Clerk proves who someone is, but the PostgreSQL record determines what they can do inside Medi_Meet.
// Shape of the identity bridge
const clerkUser = await auth();
const localUser = await prisma.user.upsert({
where: { clerkId: clerkUser.id },
update: {},
create: { clerkId: clerkUser.id, credits: 0 }
});
await prisma.creditTransaction.create({
data: { userId: localUser.id, type: 'free_user', amount: 0 }
});
That last transaction is a small but revealing detail. New users are not just inserted. They are initialized into the system’s economic model from day one.
Credits Are the Product, Not a Side Effect
The repo’s credit system is not decorative wallet logic. It is the monetization engine. The `User` model tracks a balance, and `CreditTransaction` preserves every movement of value.
The hardcoded appointment cost makes the business rule explicit. A consultation consumes credits, and the system treats that cost as a first-class constraint instead of a hidden assumption.
That design also hints at a subscription model. If credits can be allocated by plan, then booking becomes the moment when membership turns into actual service delivery.
| Concern | Simple app behavior | Medi_Meet behavior | Why it matters |
|---|---|---|---|
| Balance | Stored as a loose number | Backed by transaction records | You can audit changes |
| Booking cost | Calculated in the UI | Enforced in server logic | The client cannot bypass it |
| Monetization | Bolted on later | Built into the state model | Product and revenue align |
| Refunds | Single balance update | Ledger entries on both sides | The books stay coherent |
This is why the app feels closer to an escrow system than a scheduler. Credits are not a byproduct of usage. They are the currency that makes usage possible.
Cancellation Is Where the Design Gets Serious
The strongest evidence of discipline is the cancellation flow. Instead of flipping one appointment status and moving on, the code uses a transaction that updates both sides of the ledger together.
That means the patient gets refunded, the doctor’s balance is adjusted, and the transaction log records the change in one atomic unit. If anything fails, the system does not end up with a half-refunded appointment and a broken balance sheet.
This is the difference between simple CRUD and business software. CRUD changes rows. Medi_Meet protects invariants.
await prisma.$transaction([
prisma.appointment.update({
where: { id: appointmentId },
data: { status: 'CANCELLED' }
}),
prisma.creditTransaction.create({ data: { userId: patientId, amount: 2, type: 'refund' } }),
prisma.creditTransaction.create({ data: { userId: doctorId, amount: -2, type: 'chargeback' } }),
prisma.user.update({ where: { id: patientId }, data: { credits: { increment: 2 } } }),
prisma.user.update({ where: { id: doctorId }, data: { credits: { decrement: 2 } })
]);
The exact implementation details matter less than the pattern. Cancellation is treated as balancing the books, not erasing history.
Verified Providers Are a Trust Boundary
Doctor onboarding is not open-ended. A provider submits credentials, an admin verifies them, and only then does the doctor become eligible for listings and bookings.
That is a real trust boundary, not a badge. It keeps the marketplace from confusing registration with legitimacy.
For telehealth, that distinction matters. Users are not just selecting a profile. They are choosing someone who can lawfully and operationally participate in care delivery.
| Concern | Naïve platform | Medi_Meet | Why it matters |
|---|---|---|---|
| Doctor status | Self-declared | Admin verified | Trust is operational, not cosmetic |
| Listing | Everyone appears immediately | Only verified providers surface | Patients see fewer false positives |
| Onboarding | Profile completion only | Credential submission plus review | The platform can enforce standards |
| Risk | Handled socially | Handled in workflow | The code backs the policy |
That approach is conservative in the best way. It slows the system where trust needs friction and speeds it up where automation makes sense.
The Stack Is Modern, But the Real Story Is the State Model
Medi_Meet uses a modern stack: Next.js 15, React 19, Prisma 6, PostgreSQL on Neon, Clerk, Vonage, Tailwind 4, and shadcn/ui. That is a competent lineup, but it is not the headline.
The headline is that the stack is arranged around state integrity. Server Actions remove a lot of API ceremony, Prisma transactions keep writes coherent, and `revalidatePath` helps the UI stay in sync after a commit.
That combination lets the app behave like a controlled marketplace without a lot of surface area. The architecture is lean because the business rules are doing the heavy lifting.
| Layer | What it does | Why it matters |
|---|---|---|
| Next.js App Router | Organizes the app and server actions | Keeps the flow direct |
| Prisma + PostgreSQL | Handles transactional writes | Preserves credit and appointment integrity |
| Clerk | Authenticates users | Separates login from local business state |
| Vonage | Creates video sessions | Delivers access only when needed |
| Tailwind + shadcn/ui | Shapes the interface | Supports the system, but does not define it |
What Medi_Meet Suggests About Telehealth Software
Medi_Meet is still a beta-style project, but its instincts are sharp. It understands that healthcare software needs more than booking screens. It needs boundaries, auditability, and a booking process that can survive real rules.
That is the broader lesson here. Telehealth gets more credible when trust, credits, and scheduling are modeled as data systems instead of bolted-on features.
If the front end is the visible part, the ledger is the product. Medi_Meet knows that, and the code follows through.




