# Technology Stack **Analysis Date:** 2026-06-02 ## Languages **Primary:** - Python 3.12 — backend API, services, Celery tasks, storage backends - JavaScript (ES Modules, ES2022+) — Vue 3 frontend SPA **Secondary:** - SQL — PostgreSQL schema via Alembic migrations (`backend/migrations/`) - HTML/CSS — Vue SFC templates, Tailwind utility classes ## Runtime **Backend:** - CPython 3.12 (pinned: `FROM python:3.12-slim` in `backend/Dockerfile`) - ASGI server: Uvicorn `>=0.29` with `[standard]` extras - Entry point: `backend/main.py` — `uvicorn main:app` **Frontend:** - Node.js 20 (pinned: `FROM node:20-alpine` in `frontend/Dockerfile`) - Dev server: Vite 5 on port 5173, proxies `/api` → `http://backend:8000` - Entry point: `frontend/index.html` → `frontend/src/main.js` **Package Manager:** - Backend: `pip` — `backend/requirements.txt`; no lockfile (floating `>=` ranges used throughout — see CONCERNS.md) - Frontend: `npm` — lockfile: `frontend/package-lock.json` ## Frameworks ### Backend Core | Package | Version | Purpose | |---|---|---| | `fastapi` | `>=0.111` | Async REST API framework — `backend/main.py` | | `uvicorn[standard]` | `>=0.29` | ASGI server | | `pydantic` | `>=2.0` with `[email]` | Request/response validation | | `pydantic-settings` | `>=2.2` | Environment-based config — `backend/config.py` | | `python-multipart` | `>=0.0.27` | Multipart file upload parsing | ### ORM / Database | Package | Version | Purpose | |---|---|---| | `sqlalchemy[asyncio]` | `>=2.0.49` | Async ORM — `backend/db/session.py`, `backend/db/models.py` | | `psycopg[binary]` | `>=3.3.4` | psycopg v3 async PostgreSQL driver | | `alembic` | `>=1.18.4` | Schema migrations — `backend/migrations/` | | `aiosqlite` | `>=0.20.0` | SQLite async driver (test isolation only) | ### Background Tasks | Package | Version | Purpose | |---|---|---| | `celery[redis]` | `>=5.5.0` | Async task queue — `backend/celery_app.py` | | `redis` | `>=4.6.0` | Redis async client; Celery broker + result backend + JTI token store | ### Auth / Security | Package | Version | Purpose | |---|---|---| | `PyJWT` | `>=2.8.0` | JWT access token creation and verification — `backend/services/auth.py` | | `pwdlib[argon2]` | `>=0.2.1` | Argon2id password hashing | | `pyotp` | `>=2.9.0` | TOTP provisioning and verification (2FA) | | `cryptography` | `>=41.0.0` | HKDF per-user key derivation; Fernet encryption for cloud credentials | | `slowapi` | `>=0.1.9` | Rate limiting middleware on auth endpoints | | `httpx` | `>=0.27` | Async HTTP client (HIBP k-anonymity checks, OneDrive Graph API) | ### Document Processing | Package | Version | Purpose | |---|---|---| | `PyMuPDF` | `>=1.26.7` | 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 loading for OCR pipeline | | `aiofiles` | `>=23.2` | Async file I/O | ### AI Classification | Package | Version | Purpose | |---|---|---| | `anthropic` | `>=0.26` | Anthropic Claude SDK — `backend/ai/anthropic_provider.py` | | `openai` | `>=1.30` | OpenAI SDK; also used as shim for Ollama and LM Studio — `backend/ai/openai_provider.py` | ### Cloud Storage SDKs | Package | Version | Purpose | |---|---|---| | `minio` | `>=7.2.20` | MinIO/S3 object storage SDK — `backend/storage/minio_backend.py` | | `google-auth-oauthlib` | `>=1.3.1` | Google OAuth2 flow — `backend/storage/google_drive_backend.py` | | `google-api-python-client` | `>=2.196.0` | Google Drive v3 API — `backend/storage/google_drive_backend.py` | | `msal` | `>=1.36.0` | Microsoft Auth Library for OneDrive — `backend/storage/onedrive_backend.py` | | `webdavclient3` | `>=3.14.7` | Generic WebDAV + Nextcloud — `backend/storage/webdav_backend.py` | | `cachetools` | `>=5.3.0` | Cloud connection caching — `backend/services/cloud_cache.py` | ### Frontend | Package | Version | Purpose | |---|---|---| | `vue` | `^3.4.0` | UI framework (Options API) — `frontend/src/` | | `vue-router` | `^4.3.0` | Client-side routing — `frontend/src/router/` | | `pinia` | `^2.1.0` | State management (JWT access token stored in memory only) — `frontend/src/stores/` | | `qrcode` | `^1.5.4` | TOTP QR code generation for 2FA enrollment UI | | `tailwindcss` | `^3.4.0` | Utility-first CSS — `frontend/tailwind.config.js` | ### Frontend Dev / Build | Tool | Version | Purpose | |---|---|---| | `vite` | `^5.2.0` | Dev server and bundler — `frontend/vite.config.js` | | `@vitejs/plugin-vue` | `^5.0.0` | Vue SFC compilation | | `postcss` | `^8.4.0` | CSS processing — `frontend/postcss.config.js` | | `autoprefixer` | `^10.4.0` | CSS vendor prefixing | ### Testing | Tool | Version | Purpose | |---|---|---| | `pytest` | `>=8.2` | Backend test runner — `backend/pytest.ini` | | `pytest-asyncio` | `>=1.3.0` | Async test support (`asyncio_mode = auto`) | | `vitest` | `^4.1.7` | Frontend test runner — `frontend/vitest.config.js` | | `@vue/test-utils` | `^2.4.10` | Vue component test utilities | | `happy-dom` | `^20.9.0` | DOM environment for Vitest | ## Infrastructure ### Docker Compose Services (`docker-compose.yml`) | Service | Image | Port(s) | Notes | |---|---|---|---| | `postgres` | `postgres:17-alpine` | internal | Persistent `postgres_data` volume | | `minio` | `minio/minio:latest` | `9000`, `9001` | S3-compatible object store; persistent `minio_data` volume | | `redis` | `redis:7-alpine` | internal | Password-protected; Celery broker + JTI revocation store | | `backend` | Built from `./backend` | `8000` | Hot-reload via volume mount; depends on postgres, minio, redis | | `celery-worker` | Built from `./backend` | — | Processes `documents` queue | | `celery-beat` | Built from `./backend` | — | Periodic task scheduler | | `frontend` | Built from `./frontend` | `5173` | Vite dev server; proxies `/api` → `backend:8000` | ### Database Role Separation - `docuvault_app` — DML only (SELECT/INSERT/UPDATE/DELETE); used by FastAPI app - `docuvault_migrate` — DDL; used by Alembic migrations only - Init script: `docker/postgres/initdb.d/01-init-users.sql` ### 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 variables** are the single source of truth, read by `pydantic-settings` in `backend/config.py`. Required for core operation: - `DATABASE_URL` — psycopg v3 async DSN for app user - `DATABASE_MIGRATE_URL` — psycopg v3 DSN for migrate user - `MINIO_ENDPOINT`, `MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`, `MINIO_BUCKET` - `REDIS_URL` — used by both FastAPI (JTI store) and Celery - `SECRET_KEY` — JWT signing secret - `CLOUD_CREDS_KEY` — 32-byte master key for HKDF cloud credential encryption Optional: - `SMTP_HOST/PORT/USER/PASSWORD/FROM` — transactional email - `GOOGLE_CLIENT_ID/SECRET`, `ONEDRIVE_CLIENT_ID/SECRET` — OAuth cloud storage - `ADMIN_EMAIL`, `ADMIN_PASSWORD` — bootstrap admin account - `SYSTEM_PROMPT`, `DEFAULT_AI_PROVIDER`, `DEFAULT_AI_MODEL` — AI defaults - `CORS_ORIGINS`, `FRONTEND_URL`, `BACKEND_URL` ## Platform Requirements **Development:** - Docker + Docker Compose (preferred), or - Python 3.12, Node.js 20 plus running PostgreSQL 17, MinIO, Redis instances locally **Production:** - Containerised via Docker Compose; no cloud-native manifests or reverse-proxy config detected in repo --- *Stack analysis: 2026-06-02*