One Django Engine, Three Accredited Platforms
September 1, 2026 · 9 min read · Belal Nagy
Injaz, HC Holding and Mada Education look like three unrelated products. Different domains, different colors, different logos, different course catalogs. Under the surface they are the same Django and PostgreSQL engine, deployed three times. This article is about how that engine is put together, and why I would make the same call again.
The trap with client number two is copy-paste. The first LMS ships, a second client wants "the same thing but branded for us", and the fastest week of your life is the one where you fork the repo. Six months later every bug exists three times, every feature is implemented three times, and the forks have drifted so far apart that a security patch is an afternoon of careful diffing per client. I had seen that movie, so the suite was built engine-first from the start.
One codebase, three deployments
The engine is a single Django project. Each brand runs as its own deployment with its own PostgreSQL database, its own domain, its own media storage and its own environment configuration. Nothing is shared at runtime — no shared database with a tenant column, no cross-tenant queries to get wrong, no risk that one client's traffic spike or data mistake touches another client.
Everything brand-specific is configuration, not code: the theme tokens, the logo set, the payment credentials, the accreditation identifiers, the email sender. A new deployment is an environment file and a theme entry, not a fork. When I fix a bug or harden an endpoint, every platform gets the fix on its next deploy — one patch, three products.
Branding as data
The templates never mention a brand. They render CSS custom properties, logo slots and copy blocks that the deployment's theme configuration fills in. The discipline that matters day-to-day: any time a brand name or color is about to be typed into a template, it becomes a theme key instead. That rule is the entire multi-brand system; everything else is just enforcing it.
It pays off in odd places. Certificates, invoices and notification emails are all generated documents, and all of them carry brand identity. Because branding is data, the same certificate renderer produces an Injaz certificate and a Mada certificate — and a third brand would cost nothing but assets.
Accreditation is a module, not a feature
The hard requirements in this space are not CRUD — they are regulators. Saudi platforms integrate with NELC (the national e-learning center) and, for medical training, SCFHS accreditation flows: enrollment reporting, attendance evidence, completion records, certificate issuance in the shape the regulator expects.
Those integrations live behind their own module boundary in the engine, keyed by configuration. A brand that needs SCFHS turns it on; a brand that does not never loads it. When a regulator changes a field or an endpoint — and they do — the change lands once, in one module, and every accredited platform stays compliant together. This is the part of the architecture that has paid for itself most directly.
Payments, background work and the boring parts
Payments go through MyFatoorah with per-brand merchant credentials, so money flows to each client directly and refunds and reconciliation stay per-brand. Celery and Redis carry the background load: enrollment confirmations, certificate generation, regulator reporting jobs, scheduled reminders. Each deployment runs its own workers, which keeps a stuck queue on one platform from delaying another.
Database migrations are the operational cost of the engine model: every schema change runs against three production databases. The routine is unglamorous and strict — backwards-compatible migrations, deploy engine first, migrate each brand in sequence, verify. The discipline costs minutes per release and has kept three production platforms on one schema without an incident.
What it costs, honestly
The engine model is not free. Every feature request now has a second question attached: is this for one brand or for the engine? Per-brand feature flags exist and must be tested in both states. A change that would be a quick hack in a single-client codebase gets designed slightly more carefully, because it will run in three places. And the test surface is real: CI has to prove the engine against more than one configuration.
What it buys is leverage. Three accredited platforms are maintained with the effort of roughly one and a half. A compliance change ships everywhere at once. And selling platform number four is a conversation about branding and content, not about months of build time.
The takeaway
If a second client ever asks for "the same thing, but ours": do not fork. Extract the engine while there are only two consumers of it, make branding configuration instead of code, and put regulator integrations behind module boundaries from day one. The engine mindset is a habit more than an architecture — and it is far cheaper to adopt at platform two than at platform three.
Next article
Taking Over a Legacy Codebase Without Rewriting It