All Projects
Professional
Ongoing

ToxLumen

A case-first clinical toxicology intelligence platform built solo end to end: three applications, one unified Django backend, and an organization-scoped credit and billing model. Clinicians move from raw input — typed, recorded, or a live transcribed call — through AI-assisted analysis, guidance, and safety alerts to a finalized clinical note. AI assists; the clinician decides.

Overview

A case-first clinical toxicology intelligence platform built solo end to end: three applications, one unified Django backend, and an organization-scoped credit and billing model. Clinicians move from raw input — typed, recorded, or a live transcribed call — through AI-assisted analysis, guidance, and safety alerts to a finalized clinical note. AI assists; the clinician decides.

PythonDjangoDjango REST FrameworkPostgreSQLRedisHueyDjango ChannelsDockerDocker ComposeNginxOpenAI APIGroqDeepgramStripeFirebaseReact.jsTypeScriptViteTanStack QueryTanStack RouterZustandZodTailwindCSSVitestClaude Code

Problem

Medical Toxicology's capabilities had accumulated as separate production apps — MedSpeech for transcription, Simulation for training, ToxPubMed for evidence search, and a standalone app per calculator — each with its own identity, data model, and billing. None was organized around the unit that actually matters clinically: the case. Clinicians had no single surface where a consultation becomes structured facts, analysis, guidance, and documentation with an audit trail behind it.

Solution

Consolidated the estate into one product built around a single spine — Case → Analysis → Guidance → Note — with Training, Tools, and Knowledge as global areas serving that flow. The proven domains were ported rather than rewritten: a binding "migration law" makes the original MedSpeech and Simulation implementations the specification for ToxCase and Training. One unified Django backend and one React SPA serve customers; a separate superuser back-office is the single sanctioned exception. Payments and identity stay in external services, so the product owns clinical truth and nothing else.

Architecture

Ownership runs Organization → Workspace → ToxCase; billing, plans, seats and credits are organization-level only. The backend is one Django 5 + DRF service of sixteen apps under a strict layering rule — routes → views → serializers → services/selectors — where selectors own every read and services own every write inside a transaction. Every primary key is a UUIDv7 and no key ever reaches a client URL: organizations, workspaces and cases are addressed by system-issued public codes (ORG-…, WSP-…, CAS-2026-000184) resolved server-side. Background work runs on Huey; Django Channels is installed for exactly one surface — read-only supervision of a live call — with patient audio going browser → provider directly, never proxied or stored. Credits are product-scoped: one balance per (organization, product) over an append-only ledger, priced from measured provider usage — tokens against the model rate card, audio per started minute — never a flat per-stage constant. Identity lives in an external CoreLogic/Auth service (the product stores only a user mirror) and payments in an external Billing Service, whose results are applied idempotently through an event inbox. Three independent git repositories are coordinated by a meta repository holding the documentation, the binding engineering rules, and the agent configuration.

Challenges

  • Merging two independent production backends into one domain model without rewriting clinical logic that already worked — enforced as a binding rule that ported domains must be read from the source implementation, never reconstructed from documentation.

  • Credit accounting that cannot leak between products: one balance per (organization, product) over an append-only ledger, with the product argument carrying no default anywhere in the service, because a default would silently charge the wrong purse.

  • Two role systems layered on one another — organization Owner/Admin/Member above workspace Clinician/Reviewer/QA Reviewer/Viewer — where the Owner bypass opens clinical access without granting the right to drive a consultation someone else is conducting.

  • Adding real-time transcription without turning a request/response system into a streaming one: a single websocket surface for read-only supervision, with audio flowing from the browser straight to the provider so patient media never touches the platform.

Outcomes

  • Roughly 230k lines across three applications — 48 models, 275 API routes, sixteen backend domains — with ~1,500 backend tests and 200 frontend and dashboard test files, built solo.

  • Four separate production apps and a standalone app per calculator consolidated into one product with one identity, one billing surface, and one design system.

  • A documentation set verified against the code rather than written beside it — the endpoint map checked against Django's own URL table, every cited class name checked against the source.

  • A production-readiness audit that named the four deployment blockers explicitly, with file, line, and cost of the fix — found before the first real user rather than in production.

Lessons Learned

  • On a port, the source implementation is the specification. Reading the original code beats reasoning about it from a document every time — and a rule that says so is worth more than the intention to do it.

  • Money deserves no defaults. Making the product scope a required argument at every level of the credit service turned a whole class of silent mischarges into a compile-time question.

  • AI-assisted development scales only when the repository encodes its own law — a committed rules set turns a code generator into a contributor that respects layering, query discipline, and tests.

  • Documentation drifts unless it is re-read against the code on a schedule; the drift is always in the details that matter, like endpoint names and class names.

AI-Assisted Engineering

Claude Code

The entire platform was built solo with Claude Code as the primary engineering tool. Rather than prompting ad hoc, the repositories themselves encode the engineering contract: a CLAUDE.md per project, a committed rules directory, and custom skills for recurring workflows — so every AI-assisted change is held to the same architectural law a senior reviewer would apply.

  • A CLAUDE.md per repository acting as the binding architectural contract — layering, locked cross-project decisions, and scope that may not be re-litigated.

  • A committed .claude/rules/ set enforcing the Django layering pattern, query performance (every read fetches exactly what the client renders, narrowed in the query), testing, commits, and post-task checks.

  • A migration-sources rule pointing at the original MedSpeech and Simulation code, so ported domains are read from the source rather than reconstructed from memory.

  • Custom skills for repeatable work — design system, feature-based architecture, bug diagnosis, handoff, post-task checks — instead of re-explaining conventions in every session.

  • Every change ships its tests, and all three projects run their full suite before any task is reported done — never conditional on which one was edited.

Team

Sajjad Fani

Sajjad Fani

You

CTO & Software Architect & Software Engineer

Software Engineer

Professional
CTO & Software Architect & Software Engineer
July 2026 — Present