Overview

All components at a glance

Client
Next.js Pages Router
Browser — Consultation UI
Typed / dictated consultation form · MediaRecorder audio capture · SSE stream renderer · one-click translation picker
Next.js 16 (Pages Router) React 19 Clerk JS fetch-event-source
Auth & Billing — Clerk
Subscription Gate
Protect plan="premium_subscription" wraps the product page · JWT sent as Bearer token on every API call
PricingTableJWKS
POST /api/consultation · /api/transcribe · /api/translate — Bearer JWT
text/event-stream SSE, token-by-token
API Layer
FastAPI
Three streaming routes
Verifies Clerk JWT via JWKS on every route · consultation summary + patient letter · Whisper dictation · per-language translation
fastapi-clerk-authStreamingResponse
chat.completions.create(stream=True) / audio.transcriptions.create
Deployment
Vercel — fast iteration path
Serverless FastAPI function
Next.js runs server-rendered; a Python serverless function (rewritten via vercel.json so /api, /api/transcribe, /api/translate all resolve to one handler) implements all three routes with full parity to the AWS path.
Docker / AWS App Runner — always-on path
Single self-contained container
Next.js is exported to static files at image-build time and served from inside the same FastAPI process as the API routes — one container, one health check, min/max instances pinned to 1 to bound cost (~$5–10/month).
OpenAI API calls only — no database, no persistence
External
OpenAI API
Generation & Transcription
gpt-4o-mini for the consultation summary and per-language translation · whisper-1 for audio-to-text dictation
Request Lifecycle

One consultation submission — step by step with design rationale

User Action
Type or dictate a consultation note
Typed text and/or a recorded audio clip via MediaRecorder · Clerk session active
Optional: POST /api/transcribe
Whisper dictation
Recorded audio forwarded as multipart bytes to whisper-1 · returns plain-text transcript
Auth — Clerk JWT
Bearer token verified
Every route depends on ClerkHTTPBearer · sub claim identifies the requesting user
POST /api/consultation
Summary generation, streamed
gpt-4o-mini streams three sections: doctor's summary, next steps, patient email — token-by-token over SSE
Optional: POST /api/translate
Patient email translated
The patient-email section is re-streamed into any of 19 languages, generated natively rather than templated
Done
Nothing persisted
No database in the stack — note content lives only for the duration of the request
Why both input paths? Clinicians either type quickly between patients or dictate on the move. Both feed the same downstream summary pipeline, so dictation is not a second product — it's an alternate input into one flow.
Whisper, not a bundled STT model whisper-1 accepts most common recording formats (webm, mp4, m4a) directly — no client-side re-encoding needed before upload.
Shared pipeline Once transcribed, the text is indistinguishable from typed input — the summary endpoint doesn't know or care which path produced it.
Subscription-gated, not just authenticated This is a billable SaaS product from day one — Clerk gates the product page by plan (premium_subscription) in addition to verifying identity on every API call.
The wait-in-silence problem A full clinical summary takes several seconds to generate. Returning it as one blocking JSON response means a blank screen the whole time.
Token-by-token SSE Every route streams its output as it's generated. The user sees the summary build up live — the app feels responsive even though total generation time hasn't changed.
Native translation, not templating The patient email is re-generated per language rather than run through a template-and-swap step, so clinical tone holds up across languages with very different formal registers — from French and Mandarin to Farsi and Tagalog.
No persistence by design Note text goes to OpenAI for generation and nothing is written to a database — a deliberate scope boundary, not an oversight, ahead of any formal HIPAA compliance pass.
External & Infra

Models, cost tuning, and the two deployment targets

Models
OpenAI API
gpt-4o-mini — consultation summary and translation, both streamed
whisper-1 — audio dictation transcription
AWS App Runner
Cost-tuned always-on hosting
0.25 vCPU / 0.5GB, min = max = 1 instance
Estimated ~$5–10/month running cost
Cross-platform builds need --platform linux/amd64 explicitly on Apple Silicon
Auth & Billing
Clerk
JWT verified via JWKS on every backend route
Protect plan="premium_subscription" gates the product UI
Known limitation
Not HIPAA-hardened
Explicitly documented as a demonstration app, not a certified medical device
CORS on the AWS path is currently permissive (allow_origins=["*"]) — a planned hardening step
Decisions

Every architectural decision — problem and rationale

DecisionWhat the naive approach gets wrongWhy this solution is better
Two deployment topologies, one repo Picking only one target trades away either fast iteration (Vercel) or predictable always-on hosting (App Runner) Vercel serverless for day-to-day development speed; Dockerized App Runner for a traditional always-on deployment — both built from the same codebase, both with full feature parity.
AWS path collapses to one container Running Next.js as its own Node server alongside FastAPI means two processes, two health checks, more moving parts on a cost-capped instance Next.js is pre-built to static assets at image-build time and served directly from FastAPI — one process, one health check, simpler to reason about at 0.25 vCPU.
Token-by-token SSE on every route Returning one blocking JSON response after several seconds of generation reads as a frozen app Streaming keeps the app feeling responsive throughout generation, even though total time to a complete summary hasn't changed.
Native per-language translation Templating a translated patient letter risks losing the tone and formality appropriate to that language's clinical register Each translation is generated fresh in the target language, so tone holds up across languages as different as French, Mandarin, Farsi, and Tagalog.
No database, no persistence layer Storing clinical notes without a compliance pass first would be a real risk for a healthcare-adjacent product Note content is only ever in-flight to OpenAI for generation and never written to disk — a deliberate scope boundary ahead of any formal HIPAA hardening work.
App Runner sized to 1 instance, 0.25 vCPU Leaving autoscaling at defaults on a demo project risks surprise cost min = max = 1 instance pins the always-on deployment to a predictable, low, known monthly cost (~$5–10).
MediScribe — Solo Project Next.js · FastAPI · OpenAI · Whisper · Clerk · Docker · Vercel · AWS App Runner