TherapyCRM

Release notes

New features, improvements and fixes in each TherapyCRM release.

v0.2.52 ·

Production PDF Generation Fix and Revert-to-Lead Feature

Promotes the production Docker image fix that installs Chromium so PDF exports work reliably on production, and adds a Revert to Lead control on the client detail page so staff can move a client back to the leads pipeline when they were converted in error.

New features

  • Client detail page now has a Revert to Lead button between Edit and Delete that flips status to the practice's default lead status, clears conversion_date, and navigates to the leads view; pre-emptively disabled when treatment plans exist with a tooltip explaining why

Improvements

  • Production Dockerfile now installs Chromium so the server-side PDF generator has a working browser binary in containerized deployments
  • Revert-to-lead server endpoint is practice-scoped and enforces that no treatment plans exist for the client; returns a clear 409 conflict when plans are present

Bug fixes

  • Fixed PDF export failing on production deployments because Chromium was not installed in the runtime Docker image

v0.2.51 ·

Scheduler, Document, and PDF Generation Hotfixes

Day-3 follow-up to v0.2.50 resolving user-visible bugs across the scheduler, document viewer/creator/editor, PDF export, and staff management. Hardens scheduler hour math, fixes wrapped API payload regressions in the document module, restores PDF generation on Windows, corrects PDF page margins and heading orphan handling, and replaces the soft-deactivate staff delete with a real cascade-aware hard delete.

Improvements

  • Schedule detail page now coerces staff ids to strings when filtering schedules, availability, leaves, and appointments so utilization stops sticking at 0% when /api/staff returns string ids while everything else returns numeric ids from Drizzle.
  • Schedule detail capacity column renamed from 'Available Hours' to 'Capacity Hours' and a new 'Remaining Hours' column was added so a fully-booked therapist no longer reads as '5 of 5' available.
  • Calendar conflict block coloring now reflects actual hard vs soft conflict severity (red for hard, yellow for soft) — before, any conflictWarning made the block red even when the Hard Conflicts badge was 0.
  • Client intake form now lists the specific missing fields blocking submission in the toast instead of the generic 'please complete all required fields'.
  • New seedable scheduler test fixture (5 therapists with varied availability shapes, 8 clients, 8 treatment plans hitting capacity bottleneck, rotation, oversubscription, and low remaining hours axes). All rows are tagged so cleanup runs as a single query.

Bug fixes

  • Scheduler hour math switched from calendar-day approximation (calendarDays / 7) to exact day-of-week occurrence counts. A 23-weekday window now reads as exactly 23/5 = 4.6 business weeks instead of ~4.57, eliminating the off-by-one '182.9 expected 184' reported by users. Treatment-plan demand uses hoursRemaining as the authoritative figure when set, so a plan with 10 hours authorized no longer displays as 9.6 because the period spans 24 weekdays.
  • Document viewer, document view, and document edit pages now defensively unwrap the wrapped /api/documents/:id envelope ({success, data: {...}}). Previously these pages crashed with 'response.document is undefined' after the standard response wrapper was rolled out.
  • Document creator dropped its older response fallback in favor of main's unwrapApiArray helper so list payloads are handled consistently across the documents module.
  • PDF export on Windows: removed --single-process and --no-zygote from the Puppeteer launch args. Those Linux-container-only flags crash Chromium on Windows with 'Protocol error: Connection closed', so every PDF download was failing on Windows servers. The browser-print fallbacks in document-view and document-viewer that silently printed the entire React webpage when the server-side PDF failed have also been removed.
  • PDF page margins: removed the hard-coded @page { margin: 20mm } from the inline print CSS. That CSS was overriding the page.pdf() margin object, so the 35mm/30mm margins set when header/footer are enabled were silently ignored by Chrome and the multi-line practice header bled into the body content on subsequent pages. The page.pdf() margin option is now the single source of truth.
  • PDF heading orphans: added break-after: avoid / page-break-after: avoid and break-inside: avoid on h1-h6 so section headings stop appearing orphaned at the bottom of a page while their body text wraps to the next page. orphans: 3 / widows: 3 on <p> prevents paragraphs from leaving 1-2 stray lines stranded across page breaks.
  • Staff delete is now a real hard delete with cascade cleanup, replacing the prior soft-deactivate. Schedules, availability, leaves, certifications, and appointment-drafts cascade out; treatment plans and client assignments have their therapist_id nulled (records survive). Real appointments still block delete with a 409 since their therapist_id is NOT NULL.

v0.2.50 ·

Spreadsheet-Style Document Forms and Template-Driven Analytics Dashboards

Replaces the stacked-card editor for repeating document fields with a compact, spreadsheet-style table that scales to many rows and many sub-fields. Adds a generic, template-driven layer of UX hints (tooltips, suggestion chips, autoIncrement, smart row defaults, column widths, max-line caps) so any document type benefits without code changes per template. Introduces a per-template dashboard config (charts, KPIs, tables) validated server-side against the template fields, with a generic Recharts renderer that powers 30 analytics dashboards across all clinical templates.

New features

  • Repeating document fields (DTT trials, ABA Programs Worked, Family Meeting agenda items, etc.) now render as a compact spreadsheet-style table instead of stacked cards. Header toolbar adds rows in batches (Add row / +5 / +10), pastes tabular data from Excel or Sheets in TSV / CSV format, and per-cell hover actions copy from the row above or apply a value to all rows below.
  • Every active document template now ships with curated tooltips and one-click suggestion chips on its text and textarea fields. Tooltips render as an info icon next to every form label and column header, and the Suggestions popover lets a clinician insert canned phrases (click to replace, shift-click to append) — covering all 43 default templates: DTT, ABA Therapy Session Note, Speech Therapy Session Note, OT Session Note, Progress Report, Discharge Summary, Verbal Behavior Milestones Tracker, Learning Barriers Checklist, Reinforcer Assessment, ABC Data Collection Form, Frequency / Duration / Interval Recording, BIP Implementation Data, Self-Monitoring Form, Daily Behavior Report Card, Task Analysis Data Sheet, Parent Training Documentation, Family Meeting Notes, and the rest.
  • Smart defaults on new rows: auto-increment for trial numbers, default No on yes/no toggles, auto-cycle parent array fields into matching child fields (current_targets becomes the per-trial target_presented), and pull-forward stable text columns like therapist name from prior rows. Free-form prose fields (notes, comments, descriptions, observations, remarks, summary, narrative, discussion) auto-promote to multi-line textareas with a 3-line max height, and prose columns get a wider 320px minimum to keep notes readable.
  • New per-template Analytics Dashboards on every client. 30 dashboards now ship by default (DTT Performance, ABA Session, Verbal Behavior Milestones, Reinforcer Assessment, ABC Data, Frequency / Rate, Duration, Daily Behavior Report Card, Self-Monitoring, BIP Implementation, Parent Training, Speech Therapy, OT, Progress Report, and more), grouped by category (ABA Data, Behavioral Data, Communication, Parent Communication, Progress Tracking, Therapy, Skill Acquisition, Assessment, Meetings, Supervision).
  • Generic dashboard renderer powered by a Zod-validated config: line, bar, stacked bar, pie, KPI, and table chart primitives, each referencing template fields by dot-notation paths (including paths into repeating sub-fields like trials.percent_correct). Aggregations supported: sum, avg, min, max, count, first, last. Formats supported: percent, duration_minutes, duration_seconds, plain number.

Improvements

  • Every practice in the database now has the same canonical 43-template default library. The migration clones missing templates into each practice and deactivates non-canonical active templates so document creation menus stay consistent across tenants.
  • Suggestions popover is fully template-driven via field.suggestions arrays — practices that customize a template can append their own quick phrases without a code change. Same applies to field.tooltip / helpText / description for help text.
  • Notes / description / comment / observation / remarks / summary / narrative / discussion fields now auto-grow up to 3 lines in repeating tables (configurable per field via field.maxLines, field.minLines, and field.width) so long notes are readable without taking over the form.
  • Searchable Combobox now activates automatically for selects with eight or more options (e.g., Skill Domain on DTT, Barrier Name on Learning Barriers Checklist) and for resource-typeahead fields (Therapist, Assessor, Implementer, SLP/OT Name, Service Type, Client) with role and email metadata in the dropdown.
  • Documents API list now supports a templateId filter and a higher default limit so dashboards can pull a full session history per template, not just the most recent 20 documents.

Bug fixes

  • Fixed the document_templates Drizzle schema missing the dashboard jsonb column. The column was already in the database but the ORM did not select it, so dashboard configs were never returned by /api/templates and dashboards never rendered.
  • Fixed the development-preview and production-preview workflows where the Post Migration Plan to PR step embedded migration text into a JS template literal. Migration text containing backticks, ${...}, or other JS template-literal-sensitive characters crashed the github-script step with a SyntaxError. Migration summary and PR number are now passed through env vars and read with process.env so any future migration content is safe.
  • Migrations 104 and 105 originally raised when every practice did not end up with exactly 43 active templates / 30 dashboards. The strict validation has been replaced with a soft check that only fails when zero templates picked up the enriched metadata, plus an informational RAISE NOTICE listing how many practices are below the canonical count. Lets the migration succeed on environments that legitimately start with a subset of the canonical templates.

v0.2.49 ·

Document Form UX Overhaul and CI Reliability Hardening

Replaces the document creation and edit form with a smarter, type-aware renderer so every field in all 43 practice templates lands in the right widget instead of a plain text input. Adds a typed signature widget and proper boolean toggles, fixes several blockers in the Documents list (delete failing, view crash, modal crash), and ships a set of CI/CD fixes that unblock preview branch cleanup, Playwright tests, and App Engine deploys.

New features

  • Document forms now auto-detect resource fields by name and label so Therapist, Assessor, Observer, Implementer, SLP/OT Name, Interviewer, Person Reporting, Completed By, and similar fields render as a typeahead Combobox populated from /api/staff with role and email shown as metadata. Service Type fields pull from /api/therapy-types. The single Client picker pulls from /api/clients.
  • New signature field type renders a typed-name input with Sign and Clear buttons and stores both the signer name and an ISO timestamp on click, used by Daily Behavior Report Card and Self-Monitoring Form.
  • Boolean fields are now first-class and render as a Switch toggle, replacing the previous unsupported placeholder. Two-option Yes/No selects are auto-detected and rendered as a Switch as well, while still saving the original Yes or No string so HTML templates that interpolate {{field}} keep rendering correctly.
  • Long select option lists with eight or more options, including the 24-option barrier list on Learning Barriers Checklist, render as a searchable Combobox with live filtering instead of a flat dropdown.
  • New scheduled GitHub Actions workflow sweeps stale Neon preview branches every night, removing branches whose backing pull request has been closed or merged for at least 24 hours. Runs in dry-run mode on workflow_dispatch for safe verification before deletion.

Improvements

  • Practice Settings cards now show real counts for Templates, Documents, and Users. The shared fetch helper unwraps the standard {success, data} envelope so endpoints that return paginated or wrapped responses produce correct counts everywhere.
  • Neon preview branches are now created with a sanitized name (slashes and other unsafe characters replaced with dashes) and the cleanup steps resolve a branch by name to its id and delete by id, so preview branches no longer get stranded when a pull request head ref contains a slash.
  • Playwright Kubernetes test runs now pre-delete any leftover Job before applying the new manifest so a previous failed or cancelled run no longer blocks subsequent runs with the field is immutable error.
  • Document creator templates dropdown supports faster search across the practice template library.

Bug fixes

  • Fixed the Create Document modal crashing with clients.map is not a function. The /api/clients endpoint returns the {success, data: {data: [...]}} pagination envelope; the modal now unwraps it before iterating.
  • Fixed the document view page crashing with Cannot read properties of undefined (reading content) whenever any document was opened. The viewer now unwraps the response envelope before destructuring the document, template, client, and creator fields.
  • Fixed the Documents list delete button silently failing with Invalid document ID or user ID and showing the literal undefined as the document title in the confirmation dialog. The handler now reads the id and title through the nested document object that the API actually returns.
  • Fixed every App Engine deploy failing with INVALID_ARGUMENT: Liveness checks are not supported for App Engine Standard environment. The Flex-only readiness_check and liveness_check blocks are removed from all three workflows that build app.yaml inline (development-preview, production-preview, deploy-prod) so the dev preview, production preview, and production promote paths can deploy again.

v0.2.48 ·

Scheduling Readiness and Optimization Quality Release

Adds a pre-flight readiness check to the scheduling module so administrators can see and resolve data gaps before generating a schedule, replaces the legacy four-call validation flow with a single source of truth, and fixes several optimization-quality issues found during end-to-end testing of the scheduling workflows.

New features

  • Scheduling now runs a pre-flight readiness assessment before schedule generation, surfacing blocking, warning, and informational issues with capacity figures (required hours, available hours, shortfall, weeks) so practices can fix data gaps without trial-and-error generation runs
  • Create New Schedule has been converted to a modal dialog with Advanced Options for operating hours and weekend exclusion, keeping the schedules list visible while configuring a new run
  • Planning window is now capped at 28 days at both the client and server with a clear PLANNING_WINDOW_TOO_LONG check, preventing accidentally long optimization runs

Improvements

  • Schedule generation validation is now consolidated into a single readiness service replacing the legacy bundle of separate validation calls, reducing duplicate logic between the API and the UI
  • Generated appointment titles now include the client name and therapy code instead of generic Scheduled Session text, making schedule-detail and calendar views easier to scan
  • Schedule-detail page now renders unscheduled plans in the Issues tab and reports requiredHours, deliveredHours, and fulfillmentRate so optimization quality is visible at a glance

Bug fixes

  • Fixed therapist utilization showing as zero in the Utilization tab caused by an envelope unwrapping mismatch in the staff schedules query
  • Fixed per-therapist utilization rows reading 0/0/0% caused by string-versus-number id comparisons between staff and staff schedule records
  • Fixed schedule grid landing on the wrong week when the planning start time fell across a UTC and local-day boundary in eastern timezones
  • Fixed the calendar view appearing empty when the browser timezone differed from a previously hard-coded America/New_York default
  • Fixed the schedules list showing a stale state by removing the redundant Schedule Preview dialog now that readiness is the single point of truth

v0.2.47 ·

Build Pipeline Reliability Hotfix

Hotfix release that restores the production Docker build under linux/arm64 cross-compilation. The build now survives slow npm registry responses and long Vite compile times when buildx emulates arm64 on amd64 runners. No application-facing behavior changes ship in this release.

Improvements

  • Production Docker build is now resilient to slow npm registry responses under QEMU emulation by raising the npm fetch timeout, retry budget, and adding a BuildKit npm cache mount so dependency tarballs are reused across builds
  • Production build script honors a longer per-step timeout so the linux/arm64 frontend compile is no longer killed prematurely while the amd64 build path is unchanged
  • Build configuration replaces the deprecated npm ci --only=production flag with --omit=dev and removes a redundant cache cleanup step that the new cache mount makes unnecessary

Bug fixes

  • Fixed Build and Deploy to Kubernetes failures caused by ETIMEDOUT during npm ci while pulling tarballs under linux/arm64 QEMU emulation
  • Fixed Build and Deploy to Kubernetes failures caused by spawnSync ETIMEDOUT during the frontend Vite build when the hardcoded 5 minute per-step timeout was exceeded under linux/arm64 emulation