Changelog
Changelog
Section titled “Changelog”All notable changes to ClinicFlow are documented here.
Format: Keep a Changelog
[Unreleased]
Section titled “[Unreleased]”Security
Section titled “Security”- ES256 JWT — token signing algorithm migrated from HS256 to P-256 asymmetric (ES256). Public key registered with Supabase as a custom JWKS endpoint so the database can validate clinic claims directly in RLS policies without trusting the application layer.
- Full RLS overhaul — all exposed tables now have policies that check the signed
clinic_idJWT claim, live user/clinic active state, app role (admin/staff/system), and FK ownership of related rows.private.request_is_active(),private.request_is_admin(), andprivate.request_is_system()private functions centralize these checks. - Column-level privilege hardening — trigger-based
enforce_user_update_scopeprevents staff from escalating their own role or modifying protected columns. - Authorization boundary tightening —
clinics_updateRLS policy scoped to disallow cross-tenant mutations; staff self-edit guards added.
- Dark mode — system-preference aware with manual override toggle in the topbar. All surfaces use CSS custom property tokens (
--surface-*,--text-*). - Command palette (Cmd+K / Ctrl+K) — instant navigation to any dashboard page.
- Notification drawer — shows unread WhatsApp-booked appointments with a live badge.
- Onboarding checklist — guided setup flow for new clinics (WhatsApp, first doctor, first FAQ).
- Quick-peek popover — hover or tap any appointment in the calendar to see patient details without opening the full modal.
- Appointment reschedule flow — staff can move an appointment to a new date/time with a full availability re-check. Replaces the previous cancel-and-rebook workaround.
- Radix UI modal system — all 14 dashboard modals migrated to Radix Dialog. Eliminates the class of scroll-lock and backdrop bugs present in the manual overlay approach.
- OG image —
og:imagemeta tag with a branded preview card for social sharing. - Print stylesheet — calendar and appointment list render cleanly when printed or exported to PDF.
Changed
Section titled “Changed”- Shared-phone patient identity —
patientsunique constraint changed from(clinic_id, phone)to(clinic_id, phone, full_name). Families sharing one WhatsApp number now get separate patient records, one per name. The chatbot asks “¿A nombre de quién?” on shared phones and scopes the booking/lookup to the confirmed name. - Premium UI overhaul — design token system (
--brand,--surface-*,--text-*, spring easing, spotlight hover gradient), emerald rebrand (#00b96b), tighter radii (6–8px), component-level utility classes (.page-card,.cf-table,.pill,.modal-overlay,.cf-input). - Dental pages — full redesign with page-header component, pill badges for status, cf-table layout. Treatment Plans, Payments, and Recall Campaigns all updated.
- Mobile calendar week view broken layout (React Big Calendar override).
- Mobile calendar sticky gutter misalignment on scroll.
- Mobile calendar grid scroll isolation (only the grid scrolls, not the toolbar).
- Dark mode: dropdown text invisible, calendar event text clipped.
- Session handling:
sessionStoragekey inconsistency on logout. - Attendance job: used doctor ID instead of full name in daily summary.
- Post-polish regressions: z-index conflicts (command palette, notification drawer), sidebar tooltip crash on collapse, page-card spotlight invisible without stacking context.
Removed
Section titled “Removed”waitlisttable — deprecated; dropped in20260611_drop_deprecated_tables.sql.whatsapp_templatestable — deprecated; dropped in same migration.- Redundant DB indexes —
idx_users_clinic_idduplicate, redundant index oninvite_codes, redundant index onls_orders.
[1.0.0] — 2026-06-01
Section titled “[1.0.0] — 2026-06-01”- Profile picture upload — Users upload JPEG/PNG/WebP from the profile modal. Stored in Supabase Storage (
avatarsbucket, public, 3 MB limit, MIME validated server-side). URL written tousers.photo_url; displayed everywhere the initials avatar appears.POST /api/users/me/photo. - Email change — Self-service email update from profile modal with new/confirm accordion. Backend checks global uniqueness before writing.
migrate.jsrunner — Wrapsschema.sqlin a transaction, acceptsSUPABASE_DB_URL(falls back toDATABASE_URL). Schema is now fully idempotent./healthendpoint — Added alongside/healthzto match Railway health check config.
- Profile name persistence — Login response returned
fullName(camelCase) while all components readfull_name(snake_case). Name appeared blank after every fresh login. Fixed inauth.js. - Profile modal centering —
.desktop-topbarbackdrop-filter: blur(12px)created a new containing block forposition: fixeddescendants per CSS spec. Fixed viaReactDOM.createPortalintodocument.body. - WhatsApp rate limiter — Was silently a no-op: calling
JSON.parse()on an already-parsed object, swallowing the error. Also had a path check always-truthy after Express mount prefix stripping. Now readsreq.bodydirectly. - Doctor creation blocked —
createDoctorSchema .strict()rejectedphonefield sent by the frontend. Every create/edit returned 400. Addedphone: z.string().max(25).optional(). - Staff role constraint —
users.roleDB CHECK allowed('admin','receptionist')while code inserted'staff'. Staff creation failed silently. Migrated to('admin','staff'). - Reminder column mismatch — Schema had
reminder_2h_sent; code wrotereminder_1h_sent. Aligned toreminder_1h_sent. - Password minimum inconsistency — Backend
PATCH /mevalidated< 8chars; frontend and registration Zod require12. All aligned to 12. - DB schema reproducibility —
schema.sqlwas missing 4 tables and multiple columns. All DDL now idempotent (IF NOT EXISTS,DO/EXCEPTIONpolicies,CREATE OR REPLACE TRIGGER,ALTER TABLE ADD COLUMN IF NOT EXISTS). - RLS docs — Docs incorrectly claimed backend sets
app.clinic_idfor RLS. Code uses service-role client (bypasses RLS). Docs corrected to describe actual app-layer enforcement.
Security
Section titled “Security”- Production startup guard:
WHATSAPP_APP_SECRET+WHATSAPP_WEBHOOK_VERIFY_TOKENrequired whenNODE_ENV=production. - Tenant isolation: doctor lookups in
availability.jsandbookingFlow.jsnow scoped toclinicId. Chatbot booking aborts if doctor belongs to a different clinic. - Profile photo storage paths scoped to
req.user.userIdfrom signed JWT.
Changed
Section titled “Changed”- Profile modal:
createPortalcentering, 528px wide, gradient identity card header, email change accordion, mobile bottom sheet, 48px touch targets. ProfileAvataracceptsphotoUrlprop — renders<img objectFit:cover>when set, falls back to color initials.RegisterPagepassword minimum updated to 12 chars.
[0.9.0] — 2026-05-31
Section titled “[0.9.0] — 2026-05-31”- User profile section — Avatar dropdown in top-right corner (desktop + mobile). Initials-based avatar with deterministic color from name hash.
- Profile editing — Self-service name and password change via
PATCH /api/users/me. - Quick user switching — Clinic staff can switch sessions without full logout/login (Clínica/Forever Free plans). User list from
GET /api/users/switchable. - PWA forced update —
controllerchangelistener in SW registration; new deploys silently reload installed PWA instead of re-showing install prompt.
Changed
Section titled “Changed”- Sidebar footer user-info block removed; user identity now lives in profile dropdown.
[0.8.0] — 2026-05-31
Section titled “[0.8.0] — 2026-05-31”- Animated WhatsApp conversation in landing page hero section.
- ESLint configuration (
eslint.config.js) for frontend sonpm run lintruns cleanly.
- Accessibility pass (P0+P1): useDialog stabilization, trend query error logging, honest trend copy.
- Mobile horizontal overflow on Billing plans and Analytics charts.
- Unused
Heartimport removed from landing page.
[0.7.0] — 2026-05-30
Section titled “[0.7.0] — 2026-05-30”- Per-clinic AI context — Claude Haiku system prompt now injects clinic identity, doctor specialties, real working hours, and live availability slots. Prevents hallucinated appointment times.
- Anti-fabrication rules added to chatbot prompt.
- Contact info updated to clinicflow.lat channels (support, sales, info, billing).
[0.6.0] — 2026-05-29
Section titled “[0.6.0] — 2026-05-29”- WhatsApp self-signup onboarding — Clinics connect their own Meta Cloud API number from the Settings tab. Full OTP verification flow with self-heal for
verifying → activestate transitions. - Meta onboarding UI — WhatsApp tab in Settings (was previously orphaned).
Changed
Section titled “Changed”- WhatsApp migrated from Twilio to Meta Cloud API — Each clinic uses its own phone number directly through Meta Graph API. Twilio dependency removed entirely.
- Per-clinic send adapter routes messages through correct Meta credentials.
[0.5.0] — 2026-05-28
Section titled “[0.5.0] — 2026-05-28”- In-dashboard subscription upgrade — Billing page links to LemonSqueezy checkout per plan. Webhook handler processes
order_createdevents to upgrade clinic plan.
[0.4.0] — 2026-05-27
Section titled “[0.4.0] — 2026-05-27”- Conversational chatbot v2 (Haiku-driven) — Full Claude Haiku conversation engine replacing rule-based state machine. Handles booking, cancellation, and FAQ in natural language.
- Booking confirmation interactive card (WhatsApp buttons: Confirm / Edit / Cancel).
- Cancellation confirmation card.
- Session store (chat_sessions table) for stateful conversations.
- Concurrency lock — prevents duplicate bookings from double-tap.
- Chatbot hardening: availability check before confirm, durable menu, short-answer routing.
- Medium findings: history alternation, robust JSON parse, writer validation, serialization.
[0.3.0] — 2026-05-26
Section titled “[0.3.0] — 2026-05-26”- Test suite — 89 tests at launch, grown to 194. Covers auth, chatbot, WhatsApp, tenant isolation, subscription limits, encryption.
- Security hardening: auth, tenancy, payments, crypto (L1–L5, M1–M5 audit findings).
[0.2.0] — 2026-05-25
Section titled “[0.2.0] — 2026-05-25”- Patient CSV import/export (Pro+ plans).
- ICS calendar feeds — doctors get a shareable calendar URL for Google/Apple Calendar.
- Analytics dashboard (Pro+ plans) — completion rates, no-shows, busy hours by day/time.
- Superadmin panel — demo request triage, invite code management, clinic plan updates.
[0.1.0] — 2026-05-20
Section titled “[0.1.0] — 2026-05-20”- Initial launch: multi-tenant clinic SaaS.
- Appointment management (create, update status, list with filters).
- Doctor management with working hours, breaks, and vacations.
- Patient records (create, search, block).
- WhatsApp appointment notifications badge.
- Subscription plan enforcement (Basic / Pro / Clínica / Trial / Forever Free).
- JWT authentication with 8h expiry and subscription freshness checks.
- BullMQ appointment reminders (24h + 2h via WhatsApp).
- Daily agenda cron job (sent to staff every morning at 07:00 CST).
- FAQ system with keyword matching.
- PWA support with offline fallback page.