# Architecture Iron is an async Python modular monolith with a Vue single-page Web app. ## System Overview ```text Browser UI | FastAPI app | Services | Repositories | SQLite metadata database | Storage adapters: local directory, S3, WebDAV ``` ## Backend Core stack: - FastAPI - SQLAlchemy 2.x async ORM - SQLite via `aiosqlite` - Alembic migrations - durable in-process jobs stored in SQLite Important packages: - `app/api/`: route handlers and dependency wiring - `app/services/`: business logic - `app/repositories/`: database access - `app/models/`: SQLAlchemy entities - `app/schemas/`: API schemas - `app/adapters/storage/`: storage adapter protocol, registry, and backend implementations ## Frontend Core stack: - Vite - Vue 3 - TypeScript - Pinia - OpenCloud design system Source lives in `frontend/`. Built assets are emitted into `app/web/dist/` and served by FastAPI at `/app`. ## Data Model Main tables: - `users` - `auth_sessions` - `directories` - `file_entries` - `file_versions` - `blobs` - `blob_replicas` - `backends` - `upload_sessions` - `upload_session_parts` - `jobs` - `placement_policies` - `preview_artifacts` - `cache_entries` Design principles: - logical namespace is separate from physical storage placement - files have immutable content versions - physical content is represented as blobs and replicas - user-facing deletion uses recycle-bin semantics - jobs are durable and retryable - backend-specific configuration is validated before persistence and stays behind adapter boundaries ## Upload And Read Path Uploads use `tus` transport under `/files`. Flow: 1. create upload session 2. append bytes with `PATCH` 3. finalize through the API 4. create file metadata, version, blob, and local replica 5. enqueue replication or preview jobs when needed Read path: 1. resolve file and current version 2. find the best local or cached blob 3. if needed, materialize a ready remote replica into cache 4. serve download, preview, or range stream ## Browser File Access JSON APIs use bearer-token authorization through the shared frontend API client. Browser preview and download must not use naked `/api/files/...` media URLs in `img`, `iframe`, `video`, or `window.open`. Fetch file content with authorization, create an object URL, use it, then revoke it. This is covered by the Playwright E2E flow. ## Jobs Jobs are stored in SQLite and executed by the in-process job loop. Current job types include: - blob replication - preview artifact generation - backend health checks - full reconcile - file reconcile Every job should be safe to retry. ## Storage Backends Supported backend types: - `local_directory`: a filesystem directory used for default local persistence and low-latency reads - `s3`: S3 protocol storage, including AWS S3, MinIO, and compatible object stores - `webdav`: WebDAV storage, including OpenList-managed cloud drive directories exposed through a dedicated `root_path` Replica object keys are written into a structured application-owned layout such as `objects/file/sha256/73/35/.blob`. This keeps remote storage organized under a predictable object tree without trying to disguise replica content as user-authored media files. During the current development stage, Iron treats this layout as the only supported remote object format and does not preserve compatibility with earlier experimental paths. Reserved object-tree namespaces: - `objects/file/...`: primary file blobs and replica payloads - `objects/preview//...`: generated previews such as `inline_preview`, `thumbnail`, and `poster` - `objects/export/metadata/YYYY/MM/DD/...`: metadata snapshot exports - `objects/manifest//...`: future manifest-style control files such as placement or repair manifests Backend config is normalized through typed schemas before it is stored. Public config and encrypted secret config are persisted separately. `IRON_SECRET_KEY` derives the encryption key for stored backend credentials. API responses include public config plus a list of configured secret fields so operators can identify a backend without exposing access keys, client secrets, or refresh tokens. Update requests can change public config and provide secret overrides; omitted secret fields keep their previous encrypted values. Disabled backends can be deleted only when they are no longer referenced by policies and no blob replicas remain stored on them.