# mgf-fastapi v0.2.0 — `mgf.fastapi.db` cutover guide

> **Audience:** mgf-fastapi consumers migrating from v0.1.0 (paired
> with mgf-common v0.28/0.29) to v0.2.0 (paired with mgf-common v0.30
> + mgf-sqlalchemy v0.1.0).
> **What this is:** the mgf-fastapi-side migration document for the
> v0.30 federation paired-extraction. Companion guides:
> [`mgf-sqlalchemy/docs/cutover/v0.1.0.md`](https://codeberg.org/magogi-admin/mgf_sqlalchemy/src/branch/main/docs/cutover/v0.1.0.md),
> [`mgf-alembic/docs/cutover/v0.1.0.md`](https://codeberg.org/magogi-admin/mgf_alembic/src/branch/main/docs/cutover/v0.1.0.md),
> and [`mgf-common/docs/cutover/v0.30.0.md`](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/docs/cutover/v0.30.0.md).

The change in mgf-fastapi v0.2.0 is **purely additive**: a new
`mgf.fastapi.db` submodule with two helpers that previously lived
under `mgf.common.db.*`. None of the v0.1.0 surface (`mgf.fastapi`,
`.webhooks`, `.security`, `.testing`, `.exceptions`) changed shape.

The pin to mgf-common bumps to `>=0.30,<0.31`. That's the breaking
edge for v0.1.0 consumers who weren't ready for mgf-common v0.30.

---

## At-a-glance

| Was (mgf-fastapi v0.1.0 + mgf-common ≤ v0.29) | Is (mgf-fastapi v0.2.0 + mgf-common v0.30) |
|---|---|
| `from mgf.common.db import get_session` | `from mgf.fastapi.db import get_session` |
| `from mgf.common.db import setup_db` | `from mgf.fastapi.db import setup_db` |
| `pip install 'mgf-common[db,fastapi]'` | `pip install 'mgf-fastapi[sqlalchemy]' mgf-sqlalchemy` |
| `mgf-common>=0.28,<0.29` | `mgf-common>=0.30,<0.31` |
| (everything else) | unchanged |

**No code-shape changes** in `get_session` / `setup_db` themselves.
The implementations are byte-identical to mgf-common v0.29.0 modulo
the import that now uses `mgf.sqlalchemy.create_engine` /
`create_sessionmaker` (which are themselves byte-identical to the
old `mgf.common.db` originals).

---

## Why these helpers moved here

The federation roadmap stated mgf-sqlalchemy should be
**framework-agnostic**: no Starlette, no FastAPI in its dep graph.
But two helpers in the old `mgf.common.db` were inherently
FastAPI-shaped:

- `get_session` imports `starlette.requests.Request` at runtime
  (FastAPI Depends needs the runtime type for introspection).
- `setup_db` takes a `FastAPI` app parameter and reads/writes
  `app.state.mgf_db_*`.

Pulling those into a "pure-SQLAlchemy" sibling would force a
Starlette runtime dep on consumers who never asked for FastAPI.
Splitting by shape — pure helpers in mgf-sqlalchemy, FastAPI helpers
in mgf-fastapi — keeps each sibling's dep graph honest.

The trade-off: consumers who use these helpers now install BOTH
`mgf-sqlalchemy` AND `mgf-fastapi[sqlalchemy]`. The `[sqlalchemy]`
extra is just a runtime dep on `mgf-sqlalchemy>=0.1,<0.2`; without
it, importing `mgf.fastapi.db` raises `ImportError` at load time.

Pure-SQLAlchemy consumers (data pipelines, CLI workers, non-FastAPI
services) shed a transitive Starlette import they never asked for.

---

## What landed in mgf-fastapi v0.2.0

| Submodule | What |
|---|---|
| `mgf.fastapi.db` | `get_session`, `setup_db`. New optional extra: `mgf-fastapi[sqlalchemy]`. |

Nothing else changed. The full v0.1.0 surface (10 names in
`mgf.fastapi`, 1 in `.exceptions`, 4 in `.webhooks`, 2 in
`.security`, 1 in `.testing`) ships unchanged.

---

## Migration steps

### 1. Update your `pyproject.toml`

For consumers who used the FastAPI-shaped DB helpers:

```toml
# Before
dependencies = [
    "mgf-common[db,fastapi]>=0.28,<0.29",
    "mgf-fastapi>=0.1,<0.2",  # if separately listed
]

# After
dependencies = [
    "mgf-common>=0.30,<0.31",
    "mgf-sqlalchemy>=0.1,<0.2",
    "mgf-fastapi[sqlalchemy]>=0.2,<0.3",
]
```

For consumers who used `mgf.fastapi` but not the DB helpers:

```toml
# Before
dependencies = [
    "mgf-common>=0.28,<0.29",
    "mgf-fastapi>=0.1,<0.2",
]

# After
dependencies = [
    "mgf-common>=0.30,<0.31",
    "mgf-fastapi>=0.2,<0.3",
]
```

For test consumers:

```toml
# Before
[project.optional-dependencies]
test = [
    "mgf-common[db-test,fastapi-test]>=0.28,<0.29",
]

# After
test = [
    "mgf-common>=0.30,<0.31",
    "mgf-sqlalchemy[test]>=0.1,<0.2",
    "mgf-fastapi[sqlalchemy,testing]>=0.2,<0.3",
]
```

### 2. Rewrite imports

For the two helpers that moved:

```bash
# At your repo root:
git ls-files '*.py' | xargs sed -i \
    -e 's|from mgf\.common\.db import \(get_session\|setup_db\)|from mgf.fastapi.db import \1|g'
```

For pure-SQLAlchemy helpers (in the same migration window):

```bash
git ls-files '*.py' | xargs sed -i \
    -e 's|from mgf\.common\.db import create_engine|from mgf.sqlalchemy import create_engine|g' \
    -e 's|from mgf\.common\.db import create_sessionmaker|from mgf.sqlalchemy import create_sessionmaker|g' \
    -e 's|from mgf\.common\.db import tenant_session|from mgf.sqlalchemy import tenant_session|g'
```

For mixed imports like
`from mgf.common.db import create_engine, get_session, setup_db, tenant_session`,
split by hand into two lines first, then re-run sed:

```python
# Before
from mgf.common.db import create_engine, get_session, setup_db, tenant_session

# After
from mgf.sqlalchemy import create_engine, tenant_session
from mgf.fastapi.db import get_session, setup_db
```

### 3. Re-run the four gates

```bash
uv sync
uv run ruff check
uv run mypy --strict src/
uv run pytest
```

If your test suite was green against mgf-common v0.29 + mgf-fastapi
v0.1, it should be green against mgf-common v0.30 + mgf-fastapi v0.2
+ mgf-sqlalchemy v0.1 immediately after the import rewrite.

### 4. Re-run `mgf-common catch-up`

```bash
mgf-common catch-up
```

---

## What's deliberately NOT in v0.2.0

The v0.2.0 release is **strictly additive** — `mgf.fastapi.db`
arrives, the rest of the surface is unchanged. Future v0.x releases
will add:

- **More DB-shaped FastAPI helpers** — `get_engine` (for
  consumers who need engine-level access from a request scope),
  potentially a typed router-include helper for
  `setup_db`-using projects.
- **Tenant scoping at the request layer** —
  `mgf.fastapi.db.tenant_request_session` would compose
  `get_session` with `mgf.sqlalchemy.tenant_session` reading the
  tenant id from the JWT/header. Files when a consumer asks.

---

## Engineering note

mgf-fastapi v0.2.0 carries **89 tests** total (was 83 in v0.1.0):

- 6 new in `tests/unit/test_db.py` (FastAPI-Depends integration +
  `setup_db` lifespan; ported from mgf-common v0.29's
  `tests/unit/db/test_session.py` and `test_db_lifespan.py`).
- 83 unchanged — the v0.1.0 surface is byte-identical.

The PEP 420 namespace package (no top-level `mgf/__init__.py` in
any sibling repo) means `mgf.fastapi`, `mgf.fastapi.db`,
`mgf.sqlalchemy`, `mgf.alembic`, `mgf.http`, and `mgf.common`
coexist seamlessly in the same Python process.
