Medical Toxicology Platform
The multi-product platform of a US medical toxicology company: nine independently deployed Django services and seven frontends behind one shared identity — the public site, the editorial CMS, the account and wallet hub, the clinical product, a Q&A community, and the payment, messaging and support backends.
Overview
The multi-product platform of a US medical toxicology company: nine independently deployed Django services and seven frontends behind one shared identity — the public site, the editorial CMS, the account and wallet hub, the clinical product, a Q&A community, and the payment, messaging and support backends.
Problem
The company offering had grown into fourteen separately deployed products, each with its own login, database, Redis, and subdomain. A clinician who signed up for one had no account in the next, editorial staff had no shared content pipeline, and five of the products were thin surfaces over the same clinical logic. What the business needed was not another service — it was one identity, one billing surface, and a single home for each capability.
Solution
Rebuilt the estate around consolidation rather than expansion. Identity was centralized into two services — Authentication owning credentials, OTP, 2FA and OAuth, and CoreLogic owning profile, wallet and product entitlements — with every other product keeping only a user mirror keyed by a shared corelogic_id. Five standalone products were folded into ToxLumen: transcription became its clinical case domain, the training simulator became its training domain, the antidote database became a knowledge section, and seven separate calculators collapsed into one tool registry. Payments were extracted into a dedicated Billing Service that is now the ecosystem single source of truth for money.
Architecture
Nine independent Django + DRF backends — Authentication, CoreLogic, ToxLumen, CMS, Landing, Community, Billing, CommCenter and Support — each with its own git repository, PostgreSQL database, Redis instance and api.<service>.medicaltoxic.com subdomain, together exposing roughly 658 routes. Seven frontends consume them: five React 19 + Vite SPAs and two Next.js applications. Sessions travel as HttpOnly JWT cookies scoped to the parent domain and signed HS256 with a shared secret, so any service — and a future edge gateway — can verify a token locally without a network hop to the auth service. Background work runs on Celery in the older services and Huey in the newer ones; media sits on S3 behind CloudFront; each service ships as its own Docker Compose stack with nginx serving the built frontend. Service-to-service calls carry an internal API key, and the Billing Service reports results back through a signed-HMAC outbox delivered by a worker rather than through synchronous callbacks from webhook handling.
Challenges
Retiring five products without breaking the four that remained: each removal left dead enum values, dead environment variables, dead Telegram channels and dead subdomains scattered across the survivors, so consolidation meant a full inventory of cross-service references rather than deleting a repository.
Holding one session across nine independently deployed services with no shared database and no common reverse proxy — an HttpOnly JWT on the parent domain with local HS256 verification, which only works if every service verifies identically, and an audit found that they did not.
Roughly nineteen proxy endpoints — logout, profile, token renewal, account creation — duplicated across five backends, each re-implementing what an edge layer should own.
Making payments a cross-cutting service rather than a per-product feature, with invariants that hold no matter which product initiates a charge: the wallet balance never moves without a ledger row, and no client service is ever called synchronously from webhook handling.
Outcomes
Fourteen separately deployed products consolidated into nine services and seven frontends under one identity and one billing surface, serving real medical clients in production.
Every backend in the estate architected and written solo — roughly 5,000 commits across the service repositories — while the team worked on the frontends.
Five products retired into ToxLumen by porting their proven implementations rather than rewriting them, with seven standalone calculators absorbed into a single tool registry.
A verified architecture audit of the whole estate — identity model, 658-route endpoint inventory, duplicated surfaces and security debt — written as the specification for a Go edge gateway rather than as a wish list.
Lessons Learned
Consolidation costs more than expansion. Adding a service costs a repository; removing one costs an audit of every reference the rest of the estate still holds to it.
A shared-secret JWT on a parent domain buys real architectural freedom, but only while every service verifies it the same way — inconsistent verification is worse than no centralization at all.
Duplication across services is a signal, not a defect to patch in place: nineteen copies of the same proxy endpoint made the case for a gateway more convincingly than any design document could.
Frontend work parallelizes across a team; service boundaries do not. Owning every backend contract personally is what kept them coherent enough to consolidate.
AI-Assisted Engineering
The platform rebuild — every one of the nine backend services, and the cross-service architecture audit behind the consolidation — was done solo with Claude Code, while the team worked on the frontends. Each repository carries its own CLAUDE.md and committed rules directory, so the same layered Django pattern, commit discipline and quality gates apply everywhere regardless of which service is open.
A CLAUDE.md per service stating what it owns, what it must never do, and the invariants that may not be broken — the Billing Service, for instance, pins wallet accounting, the provider list and the HMAC scheme as hard invariants rather than as guidance.
The same layered Django rule — views → serializers → services/selectors, one file per resource per layer — committed into every repository, so nine services stay structurally identical and a change in one reads like a change in any other.
Commit rules enforced through a shared skill rather than remembered per session: one concern per commit, never mixing added, modified and deleted files, and no AI attribution anywhere in the history.
Cross-service architecture done as written discovery documents first — the gateway audit inventoried every route, identity flow and duplicated endpoint across nine services before any gateway code was proposed.
Post-task quality checks (ruff, black, tests) as a binding rule in every repository, so no change is finished until the service it touched is clean.



