# Dependency & unused-library audit

Every finding on this page was verified by grepping actual imports across
`frontend/app`, `frontend/src`, `frontend/modules`, and all `backend/**/*.py`. A
package is only called "unused" where a grep found no usage and it is not a
required transitive/peer/plugin dependency.

## Frontend — remove or relocate

```mermaid
graph LR
    subgraph "Remove (0 imports, non-functional)"
        R1["react-native-dotenv"]
        R2["react-native-webview"]
        R3["expo-symbols"]
    end
    subgraph "Relocate"
        M1["@expo/ngrok → devDependencies"]
    end
```

| Package | Evidence | Action |
|---|---|---|
| `react-native-dotenv` | 0 imports; no `@env` usage; **no `babel.config.js`** to even wire its plugin. All env access is `process.env.EXPO_PUBLIC_*`. A vestigial `expo.doctor` exclude still names it. | Remove — low risk |
| `react-native-webview` | 0 hits for `WebView` anywhere. The "widget preview" justification is stale — `modules/drape-widget` is a **native Swift** widget, not a WebView. | Remove — low risk |
| `expo-symbols` | 0 hits for `expo-symbols` / `SymbolView` / `SFSymbol`. | Remove — low risk |
| `@expo/ngrok` | 0 imports; a dev-only tunnel binary sitting in `dependencies`. | Move to `devDependencies` |
| `expo-web-browser` | Declared as an `app.json` plugin but 0 JS usage. | Verify no redirect flow depends on it, then remove — low/medium confidence |

**Confirmed in use (keep):** `@expo/vector-icons` (46 imports), `expo-router`
(50), `react-native-safe-area-context` (45), `@react-native-async-storage/async-storage`
(26), `expo-image` (13), `expo-linear-gradient` (8), `react-native-svg`,
`posthog-react-native`, `expo-image-picker`, `expo-camera`, `expo-file-system`,
`expo-haptics`, the three Google-font packages, `@sentry/react-native`,
`react-native-view-shot` (share cards), and `expo-image-manipulator` (loaded via a
dynamic `import()` in `body-photo.tsx`).

**Used indirectly — do not remove:** `posthog-react-native-session-replay` (native
autolinked peer), `react-native-screens` / `react-native-gesture-handler` /
`react-native-reanimated` / `react-native-worklets` (navigation + Expo infra),
`react-native-web` / `react-dom` (web build target), and the various `expo-*`
router internals.

The directly-listed `@react-navigation/*` and `@expo/metro-runtime` packages are
guaranteed transitively by `expo-router` — removing them declutters the manifest
but forfeits version pinning, so it is optional and low priority.

## Backend — the big win

The backend `requirements.txt` is a full `pip freeze` (157 pinned lines). The
code actually imports roughly **25 top-level packages**. Entire stacks are
installed that nothing imports:

```mermaid
graph TB
    subgraph "Imported & used (~25)"
        U["fastapi · motor · pymongo · pydantic · PyJWT · bcrypt<br/>pillow · numpy · httpx · stripe · supabase · upstash_redis<br/>slowapi · fal_client · fashn · sentry_sdk · langfuse · openai"]
    end
    subgraph "Installed, 0 imports (remove)"
        B1["litellm + tiktoken + tokenizers + huggingface_hub"]
        B2["google-* (genai, generativeai, api-python-client, auth…)"]
        B3["boto3 + botocore + s3transfer"]
        B4["pandas"]
        B5["pyiceberg + pyroaring + strictyaml + zstandard"]
        B6["s5cmd · jq · fastuuid · passlib · librt"]
    end
```

Each package below returned **0 import matches repo-wide** and is not a transitive
dependency of anything used:

| Package(s) | Why it is bloat |
|---|---|
| `litellm` (+ `tiktoken`, `tokenizers`, `huggingface_hub`, `hf-xet`) | Langfuse does not require litellm; came in as an unused stack |
| `google-genai`, `google-generativeai`, `google-ai-generativelanguage`, `google-api-python-client`, `google-auth*` (+ gRPC/proto tree) | Drape uses OpenAI + fal.ai + Fashn, never Gemini/Google |
| `boto3`, `botocore`, `s3transfer` | Storage is Supabase, not S3 |
| `pandas` | Never imported |
| `pyiceberg` (+ `pyroaring`, `strictyaml`, `mmh3`, `zstandard`, `fsspec`) | Apache Iceberg — not in the architecture |
| `s5cmd`, `jq`, `fastuuid`, `passlib`, `librt` | Unused CLIs / libs (`bcrypt` and stdlib `uuid` are what's actually used) |

## requirements.txt anti-patterns

1. **Full-freeze, no direct/transitive split.** 157 pinned lines mix true direct
   deps with internals like `h11`, `hpack`, `anyio`, `yarl`. Upgrades are brittle
   and the ~25 real deps are hidden.
2. **Dev tooling installed in production.** `black`, `flake8`, `isort`, `mypy`,
   `pytest`, `pycodestyle`, `pyflakes`, `mccabe`, `pathspec`, and friends are
   installed on a 512 MB Render free tier. There is **no** `requirements-dev.txt`.
3. **Inconsistent pinning.** Every line is `==`-pinned except the first,
   `anthropic>=0.40.0` — and `anthropic` is only used by a dev **cron agent**
   (`agents/bug_fixer.py`), so it does not belong in the production file.
4. **Orphaned transitives.** `ecdsa` and `rsa` (classic `python-jose` deps) remain
   even though `python-jose` was removed — the freeze was never regenerated
   cleanly.

:::info[python-jose: good news, and the old audits are wrong]
`python-jose` is **not present** and imported **nowhere** — `server.py` uses
`import jwt as pyjwt` (PyJWT). There is **no** CVE-2024-33663 / 33664 exposure. The
2026-05-25 audit docs claim the opposite ("python-jose is used, remove PyJWT") —
that is inverted and stale, and should be corrected.
:::

## Prioritized cleanup

**Tier 1 — safe, quick (low risk):**

- Frontend: remove `react-native-dotenv`, `react-native-webview`, `expo-symbols`;
  move `@expo/ngrok` to `devDependencies`. Then reinstall + an Expo build smoke
  test.
- Backend: create `requirements-dev.txt` and move the ~13 dev tools out of prod.

**Tier 2 — remove unused heavy stacks (low–medium risk):**

- Drop the Google AI, AWS, litellm, pandas, and Iceberg stacks plus their orphaned
  transitives. Expected to cut the install by well over half.
- Move `anthropic` (pinned) and `requests` to the dev file — both are
  agent-script-only.
- **Risk surface is the re-freeze.** Rebuild in a clean venv, reinstall the
  curated direct list, and verify `import server` succeeds before deploying —
  following the manual-deploy + staging-smoke-test rules.

**Tier 3 — follow-ups (housekeeping):**

- If the legacy `POST /api/previews/generate` endpoint is deleted (no frontend
  callers, its key already removed), the `openai` import becomes removable too.
- Correct the two stale audit docs.

**Net effect:** the frontend sheds three to four real dependencies; the backend
`requirements.txt` drops from 157 pinned lines to roughly 25 curated production
deps plus a separate dev file.
