# Reference consumer profile — inthewords

> **Project:** Django web application (collaborative writing platform)
> **Status:** Second reference consumer (arrived 2026-05-05). First web-shape consumer; closed strategic-review Priority 1.
> **Profile last refreshed:** 2026-05-10

inthewords is a Django web app. It's the first consumer that's
NOT a desktop/CLI shape and the trigger for several
framework-aware standards carve-outs that landed in v0.18.0
(LG-* applies_to columns, CF-* per-kind compliance matrices,
HTTP-01 exception hierarchy).

Its shape biases toward:

- Request/response lifecycle (Django middleware + view dispatch)
- DRF (Django REST Framework) JSON responses
- pip-tools `requirements/*.{txt,lock}` dependency manifest (no
  `pyproject.toml`)
- Cloud-native logging (stdout-only, structured JSON, container
  log collector); no rotating-file sink, no GUI log viewer
- Single-tenant per-installation; multi-room/multi-user but not
  SaaS multi-tenancy

When the standards docs cite "the web/Django consumer", inthewords
is implied.

---

## Shape at a glance

| Concern | inthewords' shape |
|---|---|
| Manifest | **pip-tools** `requirements/{base,dev,prod}.{txt,lock}` |
| Layout | flat `apps/<name>/…` package tree; no `src/` |
| Entry point | Django `manage.py` |
| Identity | `bootstrap(setup_logging=False)` from a Django AppConfig.ready() |
| Logging | Django's `LOGGING` dictConfig + JSON formatter; stdout-only |
| Config | mgf-common `MgfSettings` + Django `settings/{base,dev,prod}.py` |
| Vault | not used (cloud-managed secrets via env vars + secret manager) |
| Errors | mgf-common `AppError` + HTTP-01 hierarchy → DRF exception handler |
| Subprocess | rare; `mgf.common.process.run_command` for one-shot maintenance commands |
| Cancellation | request-level only (Django's request lifecycle) |
| Multi-tenancy | per-installation single-tenant; rooms + memberships within |
| Web framework | Django + DRF |
| Tests | pytest + pytest-django; mypy strict; ruff; coverage ≥ 85% |

---

## Pattern-by-pattern evidence

### Configuration

`MgfSettings` is loaded at startup; Django's settings module reads
relevant values (e.g., logging level, OTel toggle, redaction list)
from the `MgfSettings` instance. The pip-tools layout means
mgf-common's `[tool.mgf]`-in-pyproject source doesn't fire;
everything is env-var-driven via `MGF_*` prefix.

CF-* (CONFIG-01) deliberately doesn't fit Django's `settings.py`
pattern. Documented non-adoption with carve-out in the
CONFIGURATION standard (per ASPIRE-02 v0.18.0).

### Logging

LG-06 (rotating-file sink mandate) doesn't fit cloud-native log
collection — there's no persistent disk, and Kubernetes/Docker
collectors expect stdout JSON. Resolved by `bootstrap(setup_logging=False)`
+ a Django `LOGGING` dictConfig that uses `mgf.common`'s JSON
formatter directly. Per LOG-01 carve-out.

LG-07 (GUI log viewer) is N/A; resolved by LOG-02 carve-out.

### Error handling

inthewords' `apps/core/exceptions.py` defines an `AppError`
subclass hierarchy (`NotFoundError`, `PermissionDeniedError`,
`ValidationError`, `ConflictError`, `ServiceUnavailableError`,
`RoomNotFoundError`, `RoomArchivedError`, `MessageNotFoundError`,
`AuthenticationRequiredError`, `MembershipRequiredError`).

Each carries an `http_status` class attribute. After v0.18.0's
HTTP-01 shipment, the hierarchy will migrate to subclass
`mgf.common.exceptions.HttpError` directly + drop the local
`http_status` plumbing (it's now inherited from the HTTP-01 leaves
like `HttpForbidden`, `HttpConflict`, `HttpGone`).

`apps/core/exception_handlers.py` maps `exc.http_status` to the
DRF response status code via a custom `DEFAULT_EXCEPTION_HANDLER`.

### Subprocess + cancellation

Rare. One-shot maintenance commands use
`mgf.common.process.run_command` with a short timeout; no long-
running services. Cancellation is HTTP-request-scope only —
Django closes the request, the work cleans up.

### CLI

inthewords ships a small management-command set (`python manage.py
…`). They use `mgf.common.cli.translate_exceptions` for consistent
exit-code mapping; everything else flows through Django's
`BaseCommand`.

---

## Known non-adoptions

inthewords intentionally **does not** adopt:

- **`mgf.common`'s rotating-file logging sink** (LG-06). Cloud-
  native deployments don't have a persistent log directory; stdout
  is the collector's hand-off. LOG-01 documents this as a
  first-class non-adoption per kind.
- **GUI log viewer** (LG-07). Headless service; no GUI. LOG-02
  carve-out applies.
- **`mgf.common.cli`'s full subcommand registry**. Django's
  management-command registry handles dispatch; the mgf-common
  exit-code mapping + exception translator are the bits that
  port across.
- **The vault**. Secrets come from env vars + the cloud's secret
  manager; the `mgf.common.vault` encrypted-file path doesn't
  apply.
- **`pyproject.toml`-based dep declaration**. pip-tools
  `requirements/*.{txt,lock}` is the chosen shape. PAPER-15
  v0.32.0 closed the catch-up CLI gap that made this invisible
  to mgf-common's audit.

---

## Friction it surfaced (and where it went)

inthewords' adoption walk surfaced several papers that shipped
together at v0.18.0 and v0.32.0:

| Paper | What it closed |
|---|---|
| HTTP-01 | The HTTP-status-coded exception hierarchy (`HttpError` + 12 leaves) — every web consumer's basic typed-exception shape. |
| CONFIG-01 | CF-* applies_to carve-out (CF-* applies to CLI/desktop; framework-native config patterns are first-class for Django et al). |
| LOG-01 | LG-06 rotating-file mandate is N/A for cloud-native logging; stdout-only is the right shape with mgf-common's JSON formatter. |
| LOG-02 | LG-07 GUI log-viewer mandate is N/A for headless services. |
| PAPER-13 | catch-up kind detection for no-pyproject Django apps (`manage.py` heuristic). |
| PAPER-14 | catch-up v0.1-pattern audit walked into `.venv` + Markdown docs (false positives). |
| PAPER-15 | catch-up full pip-tools manifest audit (v0.32.0). |
| ASPIRE-02 | The whole "second consumer arrived" event-shape recognition + per-kind applicability columns. |

---

## Cross-references

- inthewords' own repo: <https://codeberg.org/magogi-admin/inthewords>
- inthewords' `docs/MGF_COMMON_ADOPTION.md` — the adoption-walk
  tracking doc that surfaced the friction.
- inthewords' `docs/standards/web/README.md` — the web-shape
  patterns that inthewords + TelePlasma share.
- [`docs/standards/web/`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/web/) (mgf-common) — the
  cross-web-consumer standards subtree.
- [`docs/standards/principles/non-adoption-is-valid.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/principles/non-adoption-is-valid.md)
  — the principle the carve-outs invoke.
