RatedDocs
A multi-portal dental marketplace where patients compare verified dentists, book live consultations, and pay through escrow — while dentists complete a three-phase verification and admins run the trust layer.
- >Three-phase dentist verification with admin audit, suspend, and soft-delete
- >LiveKit consultations with Socket.IO signaling and a treatment-plan → booking pipeline
- >Stripe Connect escrow, platform fees, and RDS IAM + S3 production infra

Project Vision & Meaning
RatedDocs exists because cross-border dental care is still sold through WhatsApp threads, unverified clinic lists, and opaque quotes. Patients cannot compare licensed dentists or know what they will pay; dentists cannot prove credentials at scale. The platform is a single product with three surfaces — a public directory for patients, a verification and practice workspace for dentists, and an operations console for admins — so discovery, trust, consultation, and payment live in one system instead of a stack of agencies.
Real-World Problems Solved
Patients search verified dentists with transparent procedure pricing, claim or book a clinic, and join a live consultation. Dentists complete license, operations, and clinic verification before they appear in the directory. After a consult, treatment plans convert into escrow bookings with Stripe Connect payouts and a configurable platform fee. Admins run verification queues, anti-collusion review, and user lifecycle controls (edit, suspend, soft-delete) with an audit log — the operational layer a marketplace needs before it can take money.
Challenges & Solutions
Session Auth Across Two Subdomains and Two Auth Systems
Problem Context:The product serves mvp.rateddocs.com (Next.js) and api.mvp.rateddocs.com (Express) with cookie credentials. Auth is dual-path: Better Auth sessions for the identity layer and custom JWT access/refresh cookies for API guards. A naive single-cookie setup broke on subdomain boundaries; a JWT-only setup lost Better Auth's Google and session store; calling the API from Edge middleware with no fallback left dashboards blank when the API blipped.
Configured cross-subdomain cookies on .mvp.rateddocs.com, mounted Better Auth at /api/auth/*, and wrote an Express guard that tries the access-token cookie (or Bearer) first, then the Better Auth session. Edge middleware checks GET /auth/current-user-session with forwarded cookies and falls back to a local JWT decode only if the API is unreachable. Role and account-status checks (SUSPENDED / DELETED) run on every protected route so a revoked dentist cannot keep a live session.
Consultation to Escrow Without Losing the Booking State Machine
Problem Context:A dental booking is not a calendar slot. Intake becomes a consultation, the consult becomes a treatment plan, the plan becomes a paid booking, and money should not release until arrival/payment rules say so. Dropping this into a single 'appointments' table created illegal state jumps (paid before consult, payout before arrival) and made Stripe Connect the source of truth instead of the application.
Modeled the lifecycle in Prisma as ConsultationIntake → Consultation → TreatmentPlan → TreatmentBooking with explicit status machines. LiveKit rooms and Socket.IO handle the call; Stripe Checkout and Connect webhooks only advance payment codes. Platform fee is a system setting, not a hardcoded constant. Arrival verification is blocked until the booking is actually due, so dentists cannot mark a patient arrived early to trigger payout.
Trust Queue: Verification, Collusion, and Reversible Admin Actions
Problem Context:A directory that lists anyone who signs up is a lead-gen site, not a marketplace. Dentists needed a multi-step credential review; admins needed to edit, suspend, or remove accounts without destroying forensic history; and review fraud (dentists and patients colluding) had to be visible without blocking the whole queue.
Split dentist onboarding into LICENSE, OPERATIONS, and CLINIC verification requests with an admin queue. Admin mutations write AdminAuditLog rows. Status changes and soft-deletes are dedicated endpoints so a suspended user is rejected at the auth middleware, not hidden in the UI only. Anti-collusion flags sit on directory reviews so ops can inspect patterns before a rating ships to the public listing.
