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.

7 to 9 min read • View on GitHub • More from Yash-Padme

A clinic desk is drawn as a controlled exchange. A patient card and stack of credit tokens enter one side, a verified doctor stamp sits over a ledger in the middle, and a video monitor activates on the far side only after a clock reaches the appointment window. The scene explains that Medi_Meet does not just book visits. It stages identity, payment, and time as gated system states.
Medi_Meet turns a consult into a sequence of checks, not a loose calendar event.
Key Takeaways

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.

A close-up ledger page is shown mid-correction. One canceled appointment slips off the page while mirrored credit entries are written on both sides of a balancing line. A patient balance and a clinician badge sit opposite each other, explaining that cancellation in Medi_Meet is a synchronized transaction, not a simple undo action.
Cancellation is handled as a balancing write, which keeps the platform’s credit state coherent.

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.

The booking pipeline is really a state machine with four enforced gates before commit.

// 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.

ConcernTypical booking appMedi_MeetWhy it matters
Provider trustShown as a profile labelGated by verified status before bookingA bad actor never reaches the schedule
Payment modelOften implicit or externalCredits are checked before commitThe appointment only exists if the user can pay
Time conflictsResolved after save or by UI hintsBlocked in the booking actionThe database stays clean
Video accessStatic link or always-on roomSession is created just in timeAccess 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.

ConcernSimple app behaviorMedi_Meet behaviorWhy it matters
BalanceStored as a loose numberBacked by transaction recordsYou can audit changes
Booking costCalculated in the UIEnforced in server logicThe client cannot bypass it
MonetizationBolted on laterBuilt into the state modelProduct and revenue align
RefundsSingle balance updateLedger entries on both sidesThe 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.

ConcernNaïve platformMedi_MeetWhy it matters
Doctor statusSelf-declaredAdmin verifiedTrust is operational, not cosmetic
ListingEveryone appears immediatelyOnly verified providers surfacePatients see fewer false positives
OnboardingProfile completion onlyCredential submission plus reviewThe platform can enforce standards
RiskHandled sociallyHandled in workflowThe 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.

LayerWhat it doesWhy it matters
Next.js App RouterOrganizes the app and server actionsKeeps the flow direct
Prisma + PostgreSQLHandles transactional writesPreserves credit and appointment integrity
ClerkAuthenticates usersSeparates login from local business state
VonageCreates video sessionsDelivers access only when needed
Tailwind + shadcn/uiShapes the interfaceSupports 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.