# Reference consumer profile — TelePlasma

> **Project:** FastAPI SaaS application (multi-tenant data/UI mapping for energy plasma research)
> **Status:** Third reference consumer (arrived 2026-05-08). First SaaS / multi-tenant web-shape consumer.
> **Profile last refreshed:** 2026-05-10

TelePlasma is a FastAPI-based SaaS application with a multi-tenant
data model. It's the first consumer with a real
auth-provider integration (Clerk) and a real third-party webhook
integration (Svix-shape signing). Several recent mgf-common /
mgf-fastapi additions came from TelePlasma's filings.

Its shape biases toward:

- Async-first request handling (FastAPI + uvicorn)
- Bearer-token + cookie auth via a third-party identity provider
- Per-tenant SQLAlchemy session (Postgres RLS)
- Webhook receivers (Svix HMAC verification)
- Container-native logging (stdout JSON; same shape as inthewords)
- Pyproject-based dep declaration (PEP 621)

When the standards docs cite "the FastAPI / SaaS consumer",
TelePlasma is implied.

---

## Shape at a glance

| Concern | TelePlasma's shape |
|---|---|
| Manifest | `pyproject.toml` (PEP 621) |
| Layout | `src/plasmamapper/…` |
| Entry point | `uvicorn plasmamapper.api:app` (FastAPI ASGI) |
| Identity | `bootstrap()` inside FastAPI lifespan (via `mgf.fastapi.setup_lifespan`) |
| Logging | mgf-common JSON formatter + stdout-only |
| Config | mgf-common `MgfSettings` + pydantic-settings for app-level config |
| Vault | not used |
| Errors | mgf-common HTTP-01 hierarchy via `ExceptionTranslationMiddleware` |
| Subprocess | none |
| Cancellation | per-request asyncio task cancellation |
| Multi-tenancy | per-request tenant ID → AppContext scoping → per-tenant DB session |
| Web framework | FastAPI |
| Auth | Clerk (third-party IdP) via bearer + session cookie |
| Webhooks | Svix-shape HMAC verification for upstream sync events |
| DB | SQLAlchemy async + Postgres RLS |
| Tests | pytest + pytest-asyncio + httpx; mypy strict; ruff; coverage ≥ 85% |

---

## Pattern-by-pattern evidence

### Configuration

`MgfSettings` lives alongside a domain-specific `pydantic-settings`
class for TelePlasma-specific concerns (Clerk client config, Svix
verifier secret, S3 bucket names, etc.). The two compose at
startup; CF-* applies to the mgf-common half, the FastAPI app's
own settings.py follows pydantic-settings conventions for the
app-level half.

### Logging

`bootstrap()` is called from `mgf.fastapi.setup_lifespan` with the
default `setup_logging=True`; the resulting JSON formatter writes
to stdout, which uvicorn pipes through. Per-request `X-Request-Id`
is propagated by `mgf.fastapi.RequestIdMiddleware` and lands in
every log line via the formatter's request-context binding.

### Error handling

The HTTP-01 hierarchy is used directly (`HttpUnauthorized`,
`HttpForbidden`, `HttpNotFound`, `HttpConflict`, etc.).
`mgf.fastapi.ExceptionTranslationMiddleware` maps every `AppError`
subclass to a JSON 4xx/5xx response via the `http_status` fallback;
domain-specific exceptions are subclasses of the HTTP-01 leaves so
they inherit the right status without `status_map` extension.

`HmacVerificationError` (from `mgf.fastapi.exceptions`) handles
the webhook-receiver failure path.

`HttpUnauthorized` is the unified failure path for the bearer-token
session resolution (PAPER-29 / `mgf.fastapi.security.bearer_session`).

### Auth + sessions (PAPER-29)

Every authenticated route runs through `bearer_session()` which
reads the `Authorization: Bearer <token>` header, hands the token to
TelePlasma's Clerk client (an `AuthVerifier[SessionPrincipal]`
impl), and returns the typed principal. Failure modes (missing
header, expired token, Clerk 500) translate to
`HttpUnauthorized` → 401.

Before PAPER-29 shipped (mgf-fastapi v0.3), TelePlasma had its
own ~30-LOC implementation of the same shape. The filing closed
the duplication.

### Webhooks (PAPER-26)

`HmacWebhookVerifier` validates upstream Svix-shape webhook
signatures. TelePlasma used it for the energy-data sync webhook;
the constant-time-compare + timestamp-window logic is exactly the
edges TelePlasma would have had to reimplement.

### Multi-tenancy

Per-request flow:

1. `bearer_session()` resolves the principal (carries tenant_id).
2. A dep wraps the principal in an `AppContext` scoped to the
   tenant (`AppContext(app_name=..., app_version=..., …)` → push
   onto the contextvar via `with`).
3. The per-request DB session sets `SET LOCAL app.tenant_id = …`
   via SQLAlchemy event listener → Postgres RLS enforces row-level
   isolation.
4. Logging picks up tenant_id via the request-context binding;
   every log line for the request carries it.

This exercises the "scoped" `AppContext` mode (`docs/design/multi_tenancy.md`'s
S3 — long-running services with finite tenants).

### IP allowlist (PAPER-27)

Ops-only admin endpoints (e.g. `/_/migrate`, `/_/seed`) are gated
behind `IpAllowlist(cidrs=[…], trust_proxy=True)`. Production
deployment puts an Envoy proxy in front; `trust_proxy=True`
honours the first `X-Forwarded-For` entry. PAPER-27's proxy-trust
footgun documentation lives in TelePlasma's `docs/runbook/`.

### Test API server (PAPER-28)

End-to-end tests use `mgf.fastapi.testing.run_test_app` to stand
up the real FastAPI app on a free port + run httpx against it.
The async context-manager shape was filed as PAPER-28 after
TelePlasma's tests reimplemented the same pattern.

---

## Known non-adoptions

TelePlasma intentionally **does not** adopt:

- **The vault.** Secrets come from env vars + the cloud's secret
  manager (same as inthewords).
- **The rotating-file sink** (LG-06). Same cloud-native reasoning
  as inthewords; LOG-01 carve-out applies.
- **GUI log viewer** (LG-07). Same reasoning; LOG-02 carve-out.
- **`mgf.common.cli`'s full subcommand registry**. FastAPI is the
  entry point; CLI tools are minimal.
- **`mgf.common.process.Service`**. No long-running subprocesses.
- **`VersionedFileStore`**. All state lives in Postgres + S3; no
  on-disk versioned config files.

---

## Friction it surfaced (and where it went)

TelePlasma's adoption + Phase 3 walk surfaced several papers
that shipped at v0.26 / v0.27 / v0.28 / v0.3 (mgf-fastapi):

| Paper | What it closed |
|---|---|
| PAPER-26 | `HmacWebhookVerifier` for Svix-shape upstream sync webhooks (mgf-common v0.26 → moved to mgf-fastapi v0.1 at the v0.28 split). |
| PAPER-27 | `IpAllowlist` FastAPI dep + proxy-trust footgun (mgf-common v0.27 → moved to mgf-fastapi v0.1). |
| PAPER-28 | `run_test_app` async context manager (mgf-common v0.27 → moved to mgf-fastapi v0.1). |
| PAPER-29 | `bearer_session` + `AuthVerifier` Protocol for the "Authorization: Bearer → typed session" gate (mgf-fastapi v0.3.0). |

The cumulative effect: TelePlasma's `src/plasmamapper/api/`
shrank by ~120 LOC across these four landings (each closed a
locally-duplicated ~30-LOC shape).

---

## Cross-references

- TelePlasma's own repo: not currently public; internal Magogi project.
- TelePlasma's `docs/runbook/` — operational runbooks (auth,
  webhooks, multi-tenancy).
- [`docs/standards/web/`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/web/) — the cross-web-
  consumer patterns TelePlasma exercises.
- [`docs/design/multi_tenancy.md`](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/docs/design/multi_tenancy.md) —
  the multi-tenancy position paper; TelePlasma's per-request
  scoping is its first real-world S3 exercise.
- [`mgf-fastapi`](https://codeberg.org/magogi-admin/mgf-fastapi) —
  the sibling where most TelePlasma-filed additions ship.
