---
type: plan
title: Design input for the django.md standard (P1 deliverable)
status: notes — write django.md from these
author: rian (with Claude) + professormediagroup session
created: 2026-08-25
---

# django.md — design input (capture before writing)

Not the standard itself — the agreed shape for it, so the Phase-1 session writes
it right the first time. Reached jointly with the `professormediagroup` session
(DFP). See [[rebuild-plan]] §2.3.

## The core contribution: auth becomes a THREE-WAY dispatch, not a rule with a hole

`coding.md` today says "no hand-rolled auth — identity comes from the server
gate." That's correct for gated internal apps but leaves a hole for ungated client
apps (both this project and DFP fall in it). django.md should reframe it as a
three-way dispatch so there is no hole to fall through:

1. **Gated internal app → id-auth**, as today. No app-owned auth.
2. **Ungated app where auth + admin dominate → Django.** `django.contrib.auth`
   (sessions, password reset, hashers, admin) IS the "not hand-rolled" answer —
   framework-maintained security primitives, not bespoke crypto. This project is
   case 2.
3. **Ungated app on FastAPI+React where the interactive UI earns the stack →
   app-native auth on well-audited primitives** (framework session middleware,
   argon2/bcrypt via maintained libs, no bespoke crypto). Name it explicitly as
   the **highest-scrutiny** path, with wording along the lines of: *"this is the
   costliest path — confirm the shape isn't really case 2 first."* DFP is case 3,
   deliberately parked (its agents.md marks it do-not-build-without-rian); when
   django.md lands, DFP's unresolved-auth section will point at it. **So django.md's
   language must cover case 3 explicitly, not just this project's case 2.**

## Dispatch precondition: hosting precedes stack

Put this ahead of the three-way choice. A **PHP-only host moots the whole menu**
(the Cloudways→Laravel forcing generalizes). Decide where it runs before choosing
the stack; only a host that can run Python/Node keeps cases 2 and 3 open.

## WP→app password migration belongs in django.md's auth section

The verifier chain (this project's, but reusable fleet-wide):
- phpass portable `$P$` / `$H$` (salted iterated MD5),
- WP 6.8+ **`$wp$` = bcrypt over base64(HMAC-SHA-384(password, "wp-sha384"))** —
  the HMAC-SHA-384 pre-step with that exact static key is REQUIRED; plain bcrypt
  over the password verifies nothing post-6.8. This was a live near-miss (the
  natural assumption is plain `$2y$`).
- vanilla `$2y$` bcrypt.
Registered in Django `PASSWORD_HASHERS`; Django rehashes to the default hasher on
first successful login. Fixture-test all formats before migration day.

**Fleet note (from DFP):** this exact chain is the migration path if any
WordPress-hosted sites (e.g. future competition/professor sites) ever move onto the
platform with their users — so django.md should present it as a reusable pattern,
not a one-off for this project.
