Skip to content

Case study · hero · 2026-05 to present

Kintsu AI Consultation Tool

Running the Simple Cortex engagement, I designed an ephemeral AI consultation flow that maps a selfie to real treatments and moves a patient toward booking, without storing a photo or pretending to diagnose.

Role
Product and Design Lead, Simple Cortex engagement
Company
Kintsu Medical Aesthetics
Dates
2026-05 to present
Bucket
current venture

Shipped to production July 2026. Live at imagine.kintsuaesthetics.com (noindex pending attorney and Medical Director sign-off on BAA determination).

The Kintsu AI consultation result screen in a browser frame: a plain-language summary of what the AI noticed, an educational overlay marking approximate concern zones directly on the face, and a row of concern tabs: Dark spots / uneven tone, Acne / congestion, Texture / pores. A live-analysis badge reads Gemini 2.5 Pro.
Kintsu Medical Aesthetics · AI Consultation Tool · In productionA selfie becomes a plain-language reading: concern zones mapped on the face, then a tab per concern with a severity read, Fitzpatrick-aware education, a vetted service, and a product to ask about. This is the screen the whole tool exists to earn.

TL;DR

A selfie-based AI consultation only earns its place if it earns trust first. Running the Simple Cortex engagement for Kintsu, I designed an ephemeral flow that reads a photo, maps concerns to the real treatment catalog, and moves a patient toward booking. No stored photo, no database record, no login. It is ephemeral by architecture: the photo never touches disk, so there is nothing to leak. Shipped to production in July 2026. The proof is the architecture first, and the live system second.

The result step · anatomy of one concern

3 points

The Kintsu consultation result for one concern: the photo with the concern zone marked, a Dark spots / uneven tone read marked Moderate, a Fitzpatrick-aware explanation written for richer tones, and a Worth exploring service drawn from the practice catalog.
01 · Severity read

Moderate, set conservatively for deeper skin. The severity sits next to the concern, never framed as a diagnosis.

The result screen, annotated. Each structured part marked: a severity read, skin-tone-aware education, a catalog-guarded service, and a product note. None of it framed as a diagnosis.

The problem was not AI accuracy

Accuracy matters, but trust comes first.

The tool asks for a sensitive image: a person's face. The first design decision was not which model to use. It was whether this product deserved to keep the photo at all.

The answer was no. So the tool became ephemeral by architecture, not by policy. Take the image, analyze it, return useful guidance, map results to services the practice actually offers, then get out of the way. A privacy policy saying "we delete photos later" was not good enough. The product promise is stronger when there is no stored photo to delete. Useful enough to convert, restrained enough to trust.

The second constraint was clinical: the line between patient education and medical advice can blur quickly in a medspa context. A tool that casually overclaims, or one that treats a light skin tone as the default and applies the same confidence to darker skin, damages trust before the consultation starts. I designed around both risks from the first conversation.

What I did

  • Designed a selfie-based consultation flow with no persistent photo storage. The image travels in the request, passes through the model, and the result returns to the browser. No write to disk, no row in a table.
  • Mapped concerns to the actual treatment catalog rather than generic advice. The model can describe a concern. The recommendation has to come from what Kintsu actually offers, so the service catalog acts as a guardrail (see the decision beat below).
  • Created a plain-language result screen that educates without pretending to diagnose. The tool says what it notices and what people with similar concerns often explore. It does not say what condition a patient has.
  • Built guardrails into the system prompt itself: no diagnostic language, skin-tone-aware behavior required, recommendations limited to the vetted catalog. The system prompt is the design artifact.
  • Framed the tool as a conversion bridge to booking, not a replacement for clinical judgment. The booking handoff carries the patient's shortlist of concerns and services, never patient identifiers. The user gets a useful next step. The business gets a lead path. The clinician keeps authority.
  • Isolated the AI image simulation behind a feature flag. The useful consultation flow ships without waiting on the legally exposed feature to clear review.
  • Ported the API from Vercel serverless to a Hono Node server compiled with esbuild, deployed as a Docker container behind Coolify's Traefik on the Hostinger VPS. Auto-TLS, rightmost-XFF trust, and a noindex header ship as infra configuration, not application code.
  • Replaced the single-shot selfie with a 5-frame white-light capture protocol: ambient, full-flash, left-raking, right-raking, and top-band. Raking shadows are real geometry physics a screen can produce; that reasoning ruled out colored flashes (screens cannot fake UV or polarized physics). Consent v2 adds a photosensitivity warning and a single-photo opt-out path. A quality gate retries up to three times and surfaces the failure reason as visible text rather than a silent stop.
  • Hardened the server boundary: Cloudflare Turnstile wired fail-closed (the secret lives only on a managed siteverify Worker so the token is never pre-verified on the frontend), rate-limiter sweep and cap, intake enum validation to close prompt-injection, CSP, and a 413 pre-buffer. Dependencies brought to zero known vulnerabilities.
  • Wired Zenoti lead integration: email-then-phone deduplication before guest create (fail-open, a duplicate row beats a lost lead), guest note attached with the correct field contract (field name, note type enum, and center as a nested object, not a flat ID). A code-review pass caught HTML injection in the front-desk notification email and added escaping plus an injection test before deploy.

The decision beat: I made storage impossible, not just discouraged. The reflexive engineering path was to write each analysis to a row so we could debug it later, backed by a privacy policy promising to delete photos on a schedule. I ruled that out before it was built. A policy can be reversed, breached, or quietly ignored. The stronger promise is architectural: if the photo is never written to disk or a table, there is no stored photo to leak, subpoena, or forget to delete. So the flow was ephemeral by architecture from the start. The cost is real: I gave up server-side debugging of individual analyses, which makes some failures harder to reproduce. I took that trade because on a tool handling faces, "we cannot leak what we never kept" is worth more than convenient logs.

Wizard · Five Steps · Nothing Stored

1LANDINGValue prop + ephemeralnotice. No login.2INTAKEAge range + concernpills. ~10 seconds.3CONSENT + UPLOADUpload locked untilconsent checked. Gateenforced in UI +server.4AI ANALYSISVision model reads thephoto. Photo clearedon advance.5RESULTS -> BOOKINGRecommendations +Zenoti redirect(?src=ai-tool).EPHEMERAL: NO DATABASE, NO PHOTO STORAGE
The consultation flow: no login, nothing persisted. The consent gate is enforced in the UI and again server-side; the photo is cleared the moment the user advances.

What changed

The tool shipped to production in July 2026. What changed is both the shape of the product and what the real deployment surfaced.

  • The design moved from a risky AI novelty to a bounded experience: capture, analyze, return, clear. There is no persistence layer for the photo, so the riskiest failure mode is designed out rather than mitigated after the fact.
  • The recommendation surface is closed, not open. Instead of trusting the model to name a treatment, the catalog guard checks every recommended service against the live catalog and drops anything the practice does not offer, before the response leaves the server. That is a check I can point to, not a claim to take on faith.
  • Darker skin tones are treated as a first-class case in the system prompt, not covered by a disclaimer after the fact.
  • The booking handoff carries the patient's shortlist of concerns and services, never patient identifiers.
  • The AI image simulation stays behind a feature flag until legal and clinical review clear it, so the useful flow ships without waiting on the exposed feature.
  • The production launch surfaced a latent model configuration bug: a prompt-parameter fix activated a previously-inert maxOutputTokens cap on Gemini 2.5 Pro, producing "No object generated" errors on live requests. The fix that improved the prompt broke the model in a way local tests could not catch, because the cap only triggers at inference scale. Production was pinned to GPT-4.1 while the token budget was diagnosed and raised. The enhanced error logging now captures finishReason and usage from the AI SDK error object so any future truncation is self-diagnosing.

Hypothesis (pre-patient-facing, pending BAA clearance): a trustworthy middle step between curiosity and booking should raise the rate at which visitors schedule a consultation, because they arrive with a concrete shortlist and a reason. I have not measured this. Treat it as the thing to test at launch, not a result.

Educational overlay · rendered client-side

3 points

A selfie with the Kintsu educational overlay drawn over it client-side: a soft-gold concern region across the cheeks, plain-language Left cheek and Right cheek labels, and a footer note reading that highlighted areas are an educational diagram, approximate and not a diagnosis.
01 · Concern zone

The region is tinted by severity in soft gold, not clinical red. The visual language stays calm and educational.

The overlay, drawn client-side over the local photo. Three layers marked: the severity-tinted concern zone, the plain-language label, and the honest framing. The overlay shows where the model looked without sending the photo away.

Ephemeral pipeline · nothing persisted

Your browserSELFIE CAPTUREDPOST bodyBASE64 IN REQUESTVision modelGEMINI 2.5 PROStructured JSONASSESSMENT + SLUGSBrowserRESULTS RENDERNO WRITE TO DISK · NO ROW IN A TABLEPERSISTENCE LAYER — NEVER WRITTENDatabaseDiskPhoto store
The image travels in the request body, passes through the model, and the result returns to the browser. No write to disk, no row in a table. Storage is impossible by architecture, not by policy.

Model Output

Server-Side Filter

Client

STATIC VETTED ALLOWLISTkintsu-glow-hydrafacialmedical-microneedlinglaser-resurfacingtopix-replenix-serumfilterObservations()GUARDS CONCERN + ZONE VOCABULARYfilterRecommendations()DROPS SLUGS NOT IN SERVICES.JSONkintsu-glow-hydrafacialmedical-microneedlingtopix-replenix-serumlaser-resurfacingDROPPEDNOT OFFERED
A server-side guard runs before any response leaves the function: every recommended service is checked against the live catalog, and any slug the practice does not offer is rejected rather than shown to the patient.

Phone-first · the primary surface

Three screens

Kintsu mobile consent and upload screen with the consent gate above the selfie upload, the app logo visible at the top.
01Capture & consent

Nothing leaves the device until you consent.

Kintsu mobile result screen showing what the AI noticed with the concern overlay drawn on the face, the app logo visible at the top.
02The reading

A reading, never a diagnosis.

Kintsu mobile booking handoff screen carrying the selected service shortlist, the app logo visible at the top.
03Booking handoff

The shortlist travels in the URL. The person does not.

Phone-first, because that is where selfies happen. The real screens: capture and consent, the reading, then the booking handoff, with the trust state stated at every step.

Reflection

1. Restraint was the product, not a constraint on it. The tool earns trust by refusing to keep the photo, refusing to diagnose, and refusing to recommend anything outside the real service model. Each refusal made the thing safer to launch and easier to trust. On a product handling faces, the strongest feature is often the data you choose not to hold.

2. Ephemeral by architecture cost me observability, and I would make the same call again. Because no analysis is written to a row, I cannot replay an individual bad result to see what the model saw. That is a real debugging tax. I accepted it because the alternative, a store I promise to delete, trades a hard guarantee for a soft one. The open question I am carrying into launch: can I add aggregate, non-identifying quality signals without reintroducing a photo store through the back door.

3. A fix that improves the prompt can break the model. The Gemini outage was caused by a parameter correction that activated a token cap only reachable at real inference scale. The lesson is not to distrust AI SDK configuration, but to treat model behavior in production as a separate test surface from local runs: instrument finishReason and usage from the start, because truncation at scale looks identical to a correct result until someone notices the output is empty.