# STACK — document-scanner

_Last updated: 2026-05-21_

## Summary

Document Scanner is a full-stack application with a Python/FastAPI backend and a Vue 3 frontend, containerised with Docker Compose. The backend handles document ingestion, text extraction, and AI-powered topic classification; the frontend is a single-page app served by Vite. No external database is used — all state is persisted to the local filesystem.

---

## Languages

| Language | Version | Where used |
|---|---|---|
| Python | 3.12 (pinned in `backend/Dockerfile`) | Backend API, AI providers, services |
| JavaScript (ES modules) | ES2022+ (`"type": "module"` in `frontend/package.json`) | Frontend SPA |

---

## Runtime

**Backend:**
- CPython 3.12 (Docker image: `python:3.12-slim`)
- ASGI server: Uvicorn `>=0.29` with standard extras (websockets, httptools)
- Entry point: `backend/main.py` — `uvicorn main:app`

**Frontend:**
- Node.js 20 (Docker image: `node:20-alpine`)
- Dev server: Vite 5 on port 5173
- Entry point: `frontend/index.html` → `frontend/src/main.js`

**Package Manager:**
- Backend: `pip` — lockfile: none (ranges only in `backend/requirements.txt`)
- Frontend: `npm` — lockfile: `frontend/package-lock.json` (present but not committed, generated on `npm install`)

---

## Frameworks

### Backend

| Package | Version | Purpose |
|---|---|---|
| `fastapi` | `>=0.111` | REST API framework — `backend/main.py` |
| `uvicorn[standard]` | `>=0.29` | ASGI server |
| `pydantic-settings` | `>=2.2` | Settings/config validation |
| `python-multipart` | latest | Multipart file upload parsing |

### Frontend

| Package | Version | Purpose |
|---|---|---|
| `vue` | `^3.4.0` | UI framework — `frontend/src/App.vue` and all components |
| `vue-router` | `^4.3.0` | Client-side routing — `frontend/src/router/index.js` |
| `pinia` | `^2.1.0` | State management — `frontend/src/stores/` |

### Build / Dev Tooling

| Tool | Version | Purpose |
|---|---|---|
| `vite` | `^5.2.0` | Frontend bundler and dev server — `frontend/vite.config.js` |
| `@vitejs/plugin-vue` | `^5.0.0` | Vue SFC support in Vite |
| `tailwindcss` | `^3.4.0` | Utility-first CSS — `frontend/tailwind.config.js` |
| `postcss` | `^8.4.0` | CSS processing — `frontend/postcss.config.js` |
| `autoprefixer` | `^10.4.0` | CSS vendor prefixing |

---

## Key Backend Dependencies

| Package | Version | Purpose |
|---|---|---|
| `anthropic` | `>=0.26` | Anthropic Claude API client — `backend/ai/anthropic_provider.py` |
| `openai` | `>=1.30` | OpenAI / OpenAI-compatible API client — `backend/ai/openai_provider.py`, also used for Ollama and LM Studio via `base_url` override |
| `PyMuPDF` (`fitz`) | `>=1.24` | PDF text extraction — `backend/services/extractor.py` |
| `python-docx` | `>=1.1` | DOCX text extraction — `backend/services/extractor.py` |
| `pytesseract` | `>=0.3` | OCR for image files — `backend/services/extractor.py` |
| `Pillow` | `>=10.3` | Image handling for OCR — `backend/services/extractor.py` |
| `filelock` | `>=3.14` | File-based concurrency locks — `backend/services/storage.py` |
| `aiofiles` | `>=23.2` | Async file I/O support |
| `httpx` | `>=0.27` | Async HTTP client (used internally by `anthropic` and `openai` SDKs) |

---

## Testing

| Tool | Version | Purpose |
|---|---|---|
| `pytest` | `>=8.2` | Test runner — `backend/pytest.ini`, `backend/tests/` |
| `pytest-asyncio` | `>=0.23` | Async test support; `asyncio_mode = auto` set in `backend/pytest.ini` |

No frontend test framework is present.

---

## Storage

- **File system only** — no database engine.
- Upload files stored at `backend/data/uploads/` (UUID-named).
- Document metadata stored as per-document JSON files at `backend/data/metadata/`.
- Topics registry: `backend/data/topics.json`.
- App settings: `backend/data/settings.json`.
- File-level concurrency managed via `filelock` (`backend/services/storage.py`).

---

## System Dependencies (backend Docker image)

Installed via `apt-get` in `backend/Dockerfile`:
- `tesseract-ocr` — OCR binary for `pytesseract`
- `libgl1`, `libglib2.0-0` — shared libraries required by PyMuPDF

---

## Configuration

- Environment variable `DATA_DIR` sets the root data path (default: `/app/data`).
- AI provider settings (models, API keys, base URLs) are stored in `backend/data/settings.json` and managed through the in-app Settings UI.
- Optional bootstrap via `.env` (see `.env.example`): only `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` are referenced.
- Default active provider is `lmstudio` (no API key required).

---

## Gaps / Unknowns

- No Python version pinning file (`.python-version`, `pyproject.toml`) outside the Dockerfile — local dev outside Docker may use a different Python version.
- No frontend lockfile committed; exact transitive dependency versions are non-deterministic until `npm install` is run.
- No linter or formatter config detected (no `.eslintrc`, `.prettierrc`, `biome.json`, `ruff.toml`, `mypy.ini`, etc.).
- No production deployment config beyond Docker Compose (no nginx config, no cloud provider manifests).
