16 changed files with 623 additions and 3734 deletions
@ -0,0 +1,82 @@ |
|||
# AGENTS.md |
|||
|
|||
Guidance for coding agents and automated contributors working in this repository. |
|||
|
|||
## Project Snapshot |
|||
|
|||
Iron is a self-hosted personal cloud drive gateway with: |
|||
|
|||
- FastAPI backend under `app/` |
|||
- Vite + React + TypeScript frontend under `frontend/` |
|||
- built frontend assets served from `app/web/dist/` |
|||
- Alembic migrations under `alembic/` |
|||
- tests under `tests/` |
|||
- project docs under `docs/` |
|||
|
|||
The current stage is **Product MVP Candidate**. Preserve the existing |
|||
desktop-first drive UX and avoid drifting back toward a generic admin dashboard. |
|||
|
|||
## Required Setup |
|||
|
|||
Use the local virtualenv and `uv` cache: |
|||
|
|||
```bash |
|||
UV_CACHE_DIR=.uv-cache uv venv .venv |
|||
UV_CACHE_DIR=.uv-cache uv pip install --python .venv/bin/python -e '.[dev]' |
|||
npm install |
|||
``` |
|||
|
|||
## Common Commands |
|||
|
|||
```bash |
|||
npm run build |
|||
.venv/bin/python -m pytest |
|||
.venv/bin/python scripts/ui_playwright_smoke.py |
|||
.venv/bin/python -m pytest tests/e2e/test_web_ui_playwright.py |
|||
``` |
|||
|
|||
## Development Rules |
|||
|
|||
- Keep runtime artifacts out of Git: `.venv/`, `node_modules/`, `output/`, |
|||
`.iron-storage/`, `.iron-temp/`, caches, and local databases. |
|||
- Add or update tests in the same change as behavior changes. |
|||
- For UI work, run the real-service Playwright flow and review screenshots. |
|||
- Do not use naked `/api/files/...` media URLs for browser preview/download. |
|||
Fetch file content with authorization, create an object URL, and revoke it. |
|||
- Keep docs current when changing setup, architecture, test counts, or user flows. |
|||
- Prefer small, focused changes over broad rewrites. |
|||
|
|||
## UI Quality Standard |
|||
|
|||
For any meaningful Web UI change: |
|||
|
|||
1. build frontend assets with `npm run build` |
|||
2. run `./.venv/bin/python scripts/ui_playwright_smoke.py` |
|||
3. inspect screenshots in `output/playwright/` |
|||
4. fix layout or interaction issues found in screenshots |
|||
5. rerun the Playwright flow |
|||
|
|||
See [docs/development.md](docs/development.md). |
|||
|
|||
## Documentation Expectations |
|||
|
|||
- `README.md` should stay user-facing and concise. |
|||
- `CONTRIBUTING.md` should describe contributor workflow. |
|||
- `docs/README.md` should index deeper docs. |
|||
- `docs/development.md` should describe test and UI validation rules. |
|||
- Avoid local absolute paths in committed Markdown. |
|||
|
|||
## Verification Before Finishing |
|||
|
|||
At minimum, run: |
|||
|
|||
```bash |
|||
npm run build |
|||
.venv/bin/python -m pytest |
|||
``` |
|||
|
|||
If UI behavior changed, also run: |
|||
|
|||
```bash |
|||
.venv/bin/python scripts/ui_playwright_smoke.py |
|||
``` |
|||
@ -0,0 +1,62 @@ |
|||
# Contributing |
|||
|
|||
Thanks for helping improve Iron. The project is still early, so the most useful |
|||
contributions are focused changes with tests and clear documentation updates. |
|||
|
|||
## Development Setup |
|||
|
|||
```bash |
|||
UV_CACHE_DIR=.uv-cache uv venv .venv |
|||
UV_CACHE_DIR=.uv-cache uv pip install --python .venv/bin/python -e '.[dev]' |
|||
npm install |
|||
npm run build |
|||
``` |
|||
|
|||
Run the API locally: |
|||
|
|||
```bash |
|||
.venv/bin/python -m uvicorn app.main:app --reload |
|||
``` |
|||
|
|||
Open `http://127.0.0.1:8000/app`. |
|||
|
|||
## Test Before Submitting |
|||
|
|||
Run the full suite: |
|||
|
|||
```bash |
|||
.venv/bin/python -m pytest |
|||
``` |
|||
|
|||
For UI changes, also run: |
|||
|
|||
```bash |
|||
npm run build |
|||
.venv/bin/python scripts/ui_playwright_smoke.py |
|||
``` |
|||
|
|||
Review screenshots in `output/playwright/` before considering UI work complete. |
|||
|
|||
## Pull Request Checklist |
|||
|
|||
- The change is focused and described clearly. |
|||
- Tests were added or updated for behavior changes. |
|||
- UI changes were validated with Playwright when applicable. |
|||
- Documentation was updated if setup, behavior, or architecture changed. |
|||
- Generated/runtime files are not included. |
|||
|
|||
## Code Style |
|||
|
|||
- Backend code lives in `app/` and uses async FastAPI + SQLAlchemy patterns. |
|||
- Frontend code lives in `frontend/` and uses React, React Router, and |
|||
TanStack Query. |
|||
- Keep browser file preview/download flows authenticated through the API client. |
|||
- Prefer clear names and small modules over clever abstractions. |
|||
|
|||
## Project Status |
|||
|
|||
Iron is a Product MVP Candidate. See: |
|||
|
|||
- [docs/product.md](docs/product.md) |
|||
- [docs/architecture.md](docs/architecture.md) |
|||
- [docs/development.md](docs/development.md) |
|||
@ -0,0 +1,14 @@ |
|||
# Documentation |
|||
|
|||
This directory contains the stable project documentation for Iron. |
|||
|
|||
- [Product](product.md): product scope, current stage, MVP cutline, and roadmap. |
|||
- [Architecture](architecture.md): backend, frontend, data model, storage, and job design. |
|||
- [API](api.md): route map and API groups. |
|||
- [Development](development.md): setup, test commands, Playwright workflow, and documentation rules. |
|||
|
|||
Root-level project docs: |
|||
|
|||
- [README](../README.md): user-facing overview and quick start. |
|||
- [Contributing](../CONTRIBUTING.md): contributor workflow. |
|||
- [Agents](../AGENTS.md): coding-agent and automation guidance. |
|||
@ -1,726 +0,0 @@ |
|||
# Iron API Design |
|||
|
|||
## 1. Overview |
|||
|
|||
This document defines the MVP API surface for the Iron gateway. |
|||
|
|||
Principles: |
|||
|
|||
- REST-first |
|||
- browser-first product usage, with backend auth that can evolve |
|||
- `tus` for resumable upload transport |
|||
- stable logical file identifiers |
|||
- backend topology hidden from normal users |
|||
|
|||
Base prefix: |
|||
|
|||
- `/api` |
|||
|
|||
Non-API upload transport prefix: |
|||
|
|||
- `/files` |
|||
|
|||
Notes: |
|||
|
|||
- `tus` endpoints intentionally live outside the normal JSON API shape because they follow protocol-specific request and response semantics. |
|||
- All timestamps should use ISO 8601 UTC strings. |
|||
- All entity IDs should use UUIDv7 or another sortable unique ID format. |
|||
|
|||
## 2. Authentication |
|||
|
|||
MVP auth model: |
|||
|
|||
- single local user |
|||
- bearer token session for the current backend implementation |
|||
- Web UI can later wrap this with cookie-based session handling if desired |
|||
|
|||
### 2.1 Login |
|||
|
|||
- `POST /api/auth/login` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"username": "admin", |
|||
"password": "secret" |
|||
} |
|||
``` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"access_token": "iron_xxx", |
|||
"token_type": "bearer", |
|||
"expires_at": "2026-04-20T00:00:00Z", |
|||
"user": { |
|||
"id": "usr_01", |
|||
"username": "admin" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- creates a persisted auth session and returns a bearer token |
|||
- returns `401` for invalid credentials |
|||
|
|||
### 2.2 Logout |
|||
|
|||
- `POST /api/auth/logout` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"success": true |
|||
} |
|||
``` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- revokes the current bearer-token session |
|||
|
|||
### 2.3 Current Session |
|||
|
|||
- `GET /api/auth/me` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"user": { |
|||
"id": "usr_01", |
|||
"username": "admin" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- requires `Authorization: Bearer <token>` |
|||
|
|||
## 3. Directories |
|||
|
|||
Route protection: |
|||
|
|||
- all directory, file, upload, and backend routes require authentication in the current codebase |
|||
|
|||
### 3.1 List Directory Children |
|||
|
|||
- `GET /api/directories/{directory_id}/children` |
|||
|
|||
Query params: |
|||
|
|||
- `cursor` |
|||
- `limit` |
|||
- `sort` |
|||
- `order` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"directory": { |
|||
"id": "dir_root", |
|||
"name": "/", |
|||
"parent_id": null |
|||
}, |
|||
"items": [ |
|||
{ |
|||
"kind": "directory", |
|||
"id": "dir_01", |
|||
"name": "photos", |
|||
"created_at": "2026-04-13T00:00:00Z", |
|||
"updated_at": "2026-04-13T00:00:00Z" |
|||
}, |
|||
{ |
|||
"kind": "file", |
|||
"id": "fil_01", |
|||
"name": "movie.mp4", |
|||
"mime_type": "video/mp4", |
|||
"size_bytes": 1048576, |
|||
"cache_status": "partial", |
|||
"preview_status": "ready", |
|||
"created_at": "2026-04-13T00:00:00Z", |
|||
"updated_at": "2026-04-13T00:00:00Z" |
|||
} |
|||
], |
|||
"next_cursor": null |
|||
} |
|||
``` |
|||
|
|||
### 3.2 Create Directory |
|||
|
|||
- `POST /api/directories` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"parent_id": "dir_root", |
|||
"name": "photos" |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- currently supports create under an existing parent directory |
|||
- duplicate sibling names are rejected |
|||
|
|||
### 3.3 Rename Directory |
|||
|
|||
- `POST /api/directories/{directory_id}/rename` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"name": "vacation-photos" |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
|
|||
### 3.4 Move Directory |
|||
|
|||
- `POST /api/directories/{directory_id}/move` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"target_parent_id": "dir_02" |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- moving a directory updates descendant logical path keys |
|||
|
|||
### 3.5 Delete Directory |
|||
|
|||
- `DELETE /api/directories/{directory_id}` |
|||
|
|||
Behavior: |
|||
|
|||
- soft delete in MVP |
|||
- reject if non-empty unless `recursive=true` is explicitly supported later |
|||
|
|||
Current implementation status: |
|||
|
|||
- `GET /api/directories/{directory_id}/children` is implemented |
|||
- current response can contain both directory items and file items |
|||
- items are currently returned with directories first, then files |
|||
|
|||
## 4. Files |
|||
|
|||
### 4.1 Get File Details |
|||
|
|||
- `GET /api/files/{file_id}` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"file": { |
|||
"id": "fil_01", |
|||
"directory_id": "dir_root", |
|||
"name": "movie.mp4", |
|||
"mime_type": "video/mp4", |
|||
"size_bytes": 1048576, |
|||
"current_version_id": "ver_01", |
|||
"preview_status": "ready", |
|||
"cache_status": "partial", |
|||
"created_at": "2026-04-13T00:00:00Z", |
|||
"updated_at": "2026-04-13T00:00:00Z" |
|||
}, |
|||
"preview_artifacts": [ |
|||
{ |
|||
"id": "prv_01", |
|||
"artifact_type": "thumbnail", |
|||
"blob_id": "blb_01", |
|||
"status": "ready" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- returns logical file metadata from the gateway database |
|||
- now includes preview artifact metadata when background generation has run |
|||
|
|||
### 4.2 Rename File |
|||
|
|||
- `POST /api/files/{file_id}/rename` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"name": "movie-final.mp4" |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
|
|||
### 4.3 Move File |
|||
|
|||
- `POST /api/files/{file_id}/move` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"target_parent_id": "dir_02" |
|||
} |
|||
``` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
|
|||
### 4.4 Delete File |
|||
|
|||
- `DELETE /api/files/{file_id}` |
|||
|
|||
Behavior: |
|||
|
|||
- current implementation moves the file to a recycle-bin state |
|||
- deleted files disappear from normal directory listings |
|||
- deleted files can be listed and restored through recycle-bin APIs |
|||
|
|||
### 4.5 Download File |
|||
|
|||
- `GET /api/files/{file_id}/download` |
|||
|
|||
Behavior: |
|||
|
|||
- returns attachment response |
|||
- gateway resolves best available replica and streams to client |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase for files persisted to the default local backend |
|||
- current implementation resolves the ready local replica and serves it directly |
|||
|
|||
### 4.6 Stream File |
|||
|
|||
- `GET /api/files/{file_id}/stream` |
|||
|
|||
Behavior: |
|||
|
|||
- supports `Range` requests |
|||
- intended for video and browser-native preview flows |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase for local persisted objects |
|||
- supports full reads and single-range byte requests |
|||
|
|||
### 4.7 File Thumbnail |
|||
|
|||
- `GET /api/files/{file_id}/thumbnail` |
|||
|
|||
Behavior: |
|||
|
|||
- returns preview derivative if present |
|||
- returns `404` if not yet available |
|||
|
|||
### 4.7a File Preview |
|||
|
|||
- `GET /api/files/{file_id}/preview` |
|||
|
|||
Behavior: |
|||
|
|||
- returns an inline response for preview-supported file types |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase for images and PDFs persisted to the default local backend |
|||
- unsupported media types currently return a validation-style error |
|||
|
|||
### 4.8 Recycle Bin |
|||
|
|||
- `GET /api/files/recycle-bin` |
|||
- `POST /api/files/{file_id}/restore` |
|||
|
|||
Current implementation status: |
|||
|
|||
- both endpoints are implemented |
|||
- restore returns a conflict if the original directory now contains an active item with the same file name |
|||
|
|||
## 5. Tus Upload Flow |
|||
|
|||
Iron uses `tus` as the upload transport and adds one gateway-specific finalize step. |
|||
|
|||
### 5.1 Create Upload Resource |
|||
|
|||
- `POST /files` |
|||
|
|||
Required headers: |
|||
|
|||
- `Tus-Resumable` |
|||
- `Upload-Length` |
|||
- `Upload-Metadata` |
|||
|
|||
Behavior: |
|||
|
|||
- creates a new upload session |
|||
- returns `201` with `Location` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- currently supports sequential append uploads with declared total length |
|||
- returns a gateway-managed upload resource under `/files/{upload_id}` |
|||
|
|||
### 5.2 Query Upload Offset |
|||
|
|||
- `HEAD /files/{upload_id}` |
|||
|
|||
Behavior: |
|||
|
|||
- returns current `Upload-Offset` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
|
|||
### 5.3 Upload Bytes |
|||
|
|||
- `PATCH /files/{upload_id}` |
|||
|
|||
Required headers: |
|||
|
|||
- `Tus-Resumable` |
|||
- `Upload-Offset` |
|||
- `Content-Type: application/offset+octet-stream` |
|||
|
|||
Behavior: |
|||
|
|||
- appends bytes to temporary ingest file |
|||
- updates upload progress |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- currently requires exact offset matching and sequential writes |
|||
|
|||
### 5.4 Finalize Upload |
|||
|
|||
- `POST /api/uploads/{upload_id}/finalize` |
|||
|
|||
Request: |
|||
|
|||
```json |
|||
{ |
|||
"directory_id": "dir_root", |
|||
"filename": "movie.mp4" |
|||
} |
|||
``` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"file": { |
|||
"id": "fil_01", |
|||
"name": "movie.mp4" |
|||
}, |
|||
"upload": { |
|||
"id": "upl_01", |
|||
"status": "finalized" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Behavior: |
|||
|
|||
- verifies upload completion |
|||
- computes content metadata |
|||
- creates file and file version records |
|||
- performs first durable write |
|||
- only exposes the logical file after minimum durability is met |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- currently finalizes into metadata records and persists the blob into the default local backend |
|||
- creates a `blob_replicas` record for the local persisted object |
|||
- enqueues replication jobs for enabled non-local backends such as `s3` |
|||
|
|||
## 6. Backends |
|||
|
|||
### 6.1 List Backends |
|||
|
|||
- `GET /api/backends` |
|||
|
|||
### 6.2 Create Backend |
|||
|
|||
- `POST /api/backends` |
|||
|
|||
Request example: |
|||
|
|||
```json |
|||
{ |
|||
"name": "local-main", |
|||
"type": "local", |
|||
"stability_class": "local", |
|||
"read_priority": 100, |
|||
"write_priority": 100, |
|||
"config": { |
|||
"base_path": "/srv/iron/storage" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 6.3 Update Backend |
|||
|
|||
- `PATCH /api/backends/{backend_id}` |
|||
|
|||
### 6.4 Check Backend Health |
|||
|
|||
- `POST /api/backends/{backend_id}/check` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"backend_id": "bkd_01", |
|||
"status": "healthy", |
|||
"checked_at": "2026-04-13T00:00:00Z" |
|||
} |
|||
``` |
|||
|
|||
### 6.5 Disable Backend |
|||
|
|||
- `POST /api/backends/{backend_id}/disable` |
|||
|
|||
## 7. Placement Policies |
|||
|
|||
### 7.1 List Placement Policies |
|||
|
|||
- `GET /api/policies/placement` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- returns file-class placement policy rows |
|||
- current policy shape includes: |
|||
- `require_local` |
|||
- `stable_replica_count` |
|||
- `opportunistic_replica_count` |
|||
- ordered `preferred_backend_ids` |
|||
- explicit `excluded_backend_ids` |
|||
- optional `max_non_local_size_bytes` |
|||
|
|||
### 7.2 Upsert Placement Policy |
|||
|
|||
- `PUT /api/policies/placement/{file_class}` |
|||
|
|||
Request example: |
|||
|
|||
```json |
|||
{ |
|||
"require_local": true, |
|||
"stable_replica_count": 1, |
|||
"opportunistic_replica_count": 1, |
|||
"preferred_backend_ids": ["bkd_s3_primary", "bkd_s3_archive"], |
|||
"excluded_backend_ids": ["bkd_s3_legacy"], |
|||
"max_non_local_size_bytes": 104857600 |
|||
} |
|||
``` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- validates that referenced backend ids exist |
|||
- rejects overlap between preferred and excluded backend ids |
|||
- rejects negative replica counts |
|||
|
|||
### 7.3 Preview Placement Decision |
|||
|
|||
- `GET /api/policies/placement/preview` |
|||
|
|||
Query params: |
|||
|
|||
- `mime_type` |
|||
- `size_bytes` |
|||
|
|||
Behavior: |
|||
|
|||
- implemented in current codebase |
|||
- returns the matched file class, active policy, and selected backends for the given mime type and optional size |
|||
- marks whether non-local replicas are currently allowed under the policy |
|||
|
|||
## 8. Jobs |
|||
|
|||
### 8.1 List Jobs |
|||
|
|||
- `GET /api/jobs` |
|||
|
|||
Query params: |
|||
|
|||
- `kind` |
|||
- `status` |
|||
- `limit` |
|||
|
|||
### 8.2 Get Job |
|||
|
|||
- `GET /api/jobs/{job_id}` |
|||
|
|||
### 8.3 Retry Job |
|||
|
|||
- `POST /api/jobs/{job_id}/retry` |
|||
|
|||
### 8.4 Run Pending Jobs |
|||
|
|||
- `POST /api/jobs/run-pending` |
|||
|
|||
### 8.5 Enqueue Backend Health Checks |
|||
|
|||
- `POST /api/jobs/enqueue-health-checks` |
|||
|
|||
### 8.6 Enqueue Full Reconcile |
|||
|
|||
- `POST /api/jobs/enqueue-full-reconcile` |
|||
|
|||
## 9. Exports |
|||
|
|||
### 9.1 Metadata Export |
|||
|
|||
- `GET /api/exports/metadata` |
|||
|
|||
### 9.2 Metadata Import |
|||
|
|||
- `POST /api/exports/metadata/import` |
|||
|
|||
Notes: |
|||
|
|||
- current backend requires `confirm_replace=true` for destructive import |
|||
- current backend also requires a fresh `validation_token` from `POST /api/exports/metadata/restore-plan` |
|||
- successful import currently schedules follow-up reconcile and backend health-check jobs |
|||
|
|||
## 9.3 Reconciliation |
|||
|
|||
- `POST /api/files/{file_id}/reconcile` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- the backend intention is "make this file converge to policy-defined replica state" |
|||
|
|||
## 9.4 Metadata Validation and Integrity |
|||
|
|||
- `POST /api/exports/metadata/validate` |
|||
- `GET /api/exports/metadata/integrity` |
|||
|
|||
## 9.5 Restore Plan |
|||
|
|||
- `POST /api/exports/metadata/restore-plan` |
|||
|
|||
## 10. System |
|||
|
|||
### 10.1 Health Check |
|||
|
|||
- `GET /api/system/health` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"status": "ok" |
|||
} |
|||
``` |
|||
|
|||
### 10.2 Readiness |
|||
|
|||
- `GET /api/system/ready` |
|||
|
|||
Response: |
|||
|
|||
```json |
|||
{ |
|||
"status": "ready", |
|||
"database": "ok" |
|||
} |
|||
``` |
|||
|
|||
## 10.3 Backends |
|||
|
|||
- `GET /api/backends` |
|||
- `POST /api/backends` |
|||
- `POST /api/backends/{backend_id}/check` |
|||
- `POST /api/backends/{backend_id}/disable` |
|||
|
|||
Implemented status: |
|||
|
|||
- implemented in current codebase |
|||
- supports local and s3 backend configuration metadata |
|||
- local and s3 backend health checks are implemented |
|||
|
|||
Additional implemented status: |
|||
|
|||
- `POST /api/jobs/run-pending` is implemented in current codebase |
|||
- `POST /api/jobs/enqueue-health-checks` is implemented in current codebase |
|||
- `GET /api/exports/metadata` is implemented in current codebase |
|||
- `POST /api/exports/metadata/validate` is implemented in current codebase |
|||
- `GET /api/exports/metadata/integrity` is implemented in current codebase |
|||
- `POST /api/exports/metadata/import` is implemented in current codebase |
|||
- `POST /api/files/{file_id}/reconcile` is implemented in current codebase |
|||
|
|||
## 11. Error Shape |
|||
|
|||
All JSON API errors should use one consistent envelope: |
|||
|
|||
```json |
|||
{ |
|||
"error": { |
|||
"code": "file_not_found", |
|||
"message": "File does not exist.", |
|||
"details": null |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Suggested error codes: |
|||
|
|||
- `unauthorized` |
|||
- `forbidden` |
|||
- `validation_error` |
|||
- `directory_not_found` |
|||
- `file_not_found` |
|||
- `upload_not_found` |
|||
- `backend_unavailable` |
|||
- `backend_config_invalid` |
|||
- `conflict` |
|||
- `internal_error` |
|||
|
|||
## 12. Versioning Approach |
|||
|
|||
MVP can stay unversioned internally if the API is changing quickly. |
|||
|
|||
Recommendation: |
|||
|
|||
- keep `/api` in code |
|||
- be prepared to introduce `/api/v1` before external client surface becomes stable |
|||
|
|||
## 13. Implementation Notes |
|||
|
|||
- `tus` transport handlers should be separated from normal JSON routers. |
|||
- Finalization logic must stay in application services, not inside protocol handlers. |
|||
- Download and stream endpoints should rely on the same replica resolution service. |
|||
- Avoid exposing backend IDs in normal file responses unless operationally useful. |
|||
@ -0,0 +1,84 @@ |
|||
# API |
|||
|
|||
Iron exposes JSON APIs under `/api` and `tus` upload transport under `/files`. |
|||
|
|||
Most `/api` routes require: |
|||
|
|||
```text |
|||
Authorization: Bearer <token> |
|||
``` |
|||
|
|||
## Auth |
|||
|
|||
- `POST /api/auth/login` |
|||
- `POST /api/auth/logout` |
|||
- `GET /api/auth/me` |
|||
|
|||
## Directories |
|||
|
|||
- `GET /api/directories/{directory_id}/children` |
|||
- `POST /api/directories` |
|||
- `POST /api/directories/{directory_id}/rename` |
|||
- `POST /api/directories/{directory_id}/move` |
|||
|
|||
## Files |
|||
|
|||
- `GET /api/files/{file_id}` |
|||
- `GET /api/files/{file_id}/download` |
|||
- `GET /api/files/{file_id}/preview` |
|||
- `GET /api/files/{file_id}/stream` |
|||
- `POST /api/files/{file_id}/rename` |
|||
- `POST /api/files/{file_id}/move` |
|||
- `DELETE /api/files/{file_id}` |
|||
- `POST /api/files/{file_id}/restore` |
|||
- `GET /api/files/recycle-bin` |
|||
|
|||
## Uploads |
|||
|
|||
Protocol endpoints: |
|||
|
|||
- `POST /files` |
|||
- `HEAD /files/{upload_id}` |
|||
- `PATCH /files/{upload_id}` |
|||
|
|||
Finalize endpoint: |
|||
|
|||
- `POST /api/uploads/{upload_id}/finalize` |
|||
|
|||
## Backends |
|||
|
|||
- `GET /api/backends` |
|||
- `POST /api/backends` |
|||
- `POST /api/backends/{backend_id}/check` |
|||
- `POST /api/backends/{backend_id}/disable` |
|||
|
|||
## Jobs |
|||
|
|||
- `GET /api/jobs` |
|||
- `GET /api/jobs/{job_id}` |
|||
- `POST /api/jobs/{job_id}/retry` |
|||
- `POST /api/jobs/run-pending` |
|||
- `POST /api/jobs/enqueue-health-checks` |
|||
- `POST /api/jobs/enqueue-full-reconcile` |
|||
|
|||
## Placement Policies |
|||
|
|||
- `GET /api/policies/placement` |
|||
- `PUT /api/policies/placement/{file_class}` |
|||
- `GET /api/policies/placement/preview` |
|||
|
|||
## Metadata Export And Recovery |
|||
|
|||
- `GET /api/exports/metadata` |
|||
- `POST /api/exports/metadata/validate` |
|||
- `GET /api/exports/metadata/integrity` |
|||
- `POST /api/exports/metadata/restore-plan` |
|||
- `POST /api/exports/metadata/import` |
|||
|
|||
Metadata import requires `confirm_replace=true` and a validation token from the |
|||
restore-plan endpoint. |
|||
|
|||
## System |
|||
|
|||
- `GET /api/system/health` |
|||
- `GET /api/system/ready` |
|||
@ -0,0 +1,122 @@ |
|||
# Architecture |
|||
|
|||
Iron is an async Python modular monolith with a React single-page Web app. |
|||
|
|||
## System Overview |
|||
|
|||
```text |
|||
Browser UI |
|||
| |
|||
FastAPI app |
|||
| |
|||
Services |
|||
| |
|||
Repositories |
|||
| |
|||
SQLite metadata database |
|||
| |
|||
Storage adapters: local, S3 |
|||
``` |
|||
|
|||
## 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 backends |
|||
|
|||
## Frontend |
|||
|
|||
Core stack: |
|||
|
|||
- Vite |
|||
- React |
|||
- TypeScript |
|||
- React Router |
|||
- TanStack Query |
|||
|
|||
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 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. |
|||
@ -1,507 +0,0 @@ |
|||
# Iron Database Schema |
|||
|
|||
## 1. Overview |
|||
|
|||
This document defines the initial SQLite schema for Iron MVP. |
|||
|
|||
Goals: |
|||
|
|||
- support a single logical file namespace |
|||
- separate logical metadata from physical storage placement |
|||
- track replicas and background jobs durably |
|||
- support `tus` resumable uploads |
|||
- keep the schema portable enough for future migration to PostgreSQL |
|||
|
|||
Conventions: |
|||
|
|||
- IDs are stored as `TEXT` |
|||
- timestamps are stored as UTC datetimes |
|||
- soft delete is preferred for logical user-facing entities in MVP |
|||
- provider-specific details belong in JSON columns only when no stable relational shape exists |
|||
|
|||
## 2. Entity Overview |
|||
|
|||
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` |
|||
|
|||
## 3. Table Definitions |
|||
|
|||
### 3.1 `users` |
|||
|
|||
Purpose: |
|||
|
|||
- local gateway login identity |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `username` TEXT NOT NULL UNIQUE |
|||
- `password_hash` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
### 3.2 `auth_sessions` |
|||
|
|||
Purpose: |
|||
|
|||
- persisted login sessions for bearer-token auth |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `user_id` TEXT NOT NULL REFERENCES `users`(`id`) |
|||
- `token_hash` TEXT NOT NULL UNIQUE |
|||
- `expires_at` DATETIME NOT NULL |
|||
- `revoked_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_auth_sessions_user_status` on (`user_id`, `revoked_at`, `expires_at`) |
|||
- unique `idx_auth_sessions_token_hash` on `token_hash` |
|||
|
|||
Notes: |
|||
|
|||
- raw session tokens should never be stored directly |
|||
- the current implementation stores a SHA-256 token hash and returns the raw bearer token only at login time |
|||
|
|||
### 3.3 `directories` |
|||
|
|||
Purpose: |
|||
|
|||
- logical folder hierarchy |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `parent_id` TEXT NULL REFERENCES `directories`(`id`) |
|||
- `name` TEXT NOT NULL |
|||
- `path_key` TEXT NOT NULL UNIQUE |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
- `deleted_at` DATETIME NULL |
|||
|
|||
Constraints: |
|||
|
|||
- unique sibling name constraint should be enforced in application logic or by an additional composite unique index later |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_directories_parent_id` on `parent_id` |
|||
- `idx_directories_path_key` on `path_key` |
|||
|
|||
### 3.4 `file_entries` |
|||
|
|||
Purpose: |
|||
|
|||
- logical files visible to users |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `directory_id` TEXT NOT NULL REFERENCES `directories`(`id`) |
|||
- `name` TEXT NOT NULL |
|||
- `mime_type` TEXT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `current_version_id` TEXT NULL |
|||
- `is_deleted` BOOLEAN NOT NULL DEFAULT 0 |
|||
- `deleted_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Constraints: |
|||
|
|||
- unique active filename per directory |
|||
|
|||
Indexes: |
|||
|
|||
- unique `idx_file_entries_directory_name` on (`directory_id`, `name`, `is_deleted`) |
|||
- `idx_file_entries_current_version_id` on `current_version_id` |
|||
- `idx_file_entries_deleted_at` on `deleted_at` |
|||
|
|||
Notes: |
|||
|
|||
- file deletion uses recycle-bin semantics in MVP |
|||
- active and deleted files may temporarily share the same logical name in one directory because the uniqueness rule only protects active entries |
|||
|
|||
### 3.5 `file_versions` |
|||
|
|||
Purpose: |
|||
|
|||
- immutable snapshots of file content |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_entry_id` TEXT NOT NULL REFERENCES `file_entries`(`id`) |
|||
- `content_hash` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `storage_layout` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- `single` |
|||
- `chunked` |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_file_versions_file_entry_id` on `file_entry_id` |
|||
- `idx_file_versions_content_hash` on `content_hash` |
|||
|
|||
### 3.5 `blobs` |
|||
|
|||
Purpose: |
|||
|
|||
- physical storage units referenced by file versions |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_version_id` TEXT NOT NULL REFERENCES `file_versions`(`id`) |
|||
- `blob_index` INTEGER NOT NULL |
|||
- `kind` TEXT NOT NULL |
|||
- `content_hash` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `logical_offset` INTEGER NOT NULL DEFAULT 0 |
|||
- `created_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- `file` |
|||
- `chunk` |
|||
- `thumbnail` |
|||
- `poster` |
|||
|
|||
Indexes: |
|||
|
|||
- unique `idx_blobs_file_version_index` on (`file_version_id`, `blob_index`) |
|||
- `idx_blobs_content_hash` on `content_hash` |
|||
|
|||
### 3.6 `blob_replicas` |
|||
|
|||
Purpose: |
|||
|
|||
- one row per physical copy of a blob on one backend |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `blob_id` TEXT NOT NULL REFERENCES `blobs`(`id`) |
|||
- `backend_id` TEXT NOT NULL REFERENCES `backends`(`id`) |
|||
- `storage_key` TEXT NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `etag` TEXT NULL |
|||
- `checksum` TEXT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `last_verified_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- `pending` |
|||
- `ready` |
|||
- `missing` |
|||
- `corrupt` |
|||
- `offline` |
|||
- `failed` |
|||
|
|||
Indexes: |
|||
|
|||
- unique `idx_blob_replicas_blob_backend` on (`blob_id`, `backend_id`) |
|||
- `idx_blob_replicas_backend_status` on (`backend_id`, `status`) |
|||
- `idx_blob_replicas_storage_key` on `storage_key` |
|||
|
|||
Current implementation status: |
|||
|
|||
- local backend writes now create `blob_replicas` rows during upload finalize |
|||
- initial persisted replica status is `ready` |
|||
|
|||
### 3.7 `backends` |
|||
|
|||
Purpose: |
|||
|
|||
- configured storage targets and their policy attributes |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `name` TEXT NOT NULL UNIQUE |
|||
- `type` TEXT NOT NULL |
|||
- `stability_class` TEXT NOT NULL |
|||
- `read_priority` INTEGER NOT NULL |
|||
- `write_priority` INTEGER NOT NULL |
|||
- `is_enabled` BOOLEAN NOT NULL DEFAULT 1 |
|||
- `config_json` TEXT NOT NULL |
|||
- `capacity_hint_bytes` INTEGER NULL |
|||
- `last_health_status` TEXT NULL |
|||
- `last_health_checked_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended `type` values: |
|||
|
|||
- `local` |
|||
- `s3` |
|||
|
|||
### 3.8 `placement_policies` |
|||
|
|||
Purpose: |
|||
|
|||
- persist file-class placement intent separately from backend rows |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_class` TEXT NOT NULL UNIQUE |
|||
- `require_local` BOOLEAN NOT NULL DEFAULT 1 |
|||
- `stable_replica_count` INTEGER NOT NULL DEFAULT 1 |
|||
- `opportunistic_replica_count` INTEGER NOT NULL DEFAULT 0 |
|||
- `preferred_backend_ids_json` TEXT NOT NULL DEFAULT `[]` |
|||
- `excluded_backend_ids_json` TEXT NOT NULL DEFAULT `[]` |
|||
- `max_non_local_size_bytes` INTEGER NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Notes: |
|||
|
|||
- the current backend persists preferred and excluded backend ids as JSON lists |
|||
- `max_non_local_size_bytes` can force large files to remain local-only even when stable backends exist |
|||
- this table is actively used by reconcile jobs and by `/api/policies/placement/preview` |
|||
- `aliyun` |
|||
- `baidu` |
|||
- `bridge` |
|||
|
|||
Recommended `stability_class` values: |
|||
|
|||
- `local` |
|||
- `stable` |
|||
- `opportunistic` |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_backends_enabled` on `is_enabled` |
|||
- `idx_backends_priority` on (`write_priority`, `read_priority`) |
|||
|
|||
Current implementation status: |
|||
|
|||
- the gateway currently bootstraps one default local backend record automatically |
|||
|
|||
### 3.8 `upload_sessions` |
|||
|
|||
Purpose: |
|||
|
|||
- durable record for `tus` upload lifecycle |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `directory_id` TEXT NULL REFERENCES `directories`(`id`) |
|||
- `filename` TEXT NULL |
|||
- `total_size_bytes` INTEGER NOT NULL |
|||
- `received_size_bytes` INTEGER NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `temp_path` TEXT NOT NULL |
|||
- `tus_upload_url` TEXT NULL |
|||
- `upload_metadata_json` TEXT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- `created` |
|||
- `uploading` |
|||
- `uploaded` |
|||
- `finalizing` |
|||
- `finalized` |
|||
- `failed` |
|||
- `expired` |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_upload_sessions_status` on `status` |
|||
- `idx_upload_sessions_updated_at` on `updated_at` |
|||
|
|||
### 3.9 `upload_session_parts` |
|||
|
|||
Purpose: |
|||
|
|||
- optional upload-part detail for resumable recovery and diagnostics |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `upload_session_id` TEXT NOT NULL REFERENCES `upload_sessions`(`id`) |
|||
- `part_number` INTEGER NOT NULL |
|||
- `byte_offset` INTEGER NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `checksum` TEXT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Indexes: |
|||
|
|||
- unique `idx_upload_session_parts_unique` on (`upload_session_id`, `part_number`) |
|||
- `idx_upload_session_parts_upload_id` on `upload_session_id` |
|||
|
|||
### 3.10 `jobs` |
|||
|
|||
Purpose: |
|||
|
|||
- durable background task queue |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `kind` TEXT NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `payload_json` TEXT NOT NULL |
|||
- `attempt_count` INTEGER NOT NULL DEFAULT 0 |
|||
- `max_attempts` INTEGER NOT NULL DEFAULT 5 |
|||
- `run_after` DATETIME NOT NULL |
|||
- `last_error` TEXT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- kinds: `replicate_blob`, `generate_thumbnail`, `verify_replica`, `repair_blob`, `health_check_backend` |
|||
- status: `queued`, `running`, `succeeded`, `failed`, `dead` |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_jobs_status_run_after` on (`status`, `run_after`) |
|||
- `idx_jobs_kind_status` on (`kind`, `status`) |
|||
|
|||
### 3.11 `preview_artifacts` |
|||
|
|||
Purpose: |
|||
|
|||
- preview resources such as thumbnails and poster images |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_version_id` TEXT NOT NULL REFERENCES `file_versions`(`id`) |
|||
- `artifact_type` TEXT NOT NULL |
|||
- `blob_id` TEXT NOT NULL REFERENCES `blobs`(`id`) |
|||
- `status` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- `thumbnail` |
|||
- `poster` |
|||
- `pdf_preview` |
|||
|
|||
Indexes: |
|||
|
|||
- unique `idx_preview_artifacts_version_type` on (`file_version_id`, `artifact_type`) |
|||
|
|||
### 3.12 `cache_entries` |
|||
|
|||
Purpose: |
|||
|
|||
- local cache state for blobs and derivatives |
|||
|
|||
Columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `blob_id` TEXT NOT NULL REFERENCES `blobs`(`id`) |
|||
- `local_path` TEXT NOT NULL |
|||
- `cache_kind` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `last_accessed_at` DATETIME NOT NULL |
|||
- `expires_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Recommended enum values: |
|||
|
|||
- cache kinds: `blob`, `preview`, `temp` |
|||
- status: `ready`, `partial`, `evicted`, `invalid` |
|||
|
|||
Indexes: |
|||
|
|||
- `idx_cache_entries_blob_id` on `blob_id` |
|||
- `idx_cache_entries_last_accessed_at` on `last_accessed_at` |
|||
- `idx_cache_entries_expires_at` on `expires_at` |
|||
|
|||
## 4. Relationship Summary |
|||
|
|||
- one `directory` has many child `directories` |
|||
- one `directory` has many `file_entries` |
|||
- one `file_entry` has many `file_versions` |
|||
- one `file_version` has many `blobs` |
|||
- one `blob` has many `blob_replicas` |
|||
- one `backend` has many `blob_replicas` |
|||
- one `upload_session` may become one `file_entry` |
|||
- one `job` targets one logical task payload |
|||
|
|||
## 5. Migration Guidance |
|||
|
|||
Recommended migration order: |
|||
|
|||
1. `users` |
|||
2. `directories` |
|||
3. `file_entries` |
|||
4. `file_versions` |
|||
5. `backends` |
|||
6. `blobs` |
|||
7. `blob_replicas` |
|||
8. `upload_sessions` |
|||
9. `upload_session_parts` |
|||
10. `jobs` |
|||
11. `placement_policies` |
|||
12. `preview_artifacts` |
|||
13. `cache_entries` |
|||
|
|||
Guidelines: |
|||
|
|||
- create foreign keys only after referenced tables exist |
|||
- add indexes in the same migration as table creation where practical |
|||
- keep enum values in application constants for SQLite MVP |
|||
|
|||
## 6. SQLite Notes |
|||
|
|||
- enable foreign keys explicitly |
|||
- use WAL mode for better concurrent read behavior |
|||
- keep transactions short around upload finalization and job claiming |
|||
- avoid long-lived write transactions during file streaming |
|||
|
|||
## 7. Future Schema Evolution |
|||
|
|||
Likely future additions: |
|||
|
|||
- `file_tags` |
|||
- `share_links` |
|||
- `device_clients` |
|||
- `sync_rules` |
|||
- `search_documents` |
|||
- `backend_metrics` |
|||
- `replica_verification_events` |
|||
|
|||
Likely future changes: |
|||
|
|||
- introduce true version history controls |
|||
- move some JSON config into typed backend-specific tables if the surface becomes stable |
|||
- expand `placement_policies` if policy shape grows beyond file-class controls, preferred/excluded backend sets, and size-aware replica caps |
|||
@ -0,0 +1,105 @@ |
|||
# Development |
|||
|
|||
This document captures the development workflow, test expectations, and UI |
|||
quality rules for Iron. |
|||
|
|||
## Setup |
|||
|
|||
```bash |
|||
UV_CACHE_DIR=.uv-cache uv venv .venv |
|||
UV_CACHE_DIR=.uv-cache uv pip install --python .venv/bin/python -e '.[dev]' |
|||
npm install |
|||
``` |
|||
|
|||
## Run Locally |
|||
|
|||
```bash |
|||
npm run build |
|||
.venv/bin/python -m uvicorn app.main:app --reload |
|||
``` |
|||
|
|||
Open: |
|||
|
|||
```text |
|||
http://127.0.0.1:8000/app |
|||
``` |
|||
|
|||
Default development credentials: |
|||
|
|||
```text |
|||
username: admin |
|||
password: changeme-iron |
|||
``` |
|||
|
|||
## Tests |
|||
|
|||
Full suite: |
|||
|
|||
```bash |
|||
.venv/bin/python -m pytest |
|||
``` |
|||
|
|||
Current expected result: |
|||
|
|||
```text |
|||
66 passed |
|||
``` |
|||
|
|||
Browser E2E: |
|||
|
|||
```bash |
|||
.venv/bin/python scripts/ui_playwright_smoke.py |
|||
``` |
|||
|
|||
Pytest E2E entry: |
|||
|
|||
```bash |
|||
.venv/bin/python -m pytest tests/e2e/test_web_ui_playwright.py |
|||
``` |
|||
|
|||
## UI Change Standard |
|||
|
|||
Any meaningful Web UI change must be validated against a real running service. |
|||
|
|||
Required workflow: |
|||
|
|||
1. build frontend assets with `npm run build` |
|||
2. run `./.venv/bin/python scripts/ui_playwright_smoke.py` |
|||
3. review screenshots in `output/playwright/` |
|||
4. fix layout, spacing, overflow, or interaction issues |
|||
5. rerun the Playwright flow |
|||
|
|||
The E2E flow currently covers: |
|||
|
|||
- login |
|||
- files page render |
|||
- create folder |
|||
- upload text file |
|||
- authenticated file download |
|||
- upload image file |
|||
- authenticated inline image preview |
|||
- search |
|||
- uploads, recycle bin, storage, and jobs page render |
|||
- browser `/api` 4xx/5xx failures during the flow |
|||
|
|||
## Runtime Artifacts |
|||
|
|||
Do not commit: |
|||
|
|||
- `.venv/` |
|||
- `.uv-cache/` |
|||
- `node_modules/` |
|||
- `output/` |
|||
- `.iron-storage/` |
|||
- `.iron-temp/` |
|||
- local databases |
|||
- Python caches |
|||
|
|||
## Documentation Rules |
|||
|
|||
- Keep `README.md` concise and user-facing. |
|||
- Keep contributor instructions in `CONTRIBUTING.md`. |
|||
- Keep coding-agent instructions in `AGENTS.md`. |
|||
- Keep deeper project docs in `docs/`. |
|||
- Use relative links in Markdown. |
|||
- Update docs when changing setup, commands, architecture, or user-visible behavior. |
|||
@ -1,233 +0,0 @@ |
|||
# Iron Engineering Handoff |
|||
|
|||
Last updated: 2026-04-15 |
|||
|
|||
## 1. What This Document Is For |
|||
|
|||
This is the fastest way for another AI or engineer to continue work on Iron without re-reading the full project history. |
|||
|
|||
Read this first, then use the other docs as references: |
|||
|
|||
- product scope: [requirements.md](/Users/bytedance/iron/docs/requirements.md:1) |
|||
- gap analysis: [mvp-status.md](/Users/bytedance/iron/docs/mvp-status.md:1) |
|||
- implementation architecture: [technical-architecture-draft.md](/Users/bytedance/iron/docs/technical-architecture-draft.md:1) |
|||
- API details: [api-design.md](/Users/bytedance/iron/docs/api-design.md:1) |
|||
- schema details: [database-schema.md](/Users/bytedance/iron/docs/database-schema.md:1) |
|||
|
|||
## 2. Current Truth |
|||
|
|||
The project is no longer architecture-only. |
|||
|
|||
It already has: |
|||
|
|||
- async FastAPI backend |
|||
- SQLite + SQLAlchemy ORM |
|||
- Alembic migrations |
|||
- local auth with persisted bearer-token sessions |
|||
- directories, files, recycle bin, rename, move |
|||
- `tus` uploads |
|||
- local backend persistence |
|||
- S3 runtime replication and remote fallback reads |
|||
- declarative reconcile jobs |
|||
- metadata export, validate, integrity, restore-plan, and guarded import |
|||
- placement policy persistence and placement preview API |
|||
- a frontend app scaffold at `/app` built with `Vite + React + TypeScript` |
|||
- product routes for files, uploads, recycle bin, storage, and jobs |
|||
- a desktop-first Web UI with file list, contextual inspector, upload queue, recycle bin, storage, and jobs surfaces |
|||
- Python Playwright E2E coverage for login, create folder, upload, authenticated download, authenticated image preview, search, and page rendering |
|||
|
|||
It now has a product-usable Web frontend foundation, but it still needs user-facing hardening before calling it a polished release. |
|||
|
|||
The most honest stage label is still: |
|||
|
|||
- `Product MVP Candidate` |
|||
|
|||
## 3. Current Verified Baseline |
|||
|
|||
Use `uv` and the local virtualenv: |
|||
|
|||
```bash |
|||
UV_CACHE_DIR=.uv-cache uv venv .venv |
|||
UV_CACHE_DIR=.uv-cache uv pip install --python .venv/bin/python -e '.[dev]' |
|||
``` |
|||
|
|||
Run tests with: |
|||
|
|||
```bash |
|||
export UV_CACHE_DIR=.uv-cache && .venv/bin/python -m pytest |
|||
``` |
|||
|
|||
Current expected result: |
|||
|
|||
- `66 passed` |
|||
|
|||
If new work changes behavior, update this number in: |
|||
|
|||
- [README.md](/Users/bytedance/iron/README.md:1) |
|||
- [mvp-status.md](/Users/bytedance/iron/docs/mvp-status.md:1) |
|||
- this file |
|||
|
|||
## 4. What Is Implemented |
|||
|
|||
### 4.1 Backend Capabilities |
|||
|
|||
- auth: |
|||
- bootstrap admin user |
|||
- login |
|||
- logout |
|||
- current user |
|||
- namespace: |
|||
- create/list directories |
|||
- mixed children listing |
|||
- file detail |
|||
- file and directory rename/move |
|||
- recycle-bin delete/restore for files |
|||
- upload: |
|||
- `tus` create/head/patch |
|||
- finalize to file metadata |
|||
- storage: |
|||
- local backend object persistence |
|||
- S3 adapter runtime path |
|||
- remote fallback read into local cache |
|||
- preview: |
|||
- image/PDF inline preview |
|||
- generic video stream through HTTP Range |
|||
- preview artifact rows and generation jobs |
|||
- ops: |
|||
- backend list/create/check/disable |
|||
- jobs list/detail/retry/run |
|||
- enqueue full reconcile |
|||
- enqueue backend health checks |
|||
- file reconcile |
|||
- recovery: |
|||
- metadata export |
|||
- metadata validate |
|||
- metadata integrity |
|||
- restore plan with validation token |
|||
- guarded metadata import |
|||
|
|||
### 4.2 Placement Controls |
|||
|
|||
This area is complete enough for backend MVP work. |
|||
|
|||
Current placement behavior supports: |
|||
|
|||
- policies by file class |
|||
- local requirement flag |
|||
- stable and opportunistic replica counts |
|||
- ordered preferred backend ids |
|||
- excluded backend ids |
|||
- optional `max_non_local_size_bytes` |
|||
- placement preview API |
|||
- reconcile jobs converging toward policy-selected targets |
|||
|
|||
Main files: |
|||
|
|||
- [app/services/policy_service.py](/Users/bytedance/iron/app/services/policy_service.py:1) |
|||
- [app/api/routes/policies.py](/Users/bytedance/iron/app/api/routes/policies.py:1) |
|||
- [tests/test_policy_routes.py](/Users/bytedance/iron/tests/test_policy_routes.py:1) |
|||
- [tests/test_placement_jobs.py](/Users/bytedance/iron/tests/test_placement_jobs.py:1) |
|||
|
|||
## 5. Main Remaining Work |
|||
|
|||
### 5.1 P0: Product Frontend |
|||
|
|||
This is the main next focus. |
|||
|
|||
Needed next: |
|||
|
|||
- deepen the new frontend foundation into a more polished daily-usable product |
|||
- improve directory navigation and breadcrumbs |
|||
- harden upload progress UX and directory targeting |
|||
- improve preview and detail-panel behavior |
|||
- refine mobile behavior and browser session handling |
|||
- extend Playwright E2E coverage as each product flow becomes real |
|||
|
|||
### 5.2 P1: Backend Hardening |
|||
|
|||
These are still useful, but they are no longer the main gating path: |
|||
|
|||
- stronger preview derivative generation |
|||
- post-restore operational tooling |
|||
- richer replica verification and repair visibility |
|||
- more sophisticated cache observability and eviction |
|||
|
|||
### 5.3 Post-MVP / Roadmap |
|||
|
|||
- Aliyun adapter |
|||
- Baidu adapter |
|||
- desktop client |
|||
- mobile client |
|||
- share links |
|||
- search |
|||
|
|||
## 6. Recommended Next Sequence |
|||
|
|||
If another AI continues from here, the recommended order is: |
|||
|
|||
1. preserve the current desktop-first drive UX and avoid reverting to dashboard-style empty panels |
|||
2. keep browser file access going through authenticated blob fetches, not naked `/api/files/...` media URLs |
|||
3. extend Playwright E2E coverage when adding preview, download, upload, or mutation flows |
|||
4. only after product hardening, return to backend polish such as richer preview derivatives |
|||
|
|||
## 7. Important Repo Realities |
|||
|
|||
These details are easy to get wrong if someone only reads the older architecture docs: |
|||
|
|||
- config is currently a lightweight cached dataclass module, not `pydantic-settings` |
|||
- the frontend source now lives in `frontend/` and builds into `app/web/dist` |
|||
- `tus` endpoints live under `/files`, outside the normal `/api` JSON namespace |
|||
- the backend uses persisted bearer tokens today |
|||
- metadata import is intentionally guarded by: |
|||
- `confirm_replace=true` |
|||
- `validation_token` from restore-plan |
|||
|
|||
## 8. Where To Look In Code |
|||
|
|||
High-signal entry points: |
|||
|
|||
- app bootstrap: [app/main.py](/Users/bytedance/iron/app/main.py:1) |
|||
- API composition: [app/api/router.py](/Users/bytedance/iron/app/api/router.py:1) |
|||
- auth: [app/services/auth_service.py](/Users/bytedance/iron/app/services/auth_service.py:1) |
|||
- files: [app/services/file_service.py](/Users/bytedance/iron/app/services/file_service.py:1) |
|||
- uploads: [app/services/upload_service.py](/Users/bytedance/iron/app/services/upload_service.py:1) |
|||
- jobs: [app/services/job_service.py](/Users/bytedance/iron/app/services/job_service.py:1) |
|||
- storage: [app/services/storage_service.py](/Users/bytedance/iron/app/services/storage_service.py:1) |
|||
- placement: [app/services/policy_service.py](/Users/bytedance/iron/app/services/policy_service.py:1) |
|||
- frontend entry: [frontend/src/app/App.tsx](/Users/bytedance/iron/frontend/src/app/App.tsx:1) |
|||
- frontend routes: [frontend/src/app/router.tsx](/Users/bytedance/iron/frontend/src/app/router.tsx:1) |
|||
- frontend API client: [frontend/src/lib/api.ts](/Users/bytedance/iron/frontend/src/lib/api.ts:1) |
|||
- frontend styles: [frontend/src/styles/app.css](/Users/bytedance/iron/frontend/src/styles/app.css:1) |
|||
- Playwright E2E: [scripts/ui_playwright_smoke.py](/Users/bytedance/iron/scripts/ui_playwright_smoke.py:1) |
|||
- pytest E2E entry: [tests/e2e/test_web_ui_playwright.py](/Users/bytedance/iron/tests/e2e/test_web_ui_playwright.py:1) |
|||
- built app entry: [app/web/dist/index.html](/Users/bytedance/iron/app/web/dist/index.html:1) |
|||
|
|||
## 9. Testing Guidance |
|||
|
|||
When continuing development: |
|||
|
|||
- keep using `uv` + `.venv` |
|||
- prefer adding tests in the same slice as each feature |
|||
- run Python Playwright for UI-affecting work |
|||
- update docs after meaningful milestone changes |
|||
- do not let README, MVP status, and actual test count drift apart |
|||
|
|||
Current test files: |
|||
|
|||
- [tests/test_auth_routes.py](/Users/bytedance/iron/tests/test_auth_routes.py:1) |
|||
- [tests/test_backend_routes.py](/Users/bytedance/iron/tests/test_backend_routes.py:1) |
|||
- [tests/test_directory_routes.py](/Users/bytedance/iron/tests/test_directory_routes.py:1) |
|||
- [tests/test_export_routes.py](/Users/bytedance/iron/tests/test_export_routes.py:1) |
|||
- [tests/test_file_routes.py](/Users/bytedance/iron/tests/test_file_routes.py:1) |
|||
- [tests/test_job_routes.py](/Users/bytedance/iron/tests/test_job_routes.py:1) |
|||
- [tests/test_placement_jobs.py](/Users/bytedance/iron/tests/test_placement_jobs.py:1) |
|||
- [tests/test_policy_routes.py](/Users/bytedance/iron/tests/test_policy_routes.py:1) |
|||
- [tests/test_system_routes.py](/Users/bytedance/iron/tests/test_system_routes.py:1) |
|||
- [tests/test_upload_routes.py](/Users/bytedance/iron/tests/test_upload_routes.py:1) |
|||
- [tests/test_web_routes.py](/Users/bytedance/iron/tests/test_web_routes.py:1) |
|||
|
|||
## 10. Suggested Handoff Prompt |
|||
|
|||
If another AI is about to continue, a good short prompt is: |
|||
|
|||
> Read `/Users/bytedance/iron/docs/handoff.md` first, treat it as the current source of truth, then continue from the frontend-first sequence unless new user instructions override it. |
|||
@ -1,473 +0,0 @@ |
|||
# Iron MVP Status |
|||
|
|||
Last updated: 2026-04-15 |
|||
|
|||
## 1. Purpose |
|||
|
|||
This document fixes one question in a concrete way: |
|||
|
|||
- what should count as Iron's **usable MVP** |
|||
- what is already implemented |
|||
- what still blocks that MVP today |
|||
|
|||
It is the live checkpoint between: |
|||
|
|||
- [requirements.md](/Users/bytedance/iron/docs/requirements.md:1) |
|||
- [technical-architecture-draft.md](/Users/bytedance/iron/docs/technical-architecture-draft.md:1) |
|||
- the actual code and tests in `app/` and `tests/` |
|||
|
|||
## 2. Current Conclusion |
|||
|
|||
The honest current answer is: |
|||
|
|||
- Iron already has a **real backend foundation**, not just design documents |
|||
- Iron now has a **browser-usable product foundation** |
|||
- the current code is best described as a **Product MVP Candidate** |
|||
|
|||
Why it is not yet a polished release: |
|||
|
|||
- the Web UI supports the core drive flows, but still needs real-user hardening and polish |
|||
- browser auth exists, but session setup, password management, and onboarding are still basic |
|||
- `local + S3` both have real runtime behavior, but advanced repair/visibility remains basic |
|||
- declarative reconcile, health-check, and preview-generation jobs now exist |
|||
- metadata export, validation, integrity checks, restore-plan, and guarded import now exist |
|||
|
|||
Priority decision after re-evaluation: |
|||
|
|||
- the remaining **true MVP blockers** are now mostly product-surface blockers |
|||
- the remaining backend work is important, but most of it is now `P1 polish / hardening`, not `P0 blocker` |
|||
|
|||
## 3. What "Usable MVP" Means |
|||
|
|||
For this project, a usable MVP should mean: |
|||
|
|||
- one person can deploy a single gateway node |
|||
- the person can log in from a browser |
|||
- the person can browse, upload, rename, move, delete, restore, download, and preview files |
|||
- the person does not need to care which backend stores a file |
|||
- at least two backend types work at runtime, not only in configuration |
|||
- the system can survive one non-primary backend failure without losing metadata control |
|||
- the system exposes enough operational visibility to inspect backend health and failed tasks |
|||
|
|||
This is still smaller than the long-term vision. It does **not** require yet: |
|||
|
|||
- desktop sync client |
|||
- mobile-native app |
|||
- public share links |
|||
- full-text search |
|||
- cross-file deduplication |
|||
- erasure coding |
|||
- advanced media indexing |
|||
|
|||
## 4. Current System Capability |
|||
|
|||
As of today, Iron already has these working backend slices. |
|||
|
|||
### 4.1 Core Platform |
|||
|
|||
- FastAPI service bootstrap |
|||
- async SQLAlchemy ORM with SQLite |
|||
- Alembic migrations |
|||
- `uv`-based local development flow |
|||
- automated test suite |
|||
|
|||
### 4.2 Namespace and Metadata |
|||
|
|||
- root directory bootstrap |
|||
- create directory |
|||
- list mixed directory and file children |
|||
- file detail lookup |
|||
- rename directory |
|||
- move directory with descendant `path_key` updates |
|||
- rename file |
|||
- move file |
|||
- recycle-bin file deletion |
|||
- restore file from recycle bin |
|||
|
|||
### 4.3 Upload and Persistence |
|||
|
|||
- `tus` upload creation |
|||
- upload offset inspection |
|||
- sequential `PATCH` upload |
|||
- finalize upload into file metadata |
|||
- persist finalized content into the default `local` backend |
|||
- create `blob` and `blob_replica` records |
|||
|
|||
### 4.4 Read Path |
|||
|
|||
- file download |
|||
- file streaming |
|||
- HTTP Range support for local persisted objects |
|||
- inline preview for images and PDFs stored in the local backend |
|||
|
|||
### 4.5 Backend Management |
|||
|
|||
- list backends |
|||
- create backend config entries for `local` and `s3` |
|||
- local backend health check |
|||
- S3 backend health check |
|||
- backend disable flow |
|||
- default local backend bootstrap |
|||
|
|||
### 4.6 Multi-Backend and Operations |
|||
|
|||
- S3 runtime replication path |
|||
- fallback reads from ready remote replicas |
|||
- remote blob cache materialization |
|||
- policy-based replication target selection |
|||
- durable SQLite job records |
|||
- in-process job polling loop |
|||
- job list/detail/retry/run APIs |
|||
- declarative file reconcile API |
|||
- backend health-check enqueue API |
|||
- full-system reconcile enqueue API |
|||
- metadata export, validate, integrity, and import APIs |
|||
- staged restore-plan workflow |
|||
- preview artifact generation jobs |
|||
- preview artifacts are exposed in file detail |
|||
|
|||
### 4.7 Test Baseline |
|||
|
|||
Current verified state: |
|||
|
|||
- `66` automated tests passing |
|||
- route coverage exists for the currently implemented backend slices |
|||
- Python Playwright E2E covers login, create folder, upload, authenticated download, authenticated inline image preview, search, and major page rendering |
|||
|
|||
### 4.8 Web UI Shell |
|||
|
|||
Implemented: |
|||
|
|||
- browser entry at `/app` |
|||
- frontend app scaffold with `Vite + React + TypeScript` |
|||
- local login form |
|||
- token-backed session bootstrap in browser storage |
|||
- files route with listing, selection, preview panel, and basic file actions |
|||
- uploads route with browser queue on top of existing `tus` flow |
|||
- recycle-bin route |
|||
- storage route |
|||
- jobs route |
|||
|
|||
Status: |
|||
|
|||
- real product foundation and MVP candidate |
|||
- still needs user hardening, mobile refinement, richer media behavior, and broader E2E coverage before a release label |
|||
|
|||
## 5. MVP Gap Matrix |
|||
|
|||
The table below is the most useful way to read the project right now. |
|||
|
|||
| Capability | MVP expectation | Current state | Gap level | |
|||
| --- | --- | --- | --- | |
|||
| Web login and session | browser-usable auth flow | login route and route guard implemented, still local-storage based | medium | |
|||
| Web file browser | daily-usable browser entry | desktop-first files workspace with list/grid, pagination, inspector, dialogs, menus | low | |
|||
| Namespace operations | browse, rename, move, delete, restore | backend API implemented | low | |
|||
| Upload flow | resumable upload from browser | browser upload route and files-page upload implemented, targeting still needs polish | medium | |
|||
| Download and preview | browser download and preview | authenticated browser download and image preview covered by E2E; PDF/video paths still need deeper coverage | medium | |
|||
| Runtime multi-backend storage | at least `local + S3` really work | `local + S3` both operate at runtime | low | |
|||
| Backend abstraction | provider records and management | partially implemented | medium | |
|||
| On-demand remote retrieval | read from another backend when local copy is absent | implemented for ready remote replicas | medium | |
|||
| Background tasks | replication, repair, health polling | declarative reconcile, health-check, and preview jobs implemented | low | |
|||
| Metadata export and restore | backup and recovery path | export, validate, integrity, restore-plan, and import implemented | low | |
|||
| Video-first experience | stream-friendly playback, poster/thumbnail | generic stream exists, preview artifact pipeline is still basic | medium | |
|||
| Cache model | explicit local cache behavior | remote-fetch cache exists, policy is still basic | medium | |
|||
| Repair visibility | inspect and retry failed work | job visibility, retry, and file reconcile enqueue are implemented | low | |
|||
| Aliyun/Baidu adapters | roadmap target backends | not implemented | roadmap gap | |
|||
|
|||
## 6. What Is Already Good Enough |
|||
|
|||
These areas should no longer be treated as blank or hypothetical: |
|||
|
|||
- backend service skeleton |
|||
- metadata model direction |
|||
- upload protocol choice |
|||
- recycle-bin semantics |
|||
- local object persistence |
|||
- local read, stream, and basic preview path |
|||
- namespace mutation rules |
|||
- baseline test discipline |
|||
|
|||
This matters because Iron is already past the "architecture-only" phase. The remaining work is now mostly about turning a solid backend core into a user-usable product slice. |
|||
|
|||
## 7. Biggest MVP Blockers |
|||
|
|||
If the question is "what prevents someone from really using Iron as their personal cloud drive today?", the answer is below. |
|||
|
|||
### 7.1 Web UI Exists And Is Now The Main Hardening Surface |
|||
|
|||
Iron now has a browser entry point with real drive workflows. |
|||
|
|||
Implemented: |
|||
|
|||
- login page |
|||
- session bootstrap |
|||
- root directory listing |
|||
- backend listing |
|||
- logout |
|||
- files workspace with desktop drive layout |
|||
- create folder, upload, rename, move, delete, download |
|||
- image preview through authenticated blob URLs |
|||
- uploads, recycle bin, storage, and jobs pages |
|||
- Playwright screenshots and E2E coverage |
|||
|
|||
Still missing: |
|||
|
|||
- backend management forms |
|||
- better browser-side session handling |
|||
- broader PDF/video preview E2E |
|||
- mobile/narrow-screen polish |
|||
- richer empty-state and operational guidance |
|||
|
|||
MVP priority: |
|||
|
|||
- `P0 hardening` |
|||
|
|||
### 7.2 Authentication Is Browser-Usable But Still Basic |
|||
|
|||
The backend has a real local auth slice, and the Web app now has a browser-facing login/session flow. |
|||
|
|||
Implemented: |
|||
|
|||
- bootstrap local admin user |
|||
- login API |
|||
- bearer-token session issuance |
|||
- current-user API |
|||
- logout API |
|||
- protected file, directory, backend, upload routes |
|||
- browser login page |
|||
- authenticated API client |
|||
- authenticated blob fetches for download and preview |
|||
|
|||
Still missing: |
|||
|
|||
- password rotation or setup UX |
|||
- clearer bootstrap credential onboarding |
|||
|
|||
MVP priority: |
|||
|
|||
- `P0 blocker`, but much smaller than before because the backend auth layer already exists |
|||
|
|||
### 7.3 Multi-Backend Runtime Is Real But Still Basic |
|||
|
|||
This area now has a real first implementation, but it is still early. |
|||
|
|||
Implemented: |
|||
|
|||
- real S3 read/write support |
|||
- remote fallback reads that can materialize a missing local blob into cache |
|||
- S3 health checks |
|||
- persisted placement policies by file class |
|||
- placement preview API for product-facing inspection |
|||
- preferred backend ordering and explicit backend exclusion |
|||
- size-aware non-local replica caps |
|||
- reconcile jobs now converge toward policy-selected targets instead of a single hardcoded target shape |
|||
|
|||
Still missing: |
|||
|
|||
- richer verification and replica selection rules |
|||
|
|||
MVP priority: |
|||
|
|||
- `P1 important` |
|||
- no longer a first-order blocker for the first usable release |
|||
|
|||
### 7.4 Background Task Engine Exists But Is Not Complete |
|||
|
|||
Iron now has a real first task engine, but it is still narrower than the intended MVP. |
|||
|
|||
Implemented: |
|||
|
|||
- declarative reconcile jobs |
|||
- file reconcile enqueue flow |
|||
- backend health-check enqueue flow |
|||
- task inspection and retry flow |
|||
- in-process polling loop |
|||
|
|||
Still missing: |
|||
|
|||
- richer preview derivative generation beyond the current basic artifact flow |
|||
|
|||
MVP priority: |
|||
|
|||
- `P1 important` |
|||
- the task substrate itself is no longer a blocker |
|||
|
|||
### 7.5 Metadata Recovery Exists And Has Basic Safety Checks |
|||
|
|||
This is now substantially addressed. |
|||
|
|||
Implemented: |
|||
|
|||
- export command or API |
|||
- validation API for metadata snapshots |
|||
- integrity check API for live runtime state |
|||
- restore-plan dry-run workflow |
|||
- import/restore API for metadata snapshots |
|||
- restore-triggered follow-up reconcile and health-check jobs |
|||
|
|||
Still missing: |
|||
|
|||
- richer post-restore operational tooling |
|||
|
|||
MVP priority: |
|||
|
|||
- `P1 important` |
|||
- the restore contract already exists; remaining work is hardening |
|||
|
|||
## 8. Priority Reset |
|||
|
|||
After re-evaluating the current repository, the most useful classification is: |
|||
|
|||
### 8.1 P0: Must Finish Before Release Label |
|||
|
|||
- harden Web UI flows with Playwright-backed regression |
|||
- browser-facing session UX beyond local-storage basics |
|||
- broader PDF/video/download E2E coverage |
|||
|
|||
### 8.2 P1: Should Finish Immediately Before or After MVP Cut |
|||
|
|||
- stronger preview derivative generation |
|||
- post-restore operational hardening and checks |
|||
|
|||
### 8.3 P2: Important But No Longer MVP-Critical |
|||
|
|||
- Aliyun backend |
|||
- Baidu backend |
|||
- richer cache policy |
|||
- stronger replica verification sophistication |
|||
- advanced media workflows beyond current preview artifacts |
|||
|
|||
## 9. Secondary Gaps |
|||
|
|||
These do not block the first shippable MVP as hard as the items above, but they still matter. |
|||
|
|||
### 9.1 Media Experience Is Only Basic |
|||
|
|||
Current state: |
|||
|
|||
- image preview works |
|||
- PDF preview works |
|||
- generic video stream works through HTTP Range |
|||
- preview artifacts are tracked and generated through background jobs |
|||
|
|||
Still missing: |
|||
|
|||
- richer thumbnails |
|||
- richer video posters |
|||
- better unsupported-codec fallback behavior |
|||
|
|||
### 9.2 Cache Behavior Is Not Yet a Product Feature |
|||
|
|||
The architecture talks about on-demand retrieval and local caching, but current runtime behavior does not yet expose a real cache policy. |
|||
|
|||
Still missing: |
|||
|
|||
- explicit cache store |
|||
- retention policy |
|||
- eviction policy |
|||
- cache observability |
|||
|
|||
### 9.3 Consumer Cloud Backends Are Still Roadmap Work |
|||
|
|||
Aliyun and Baidu remain important to the long-term goal, but they should be treated as **post-first-MVP** unless they become easier than S3 in practice. |
|||
|
|||
## 10. Recommended MVP Cutline |
|||
|
|||
To avoid drifting scope, the recommended first **product-usable MVP** should be defined as: |
|||
|
|||
### 10.1 Must Have |
|||
|
|||
- local authentication |
|||
- Web UI for file browsing and basic backend management |
|||
- `tus` upload from the browser |
|||
- upload, rename, move, delete, restore, download |
|||
- image and PDF preview |
|||
- video playback through range-capable gateway streaming |
|||
- `local` backend runtime support |
|||
- `S3` backend runtime support |
|||
- one policy-driven placement flow with: |
|||
- file-class placement rules |
|||
- preferred and excluded backend controls |
|||
- local plus optional non-local replicas |
|||
- backend health check visibility |
|||
- metadata export command or API |
|||
- one repair or retry path for failed replicas |
|||
|
|||
### 10.2 Can Wait Until After MVP |
|||
|
|||
- Aliyun runtime adapter |
|||
- Baidu runtime adapter |
|||
- thumbnail/poster generation pipeline |
|||
- richer cache intelligence |
|||
- share links |
|||
- search |
|||
- desktop client shell |
|||
- mobile app shell |
|||
|
|||
## 11. Stage Labels |
|||
|
|||
To keep internal communication honest, use these labels: |
|||
|
|||
### 11.1 Current Stage |
|||
|
|||
`Product MVP Candidate` |
|||
|
|||
Meaning: |
|||
|
|||
- backend APIs exist |
|||
- local auth exists |
|||
- local persistence works |
|||
- core file lifecycle works |
|||
- browser product flows exist and are E2E-tested |
|||
- still needs polish, hardening, and more coverage before release |
|||
|
|||
### 11.2 Target Next Stage |
|||
|
|||
`Product MVP` |
|||
|
|||
Meaning: |
|||
|
|||
- browser-usable |
|||
- authenticated |
|||
- local + S3 both operational |
|||
- at least one simple replication flow |
|||
- metadata export and basic repair visibility |
|||
|
|||
### 11.3 Later Stage |
|||
|
|||
`Multi-Backend Personal Drive` |
|||
|
|||
Meaning: |
|||
|
|||
- consumer cloud backends join the runtime pool |
|||
- remote fallback retrieval works |
|||
- background orchestration is richer |
|||
- media workflows are stronger |
|||
|
|||
## 12. Recommended Gap-Closing Order |
|||
|
|||
If the goal is to reach the first usable MVP with the shortest path, the order should be: |
|||
|
|||
1. harden the current browser product flows through Playwright-backed regression |
|||
2. add deeper PDF/video preview and download coverage |
|||
3. deepen browser session handling on top of the current auth backend |
|||
4. improve preview derivative generation and post-restore hardening |
|||
5. refine operational pages based on real user tasks |
|||
6. add the first consumer-cloud backend |
|||
|
|||
## 13. Final Assessment |
|||
|
|||
The most accurate one-line summary today is: |
|||
|
|||
> Iron has a credible backend and a browser-usable Web product foundation; the next work is hardening and polish. |
|||
|
|||
The shortest path to changing that is not "more backend breadth everywhere". It is: |
|||
|
|||
- browser session hardening |
|||
- deeper Web UI regression coverage |
|||
- stronger media and restore hardening |
|||
- repair and restore |
|||
|
|||
For implementation sequencing and repo-level handoff notes, see [handoff.md](/Users/bytedance/iron/docs/handoff.md:1). |
|||
|
|||
Once those land, Iron can honestly be called a first usable personal cloud-drive MVP. |
|||
@ -0,0 +1,69 @@ |
|||
# Product |
|||
|
|||
Iron is a self-hosted personal cloud drive gateway. The product goal is to give |
|||
one person a familiar browser drive experience while keeping storage placement, |
|||
repair, and metadata ownership under their control. |
|||
|
|||
## Current Stage |
|||
|
|||
Iron is a **Product MVP Candidate**. |
|||
|
|||
Implemented: |
|||
|
|||
- local authentication and browser login |
|||
- file browser with folders, search, sort, pagination, and an inspector panel |
|||
- create folder, upload, rename, move, delete, restore, download, and image preview |
|||
- uploads, recycle bin, storage, and jobs pages |
|||
- local backend persistence |
|||
- S3 runtime replication and remote fallback reads |
|||
- placement policies and reconcile jobs |
|||
- metadata export, validate, integrity, restore-plan, and guarded import |
|||
- Python Playwright E2E coverage for the core browser flow |
|||
|
|||
Still needs hardening before a polished release: |
|||
|
|||
- better browser session and bootstrap credential UX |
|||
- deeper PDF/video preview coverage |
|||
- richer preview derivative generation |
|||
- stronger post-restore and repair visibility |
|||
- mobile and narrow-screen refinement |
|||
|
|||
## MVP Cutline |
|||
|
|||
A first usable MVP should let one person: |
|||
|
|||
- deploy a single gateway node |
|||
- log in from a browser |
|||
- browse, upload, preview, download, rename, move, delete, and restore files |
|||
- use local storage and at least one remote backend |
|||
- inspect backend health and failed work |
|||
- export and validate metadata for recovery |
|||
|
|||
Not required for the first MVP: |
|||
|
|||
- desktop sync client |
|||
- mobile native app |
|||
- public share links |
|||
- full-text search |
|||
- cross-file deduplication |
|||
- erasure coding |
|||
- advanced media indexing |
|||
|
|||
## Roadmap |
|||
|
|||
Near-term: |
|||
|
|||
- harden Web UI flows with Playwright-backed regression |
|||
- improve session management and onboarding |
|||
- expand PDF/video preview tests |
|||
- improve upload targeting and progress feedback |
|||
- refine storage and jobs pages around real user tasks |
|||
|
|||
Later: |
|||
|
|||
- Aliyun and Baidu adapters |
|||
- richer cache policy |
|||
- share links |
|||
- desktop and mobile clients |
|||
- stronger media workflows |
|||
- advanced repair orchestration |
|||
@ -1,397 +0,0 @@ |
|||
# Iron Requirements |
|||
|
|||
## 1. Product Overview |
|||
|
|||
`Iron` is a personal cloud drive system built around a self-hosted `gateway` service. |
|||
|
|||
Users access a unified file space through a Web application in the first phase. The gateway manages metadata, local cache, upload/download pipelines, preview streaming, and data placement across multiple storage backends. |
|||
|
|||
The product goal is not to be a backup tool first. It is a daily-use personal drive focused on: |
|||
|
|||
- ease of use |
|||
- resistance to storage provider failure |
|||
- low storage cost |
|||
- optional privacy protections |
|||
|
|||
The system should allow storage across a mix of: |
|||
|
|||
- Baidu Netdisk |
|||
- Aliyun Drive |
|||
- S3-compatible object storage |
|||
- local directories |
|||
|
|||
The long-term vision is to expose the same core capabilities to desktop and mobile clients, while keeping storage control and metadata ownership in the user's hands. |
|||
|
|||
## 2. Product Goals |
|||
|
|||
### 2.1 Primary Goals |
|||
|
|||
- Provide a single virtual drive space across multiple heterogeneous storage backends. |
|||
- Support daily file management, not only backup and restore. |
|||
- Allow large media files and documents to coexist in one product. |
|||
- Support on-demand cloud retrieval so files do not need to be fully cached locally. |
|||
- Support preview-first workflows, especially for photos, videos, and PDFs. |
|||
- Keep system-critical metadata under user control instead of delegating it to any one storage vendor. |
|||
- Allow unstable or free providers to participate as secondary or cold-tier storage. |
|||
|
|||
### 2.2 Priority Order |
|||
|
|||
1. Ease of use |
|||
2. Resistance to provider shutdown or lock-in |
|||
3. Low cost |
|||
4. Privacy and encryption |
|||
|
|||
## 3. Target Users and Usage Context |
|||
|
|||
### 3.1 Primary User |
|||
|
|||
- a single user or household |
|||
- has one always-on host running the gateway |
|||
- accesses files from PCs and phones in a home network, with possible future remote access |
|||
|
|||
### 3.2 Main Data Types |
|||
|
|||
- large video files |
|||
- large photo libraries |
|||
- documents |
|||
- PDFs |
|||
- mixed personal archives |
|||
|
|||
### 3.3 Usage Style |
|||
|
|||
- browse files from a Web UI |
|||
- upload from browser or client |
|||
- preview before download when possible |
|||
- let the system decide actual storage placement |
|||
- tolerate heavier local infrastructure if it improves experience |
|||
|
|||
## 4. Product Principles |
|||
|
|||
- Users see one logical drive, not multiple backend silos. |
|||
- Storage placement is system-managed, not user-managed in normal workflows. |
|||
- Metadata must remain recoverable even if one backend becomes unavailable. |
|||
- Stable backends and unstable backends must be treated differently by policy. |
|||
- Media experience should be optimized explicitly, not treated as a side effect of generic file storage. |
|||
- The MVP should prefer understandable replication over complex erasure coding. |
|||
|
|||
## 5. Scope Definition |
|||
|
|||
### 5.1 In Scope for the Product |
|||
|
|||
- file browsing and directory navigation |
|||
- upload and download |
|||
- delete, rename, move, copy |
|||
- on-demand retrieval from remote storage |
|||
- local cache management |
|||
- image preview |
|||
- video preview via streaming |
|||
- PDF preview |
|||
- multi-backend storage placement |
|||
- backend health monitoring |
|||
- metadata backup and recovery tooling |
|||
- background jobs for sync, repair, and replication |
|||
|
|||
### 5.2 Out of Scope for MVP |
|||
|
|||
- real-time collaborative editing |
|||
- multi-tenant enterprise permissions |
|||
- public sharing links with strong abuse controls |
|||
- fully offline-first desktop synchronization |
|||
- true distributed peer-to-peer storage nodes |
|||
- POSIX-complete filesystem semantics |
|||
- erasure coding as a required storage strategy |
|||
- full-text OCR and semantic search |
|||
|
|||
## 6. System Context |
|||
|
|||
### 6.1 Phase 1 Deployment Model |
|||
|
|||
- one self-hosted gateway process |
|||
- one Web client |
|||
- one SQLite database |
|||
- one local cache directory |
|||
- multiple configured storage backends |
|||
|
|||
### 6.2 Future Deployment Model |
|||
|
|||
- gateway remains the control plane |
|||
- desktop clients may add richer local sync and mount capabilities |
|||
- mobile clients may provide browsing, preview, upload, and camera ingestion |
|||
- metadata database may move from SQLite to a networked database if needed |
|||
|
|||
## 7. Functional Requirements |
|||
|
|||
### 7.1 File Space and Navigation |
|||
|
|||
- The system must expose a single hierarchical directory tree. |
|||
- The system must allow creating, renaming, moving, and deleting directories. |
|||
- The system must allow listing files with pagination and sorting. |
|||
- The system must show key metadata including name, size, type, timestamps, and cache status. |
|||
- The system must decouple logical path from backend storage location. |
|||
|
|||
### 7.2 Upload |
|||
|
|||
- The system must support browser-based upload. |
|||
- The system must support resumable upload at least at the gateway boundary. |
|||
- The system must support large-file upload without requiring full in-memory buffering. |
|||
- The system must classify uploaded files by size and media type to choose storage strategy. |
|||
- The system must allow asynchronous replication after initial successful ingestion. |
|||
|
|||
### 7.3 Download |
|||
|
|||
- The system must allow direct file download from the Web UI. |
|||
- The system must support on-demand fetch from remote backends if data is not in local cache. |
|||
- The system must expose download progress and failure states. |
|||
|
|||
### 7.4 Preview |
|||
|
|||
- The system must support image preview. |
|||
- The system must support PDF preview. |
|||
- The system must support video preview through HTTP range-compatible streaming. |
|||
- The system should generate thumbnails for common media types. |
|||
- The system should avoid full-file fetch when previewing large video files if the backend layout permits partial reads. |
|||
|
|||
### 7.5 Cache Management |
|||
|
|||
- The gateway must maintain a local cache for hot files and preview artifacts. |
|||
- The system must track cache state separately from logical file state. |
|||
- The system must support configurable cache eviction policies. |
|||
- The system should allow pinning specific files or directories for local retention in future versions. |
|||
|
|||
### 7.6 Multi-Backend Storage |
|||
|
|||
- The system must support multiple backend types at once. |
|||
- The system must support backend policies such as `stable`, `opportunistic`, and `local`. |
|||
- The system must support at least one primary copy and optional secondary copies. |
|||
- The system must track where each object or file replica is stored. |
|||
- The system must detect backend unavailability and mark replicas accordingly. |
|||
|
|||
### 7.7 Metadata and Recovery |
|||
|
|||
- The system must maintain its own metadata database independent of backend-native directory layouts. |
|||
- The system must support export and backup of metadata. |
|||
- The system must support integrity verification between metadata records and backend objects. |
|||
- The system must support repair jobs that recreate missing replicas when another valid replica exists. |
|||
|
|||
### 7.8 Jobs and Operations |
|||
|
|||
- The system must support background jobs for uploads, replication, thumbnail generation, and repair. |
|||
- The system must expose job status in the UI or API. |
|||
- The system must retain structured logs for user-visible failures. |
|||
|
|||
### 7.9 Backend Management |
|||
|
|||
- The system must allow adding, updating, disabling, and deleting backend configurations. |
|||
- The system must display backend status, capacity hints if available, and last health-check result. |
|||
- The system should support backend weighting and placement rules. |
|||
|
|||
## 8. Non-Functional Requirements |
|||
|
|||
### 8.1 Usability |
|||
|
|||
- A user should not need to understand backend topology during normal file operations. |
|||
- Common file operations should be understandable from a single Web interface. |
|||
- Preview should be first-class for photo, video, and PDF content. |
|||
|
|||
### 8.2 Reliability |
|||
|
|||
- Metadata must not depend on a single unstable third-party backend. |
|||
- The system should tolerate temporary backend outages and recover later. |
|||
- Background jobs must be restart-safe. |
|||
|
|||
### 8.3 Performance |
|||
|
|||
- Listing a directory from metadata should not require live backend enumeration. |
|||
- Upload and download pipelines should stream rather than fully buffer large files. |
|||
- Preview start latency for cached or stable-backend media should be low enough for normal personal use. |
|||
|
|||
### 8.4 Extensibility |
|||
|
|||
- Backend integrations must be pluggable. |
|||
- Data model must allow migration from SQLite to another relational database. |
|||
- API design must allow future desktop and mobile clients. |
|||
|
|||
### 8.5 Security |
|||
|
|||
- Authentication is required for the Web UI and APIs. |
|||
- Secrets for backend credentials must not be stored in plaintext in user-facing logs. |
|||
- Encryption should be supported in design even if not mandatory for every backend path in MVP. |
|||
|
|||
## 9. Storage Model Strategy |
|||
|
|||
### 9.1 MVP Strategy |
|||
|
|||
- documents and small files are stored as whole-file objects |
|||
- photos are stored as whole-file originals plus generated thumbnails |
|||
- large videos may use chunked storage if needed for upload resilience and streamability |
|||
- replication is preferred over erasure coding |
|||
|
|||
### 9.2 Future Strategy |
|||
|
|||
- content-addressed chunks for large files |
|||
- optional object packing for small files |
|||
- deduplication across identical content |
|||
- tier-aware migration policies |
|||
- optional erasure coding for selected backend groups |
|||
|
|||
## 10. Backend Policy Model |
|||
|
|||
Each backend should have policy metadata, for example: |
|||
|
|||
- backend type |
|||
- stability class |
|||
- cost class |
|||
- write priority |
|||
- read priority |
|||
- capacity hint |
|||
- health status |
|||
- credential state |
|||
|
|||
Suggested policy classes: |
|||
|
|||
- `stable`: trusted for primary storage, such as S3 or a managed local directory on a reliable host |
|||
- `opportunistic`: useful for secondary replicas or cold storage, such as free consumer cloud drives |
|||
- `local`: fast cache-adjacent storage on the gateway host |
|||
|
|||
## 11. MVP Definition |
|||
|
|||
### 11.1 MVP Objective |
|||
|
|||
Deliver a working single-user personal cloud drive that feels usable every day through a Web UI, with support for multi-backend storage, on-demand file retrieval, and media preview. |
|||
|
|||
### 11.2 MVP Feature Set |
|||
|
|||
- Web authentication |
|||
- file and directory browsing |
|||
- upload, download, rename, move, delete |
|||
- backend management for local directory, S3, Aliyun Drive, and Baidu Netdisk |
|||
- SQLite metadata store |
|||
- local cache directory |
|||
- background job queue inside the gateway process |
|||
- image preview and thumbnail generation |
|||
- PDF preview |
|||
- video preview through range-capable gateway streaming |
|||
- replica tracking |
|||
- backend health checks |
|||
- metadata export |
|||
- repair job for missing replicas |
|||
|
|||
### 11.3 MVP Constraints |
|||
|
|||
- single-user only |
|||
- one gateway node only |
|||
- no desktop sync client yet |
|||
- no mobile-native app yet |
|||
- no public share links |
|||
- no full-text search |
|||
- no cross-file deduplication requirement |
|||
- no erasure coding requirement |
|||
|
|||
### 11.4 MVP Success Criteria |
|||
|
|||
- A user can upload files and browse them without caring which backend stores them. |
|||
- A user can preview photos, PDFs, and many common videos from the browser. |
|||
- A user can survive loss of one configured secondary backend without losing metadata control. |
|||
- A user can inspect and retry failed background tasks. |
|||
- A user can back up metadata and recover system state onto a new gateway host. |
|||
|
|||
Current implementation status: |
|||
|
|||
- see [mvp-status.md](/Users/bytedance/iron/docs/mvp-status.md:1) for the live gap analysis against this MVP definition |
|||
- the current repository should be described as a `Product MVP Candidate`, not yet a polished release |
|||
- after re-evaluation, the main remaining `P0` items are Web UI and browser-facing auth/session UX |
|||
- the backend now has persisted placement policy controls for file classes, preferred/excluded backends, and size-aware non-local replica caps |
|||
- most remaining backend work has moved into `P1 hardening` |
|||
|
|||
## 12. End-State Vision |
|||
|
|||
### 12.1 Product Vision |
|||
|
|||
Iron becomes a full personal storage control plane for heterogeneous storage providers, with one logical namespace, rich media workflows, policy-driven placement, and resilient metadata ownership. |
|||
|
|||
### 12.2 End-State Capabilities |
|||
|
|||
- Web, desktop, and mobile clients |
|||
- remote access support |
|||
- selective offline sync |
|||
- folder pinning |
|||
- advanced media indexing and timeline views |
|||
- content deduplication |
|||
- optional end-to-end encryption modes |
|||
- policy-based lifecycle management |
|||
- automatic migration between hot, warm, and cold tiers |
|||
- stronger repair and self-healing workflows |
|||
- share links and fine-grained permissions |
|||
- import and migration tools from common cloud drives |
|||
- optional mount support on desktop systems |
|||
|
|||
## 13. Version Roadmap |
|||
|
|||
### 13.1 V0: Foundation |
|||
|
|||
- repository setup |
|||
- gateway skeleton |
|||
- metadata schema |
|||
- local backend |
|||
- basic Web UI shell |
|||
|
|||
Current status: |
|||
|
|||
- mostly achieved for backend foundation |
|||
- a browser-usable Web UI now exists, but it still needs real-user hardening, broader E2E coverage, and polish |
|||
|
|||
### 13.2 V1: MVP |
|||
|
|||
- file operations |
|||
- local cache |
|||
- S3 backend |
|||
- Aliyun backend |
|||
- Baidu backend |
|||
- preview pipeline |
|||
- jobs and repair |
|||
|
|||
Current interpretation: |
|||
|
|||
- the first shippable V1 should prioritize `auth + Web UI + local + S3 + simple replication + metadata export` |
|||
- the backend side of `local + S3 + simple replication + metadata recovery contract` is already largely in place |
|||
- Aliyun and Baidu remain in the roadmap, but are not required to call the first public version a usable MVP |
|||
|
|||
### 13.3 V2: Usability Expansion |
|||
|
|||
- better backend policies |
|||
- desktop client shell |
|||
- remote access hardening |
|||
- richer media views |
|||
- pinning and offline support |
|||
|
|||
### 13.4 V3: Advanced Storage Intelligence |
|||
|
|||
- deduplication |
|||
- packed small-object storage |
|||
- lifecycle movement |
|||
- stronger repair orchestration |
|||
- optional erasure-coded backend groups |
|||
|
|||
## 14. Risks and Product Assumptions |
|||
|
|||
### 14.1 Assumptions |
|||
|
|||
- The user accepts a heavy local gateway service. |
|||
- Free or consumer cloud backends may be unstable and are therefore not trusted as the only source of critical metadata. |
|||
- Web-first access is sufficient for MVP. |
|||
|
|||
### 14.2 Risks |
|||
|
|||
- Consumer cloud providers may change APIs, rate limits, or anti-abuse rules. |
|||
- Preview latency may be inconsistent for files that only exist on slow or unstable backends. |
|||
- Browser upload behavior for very large files may require resumable protocols early. |
|||
- Media streaming behavior can vary by codec and container format. |
|||
|
|||
## 15. Open Questions for Technical Design |
|||
|
|||
- What auth model should the first gateway use: simple local account, reverse-proxy auth, or pluggable auth? |
|||
- Should large video files use chunking from day one, or only after file size thresholds are exceeded? |
|||
- Should backend adapters be implemented natively or through an abstraction layer such as rclone-compatible gateways? |
|||
- How should local cache quotas and eviction policies be tuned? |
|||
- What metadata export format should be treated as the recovery contract? |
|||
- How much encryption should be mandatory in MVP versus optional by backend policy? |
|||
@ -1,874 +0,0 @@ |
|||
# Iron Technical Architecture Draft |
|||
|
|||
## 1. Design Goals |
|||
|
|||
This draft translates the product requirements into an implementation-oriented architecture for the first development phase. |
|||
|
|||
The design aims to: |
|||
|
|||
- support a Web-first product with a self-hosted gateway |
|||
- keep the codebase simple enough for rapid iteration |
|||
- isolate backend-specific complexity behind adapters |
|||
- use SQLite first without blocking future database migration |
|||
- optimize for media preview and daily file operations |
|||
|
|||
## 2. Recommended MVP Technical Stack |
|||
|
|||
## 2.1 Backend |
|||
|
|||
Recommended: |
|||
|
|||
- language: `Python` |
|||
- HTTP framework: `FastAPI` |
|||
- data access: `SQLAlchemy 2.0 ORM` |
|||
- migrations: `Alembic` |
|||
- schema validation: `Pydantic v2` |
|||
- background jobs: in-process worker pool backed by database job records |
|||
- object hashing: standard SHA-256 |
|||
- config: env-driven settings via a small cached settings module |
|||
|
|||
Why: |
|||
|
|||
- Python fits rapid iteration well and has a strong ecosystem for Web APIs, file tooling, storage SDKs, and media processing. |
|||
- `FastAPI` provides typed request and response models, automatic OpenAPI generation, and a clean async-friendly API layer. |
|||
- MVP is a single-node gateway, so Python is a good fit as long as upload, download, and preview paths are implemented with async streaming semantics instead of full buffering. |
|||
- The architecture should keep storage I/O and worker logic explicit so hot paths remain understandable and optimizable. |
|||
|
|||
## 2.2 Frontend |
|||
|
|||
Recommended: |
|||
|
|||
- framework: `React` with `Next.js` App Router or `Vite + React` |
|||
- UI library: minimal component primitives such as `shadcn/ui` or `Radix UI` |
|||
- data fetching: `TanStack Query` |
|||
- video and file preview: native browser capabilities first |
|||
|
|||
Recommendation between the two: |
|||
|
|||
- choose `Vite + React` if the Web app is a pure SPA against the gateway API |
|||
- choose `Next.js` only if server-rendered routing or later integrated auth flows are clearly desired |
|||
|
|||
For this project, the current recommendation is: |
|||
|
|||
- `Vite + React` |
|||
|
|||
Reason: |
|||
|
|||
- the gateway already owns the API |
|||
- the app is operational rather than content-heavy |
|||
- simpler deployment and fewer moving parts for MVP |
|||
|
|||
## 2.3 Storage Integrations |
|||
|
|||
Recommended strategy: |
|||
|
|||
- implement a common backend adapter interface in the gateway |
|||
- use native SDKs when stable and practical |
|||
- explicitly allow a bridge adapter layer when consumer cloud providers are unstable or poorly documented |
|||
- keep bridge usage behind the same storage adapter interface so the rest of the system stays readable |
|||
|
|||
Proposed initial adapter strategy: |
|||
|
|||
- local directory: native file operations |
|||
- S3: AWS SDK compatible implementation |
|||
- Aliyun Drive: adapter with bridge mode support |
|||
- Baidu Netdisk: adapter with bridge mode support |
|||
|
|||
Important note: |
|||
|
|||
- consumer cloud providers are the highest churn part of the system |
|||
- keep their adapters in isolated packages and do not let provider-specific concepts leak into core domain models |
|||
- bridge mode is preferred over contaminating core services with provider-specific protocol quirks |
|||
|
|||
## 3. System Architecture |
|||
|
|||
```text |
|||
Browser |
|||
| |
|||
v |
|||
Web UI |
|||
| |
|||
v |
|||
Gateway API |
|||
| |
|||
+--> Auth Module |
|||
+--> File Service |
|||
+--> Preview Service |
|||
+--> Backend Service |
|||
+--> Job Service |
|||
| |
|||
+--> Metadata Repository (SQLite) |
|||
+--> Cache Manager (local disk) |
|||
+--> Storage Engine |
|||
| |
|||
+--> Placement Planner |
|||
+--> Transfer Manager |
|||
+--> Replica Manager |
|||
+--> Backend Adapters |
|||
|- Local |
|||
|- S3 |
|||
|- Aliyun |
|||
|- Baidu |
|||
``` |
|||
|
|||
## 4. Layering Recommendation |
|||
|
|||
Use a layered async modular monolith for MVP. |
|||
|
|||
Suggested top-level structure: |
|||
|
|||
```text |
|||
/app |
|||
/api |
|||
/core |
|||
/domain |
|||
/services |
|||
/repositories |
|||
/models |
|||
/schemas |
|||
/adapters |
|||
/db |
|||
/storage |
|||
/jobs |
|||
/preview |
|||
/cache |
|||
/placement |
|||
/workers |
|||
/utils |
|||
/alembic |
|||
/scripts |
|||
/tests |
|||
/web |
|||
/docs |
|||
``` |
|||
|
|||
Alternative package layout if you prefer stricter layering: |
|||
|
|||
```text |
|||
/app |
|||
/config |
|||
/domain |
|||
/service |
|||
/repository |
|||
/adapter |
|||
/http |
|||
/db |
|||
/storage |
|||
/job |
|||
/preview |
|||
/cache |
|||
/placement |
|||
``` |
|||
|
|||
Layer responsibilities: |
|||
|
|||
- `domain`: core entities, enums, policies, service contracts |
|||
- `services`: business orchestration such as upload, move, preview, repair |
|||
- `repositories`: persistence operations over SQLite |
|||
- `models`: SQLAlchemy ORM models |
|||
- `schemas`: API request and response models |
|||
- `adapter/db`: SQLite implementations |
|||
- `adapter/storage`: backend-specific storage adapters |
|||
- `api`: FastAPI routers, dependencies, and HTTP entrypoints |
|||
- `jobs`: durable job definitions and scheduling logic |
|||
- `cache`: local cache and preview artifact management |
|||
- `placement`: backend selection and replication policy logic |
|||
|
|||
This keeps the codebase simple and still allows later extraction. |
|||
|
|||
Async design rules: |
|||
|
|||
- API handlers must be async. |
|||
- Repository methods should be async-facing. |
|||
- Backend adapters should expose async APIs. |
|||
- Blocking SDKs or filesystem-heavy operations must be isolated behind explicit threadpool boundaries. |
|||
- No request path should rely on hidden blocking I/O in utility code. |
|||
|
|||
## 5. Core Domain Model |
|||
|
|||
The system should not model files as mere backend paths. Use stable IDs. |
|||
|
|||
Core entities: |
|||
|
|||
- `User` |
|||
- `Directory` |
|||
- `FileEntry` |
|||
- `FileVersion` |
|||
- `Blob` |
|||
- `BlobReplica` |
|||
- `Backend` |
|||
- `UploadSession` |
|||
- `Job` |
|||
- `PreviewArtifact` |
|||
- `CacheEntry` |
|||
|
|||
### 5.1 Entity Semantics |
|||
|
|||
- `Directory`: logical folder node in the virtual filesystem |
|||
- `FileEntry`: logical file identity tied to a path parent and display name |
|||
- `FileVersion`: immutable content snapshot of a file entry |
|||
- `Blob`: the stored binary unit, whole-file or chunk object |
|||
- `BlobReplica`: one physical copy of a blob on one backend |
|||
- `Backend`: configured storage target and its policy metadata |
|||
- `PreviewArtifact`: thumbnail, poster frame, or derivative preview asset |
|||
- `CacheEntry`: local materialization status for blobs or preview artifacts |
|||
|
|||
This separation matters because: |
|||
|
|||
- rename and move should not create a new file identity |
|||
- future version history should be possible |
|||
- one logical file may map to multiple blobs |
|||
- one blob may have multiple replicas |
|||
|
|||
## 6. SQLite Schema Draft |
|||
|
|||
Below is the recommended MVP schema direction. Naming can still change, but the concepts should remain stable. |
|||
|
|||
### 6.1 `users` |
|||
|
|||
Purpose: |
|||
|
|||
- local authentication identity for MVP |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `username` TEXT NOT NULL UNIQUE |
|||
- `password_hash` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
### 6.2 `directories` |
|||
|
|||
Purpose: |
|||
|
|||
- logical folder tree |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `parent_id` TEXT NULL |
|||
- `name` TEXT NOT NULL |
|||
- `path_key` TEXT NOT NULL UNIQUE |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
- `deleted_at` DATETIME NULL |
|||
|
|||
Notes: |
|||
|
|||
- `path_key` is a normalized path index for fast lookups |
|||
- root directory can be a special fixed row |
|||
|
|||
### 6.3 `file_entries` |
|||
|
|||
Purpose: |
|||
|
|||
- logical file objects visible in the namespace |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `directory_id` TEXT NOT NULL |
|||
- `name` TEXT NOT NULL |
|||
- `mime_type` TEXT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `current_version_id` TEXT NOT NULL |
|||
- `is_deleted` BOOLEAN NOT NULL DEFAULT 0 |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
- UNIQUE (`directory_id`, `name`) |
|||
|
|||
### 6.4 `file_versions` |
|||
|
|||
Purpose: |
|||
|
|||
- immutable content version records |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_entry_id` TEXT NOT NULL |
|||
- `content_hash` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `storage_layout` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
|
|||
Suggested `storage_layout` values: |
|||
|
|||
- `single` |
|||
- `chunked` |
|||
|
|||
### 6.5 `blobs` |
|||
|
|||
Purpose: |
|||
|
|||
- binary storage units |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_version_id` TEXT NOT NULL |
|||
- `blob_index` INTEGER NOT NULL |
|||
- `kind` TEXT NOT NULL |
|||
- `content_hash` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `logical_offset` INTEGER NOT NULL DEFAULT 0 |
|||
- `created_at` DATETIME NOT NULL |
|||
|
|||
Suggested `kind` values: |
|||
|
|||
- `file` |
|||
- `chunk` |
|||
- `thumbnail` |
|||
- `poster` |
|||
|
|||
### 6.6 `blob_replicas` |
|||
|
|||
Purpose: |
|||
|
|||
- track every physical copy |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `blob_id` TEXT NOT NULL |
|||
- `backend_id` TEXT NOT NULL |
|||
- `storage_key` TEXT NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `etag` TEXT NULL |
|||
- `checksum` TEXT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `last_verified_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Suggested `status` values: |
|||
|
|||
- `pending` |
|||
- `ready` |
|||
- `missing` |
|||
- `corrupt` |
|||
- `offline` |
|||
- `failed` |
|||
|
|||
### 6.7 `backends` |
|||
|
|||
Purpose: |
|||
|
|||
- backend configuration and policy metadata |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `name` TEXT NOT NULL UNIQUE |
|||
- `type` TEXT NOT NULL |
|||
- `stability_class` TEXT NOT NULL |
|||
- `read_priority` INTEGER NOT NULL |
|||
- `write_priority` INTEGER NOT NULL |
|||
- `is_enabled` BOOLEAN NOT NULL DEFAULT 1 |
|||
- `config_json` TEXT NOT NULL |
|||
- `capacity_hint_bytes` INTEGER NULL |
|||
- `last_health_status` TEXT NULL |
|||
- `last_health_checked_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Notes: |
|||
|
|||
- secrets should be encrypted before being stored in `config_json` |
|||
|
|||
### 6.8 `upload_sessions` |
|||
|
|||
Purpose: |
|||
|
|||
- tus-based resumable upload tracking between browser and gateway |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `directory_id` TEXT NOT NULL |
|||
- `filename` TEXT NOT NULL |
|||
- `total_size_bytes` INTEGER NOT NULL |
|||
- `received_size_bytes` INTEGER NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `temp_path` TEXT NOT NULL |
|||
- `tus_upload_url` TEXT NULL |
|||
- `upload_metadata_json` TEXT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
### 6.8a `upload_session_parts` |
|||
|
|||
Purpose: |
|||
|
|||
- track uploaded ranges or parts when local resumable state is needed |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `upload_session_id` TEXT NOT NULL |
|||
- `part_number` INTEGER NOT NULL |
|||
- `byte_offset` INTEGER NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `checksum` TEXT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
- UNIQUE (`upload_session_id`, `part_number`) |
|||
|
|||
### 6.9 `jobs` |
|||
|
|||
Purpose: |
|||
|
|||
- durable background work tracking |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `kind` TEXT NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `payload_json` TEXT NOT NULL |
|||
- `attempt_count` INTEGER NOT NULL DEFAULT 0 |
|||
- `max_attempts` INTEGER NOT NULL DEFAULT 5 |
|||
- `run_after` DATETIME NOT NULL |
|||
- `last_error` TEXT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
Suggested `kind` values: |
|||
|
|||
- `replicate_blob` |
|||
- `generate_thumbnail` |
|||
- `verify_replica` |
|||
- `repair_blob` |
|||
- `health_check_backend` |
|||
|
|||
### 6.10 `preview_artifacts` |
|||
|
|||
Purpose: |
|||
|
|||
- preview resources mapped back to files or file versions |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `file_version_id` TEXT NOT NULL |
|||
- `artifact_type` TEXT NOT NULL |
|||
- `blob_id` TEXT NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
### 6.11 `cache_entries` |
|||
|
|||
Purpose: |
|||
|
|||
- local cache tracking |
|||
|
|||
Suggested columns: |
|||
|
|||
- `id` TEXT PRIMARY KEY |
|||
- `blob_id` TEXT NOT NULL |
|||
- `local_path` TEXT NOT NULL |
|||
- `cache_kind` TEXT NOT NULL |
|||
- `size_bytes` INTEGER NOT NULL |
|||
- `status` TEXT NOT NULL |
|||
- `last_accessed_at` DATETIME NOT NULL |
|||
- `expires_at` DATETIME NULL |
|||
- `created_at` DATETIME NOT NULL |
|||
- `updated_at` DATETIME NOT NULL |
|||
|
|||
## 7. API Design Direction |
|||
|
|||
Use a clean REST API for MVP. gRPC is unnecessary at this stage. |
|||
|
|||
Suggested route groups: |
|||
|
|||
- `/api/auth` |
|||
- `/api/files` |
|||
- `/api/directories` |
|||
- `/api/uploads` |
|||
- `/api/previews` |
|||
- `/api/backends` |
|||
- `/api/jobs` |
|||
- `/api/system` |
|||
|
|||
### 7.1 Key Endpoints |
|||
|
|||
Examples: |
|||
|
|||
- `POST /api/auth/login` |
|||
- `GET /api/directories/:id/children` |
|||
- `POST /api/directories` |
|||
- `POST /api/uploads` |
|||
- `HEAD /api/uploads/:id` |
|||
- `PATCH /api/uploads/:id` |
|||
- `POST /api/uploads/:id/finalize` |
|||
- `GET /api/files/:id` |
|||
- `GET /api/files/:id/download` |
|||
- `GET /api/files/:id/stream` |
|||
- `GET /api/files/:id/thumbnail` |
|||
- `POST /api/files/:id/move` |
|||
- `POST /api/files/:id/rename` |
|||
- `DELETE /api/files/:id` |
|||
- `GET /api/backends` |
|||
- `POST /api/backends` |
|||
- `POST /api/backends/:id/check` |
|||
- `GET /api/jobs` |
|||
- `POST /api/jobs/:id/retry` |
|||
|
|||
## 8. Upload Pipeline |
|||
|
|||
Recommended MVP flow: |
|||
|
|||
1. Browser creates a `tus` upload resource on the gateway. |
|||
2. Browser uploads file content through `tus` patch requests. |
|||
3. Gateway writes incoming bytes to a temporary local ingest path. |
|||
4. Gateway tracks upload progress in the database. |
|||
5. When upload completes, gateway computes metadata such as mime type, hash, and size. |
|||
6. Gateway creates logical records in the database. |
|||
7. Gateway writes the first required replica synchronously to a chosen primary backend. |
|||
8. Gateway marks the file visible when minimum durability criteria are met. |
|||
9. Gateway schedules secondary replication and preview generation jobs. |
|||
|
|||
Important MVP rule: |
|||
|
|||
- visibility should happen only after at least one durable backend write succeeds |
|||
|
|||
Recommended upload protocol choice: |
|||
|
|||
- adopt `tus` for resumable uploads in MVP |
|||
- keep upload session state explicit in the database so the gateway can coordinate file creation, placement, and recovery |
|||
- treat `tus` as the ingress protocol, while keeping storage placement and replica logic as internal concerns |
|||
- add a gateway-side finalize step so a completed `tus` upload becomes a managed logical file only after validation and first durable write |
|||
|
|||
## 9. Download and Stream Pipeline |
|||
|
|||
### 9.1 Download |
|||
|
|||
1. User requests file download. |
|||
2. Gateway resolves current file version and blob layout. |
|||
3. Gateway checks local cache. |
|||
4. If cache misses, gateway chooses the best available replica based on backend health and priority. |
|||
5. Gateway streams the response to the client while optionally filling cache. |
|||
|
|||
### 9.2 Video Streaming |
|||
|
|||
Recommended strategy: |
|||
|
|||
- support HTTP Range requests on the gateway |
|||
- map byte ranges to full-file or chunked blob reads |
|||
- prefer local cache, then stable backends, then opportunistic backends |
|||
|
|||
Why: |
|||
|
|||
- this is the most standard Web-compatible approach |
|||
- native browser video players work with it |
|||
- it avoids inventing a custom preview transport too early |
|||
|
|||
## 10. Preview Pipeline |
|||
|
|||
Recommended preview support for MVP: |
|||
|
|||
- images: generate thumbnails and serve original or scaled versions |
|||
- PDFs: browser inline preview using direct file or proxy response |
|||
- videos: poster image plus range-based playback |
|||
|
|||
Suggested preview job flow: |
|||
|
|||
1. file ingest completes |
|||
2. preview worker inspects mime type |
|||
3. thumbnail or poster extraction runs if applicable |
|||
4. derivative asset is stored as a blob |
|||
5. preview artifact record is created |
|||
|
|||
Tooling options: |
|||
|
|||
- `ffmpeg` for video poster generation and optional transcoding later |
|||
- image library for thumbnails |
|||
|
|||
Recommendation: |
|||
|
|||
- do not include full video transcoding in MVP |
|||
- stick to poster extraction and native playback for supported source formats |
|||
|
|||
## 11. Placement and Replica Policy |
|||
|
|||
Recommended MVP policy engine: |
|||
|
|||
- every backend has a policy score |
|||
- backend selection uses stability class, enabled state, health state, and priority |
|||
- every file has a placement rule selected by file class |
|||
|
|||
Suggested first placement classes: |
|||
|
|||
- `critical-metadata` |
|||
- `document` |
|||
- `photo` |
|||
- `video` |
|||
- `cold-archive` |
|||
|
|||
Suggested default behavior: |
|||
|
|||
- metadata exports: local + stable backend |
|||
- documents: stable primary, optional opportunistic secondary |
|||
- photos: stable primary, opportunistic secondary if available |
|||
- videos: stable primary, optional async secondary depending on size and backend capacity |
|||
|
|||
## 12. Authentication Recommendation |
|||
|
|||
For MVP: |
|||
|
|||
- one local user table |
|||
- session cookie auth or signed token auth |
|||
|
|||
Recommendation: |
|||
|
|||
- use a simple local auth model first |
|||
- the current backend implementation uses persisted bearer-token sessions |
|||
- the future Web UI may wrap that with cookie handling or translate it into cookie-based sessions |
|||
- avoid introducing OAuth or external identity providers in MVP |
|||
|
|||
Reason: |
|||
|
|||
- local self-hosted single-user setup does not need auth complexity yet |
|||
|
|||
## 13. Secrets and Security |
|||
|
|||
Recommended MVP measures: |
|||
|
|||
- encrypt backend credentials before storing them in SQLite |
|||
- use a gateway master key from environment or local config file |
|||
- redact sensitive fields in logs |
|||
- require login for all file and backend management routes |
|||
|
|||
## 14. Caching Strategy |
|||
|
|||
Suggested MVP cache layers: |
|||
|
|||
- ingest temp area |
|||
- blob cache |
|||
- preview cache |
|||
|
|||
Suggested cache policy: |
|||
|
|||
- LRU-like eviction based on size budget and recent access |
|||
- separate quotas for blob cache and preview cache |
|||
|
|||
Do not make cache semantics too smart in MVP. Keep them observable and debuggable. |
|||
|
|||
## 15. Background Jobs |
|||
|
|||
Recommended architecture: |
|||
|
|||
- jobs stored in SQLite |
|||
- one scheduler loop claims runnable jobs |
|||
- small worker pool executes jobs |
|||
- failed jobs are retried with backoff |
|||
- workers may call synchronous SDKs through thread pools where async-native clients are unavailable |
|||
|
|||
Why not a separate queue system yet: |
|||
|
|||
- too much operational complexity for single-node MVP |
|||
- SQLite durability is enough for this stage if jobs are idempotent |
|||
|
|||
Job design rule: |
|||
|
|||
- every job must be safe to retry |
|||
|
|||
## 16. Adapter Interface Draft |
|||
|
|||
Define a storage adapter interface around core object operations. |
|||
|
|||
Suggested interface shape: |
|||
|
|||
```python |
|||
from typing import Protocol |
|||
|
|||
|
|||
class StorageAdapter(Protocol): |
|||
adapter_type: str |
|||
|
|||
async def check(self) -> None: ... |
|||
|
|||
async def stat(self, key: str) -> "ObjectInfo": ... |
|||
|
|||
async def put( |
|||
self, |
|||
key: str, |
|||
stream, |
|||
size: int, |
|||
options: "PutOptions", |
|||
) -> "ObjectInfo": ... |
|||
|
|||
async def get( |
|||
self, |
|||
key: str, |
|||
byte_range: "ByteRange | None" = None, |
|||
) -> tuple[object, "ObjectInfo"]: ... |
|||
|
|||
async def delete(self, key: str) -> None: ... |
|||
``` |
|||
|
|||
Notes: |
|||
|
|||
- use `key` as the physical storage identifier |
|||
- keep adapters object-oriented even for local filesystem storage |
|||
- do not let adapters know about directories, files, or logical paths |
|||
- if a provider SDK is synchronous, isolate it inside the adapter and offload blocking work explicitly |
|||
|
|||
Suggested adapter split: |
|||
|
|||
- `NativeStorageAdapter`: direct provider SDK or protocol implementation |
|||
- `BridgeStorageAdapter`: talks to an external bridge service or compatibility layer |
|||
|
|||
Core services should not need to know which one is in use. |
|||
|
|||
## 17. Physical Key Strategy |
|||
|
|||
Do not store files in backends by original user path. |
|||
|
|||
Recommended key pattern: |
|||
|
|||
- `blobs/sha256_prefix/full_hash` |
|||
- `previews/file_version_id/artifact_type` |
|||
- `exports/date/export_id` |
|||
|
|||
Why: |
|||
|
|||
- avoids backend path rename costs |
|||
- reduces coupling to logical namespace changes |
|||
- makes replication and repair much simpler |
|||
|
|||
## 18. Suggested First Implementation Order |
|||
|
|||
1. config loading and app bootstrap |
|||
2. SQLite migrations |
|||
3. domain models and repository interfaces |
|||
4. local backend adapter |
|||
5. file ingest pipeline |
|||
6. file listing and basic Web UI |
|||
7. blob cache |
|||
8. download pipeline |
|||
9. image and PDF preview |
|||
10. S3 adapter |
|||
11. job system |
|||
12. Aliyun adapter |
|||
13. Baidu adapter |
|||
14. video poster generation and range streaming polish |
|||
|
|||
## 19. Key Architecture Decisions To Confirm |
|||
|
|||
These are the most important choices still worth discussing before coding: |
|||
|
|||
- Backend language: `Python` is confirmed. |
|||
- Frontend stack: confirm `Vite + React`. |
|||
- Database access: `SQLAlchemy ORM` is confirmed. |
|||
- Consumer cloud adapters: bridge-capable adapter strategy is confirmed. |
|||
- Upload protocol: `tus` is confirmed. |
|||
- Credential encryption: define whether to use a local master key file or environment variable only. |
|||
- Async model: async-first architecture is confirmed; blocking operations must be isolated explicitly. |
|||
|
|||
## 20. Recommendation Summary |
|||
|
|||
For the first implementation phase, the strongest recommendation is: |
|||
|
|||
- backend: `Python + FastAPI` |
|||
- frontend: `Vite + React` |
|||
- database: `SQLite` |
|||
- data access: `SQLAlchemy ORM` |
|||
- jobs: in-process durable workers |
|||
- architecture: layered async modular monolith |
|||
- storage strategy: replication first, chunking only where beneficial |
|||
- upload strategy: `tus` resumable upload with gateway-managed session records |
|||
- preview strategy: native browser preview plus range-based streaming |
|||
- backend order: local, S3, Aliyun, Baidu |
|||
- adapter policy: native where clean, bridge where provider complexity would otherwise damage maintainability |
|||
- Python libraries to prefer: `SQLAlchemy 2.0`, `Alembic`, `Pydantic v2`, `httpx`, `boto3` or compatible S3 SDK, and `ffmpeg` integration for previews |
|||
|
|||
This combination is the best balance between simplicity, stream handling, self-hosted deployment, and future extensibility. |
|||
|
|||
## 21. Implemented Foundation Status |
|||
|
|||
For a product-level view of what is still missing before Iron can be called a usable MVP, see [mvp-status.md](/Users/bytedance/iron/docs/mvp-status.md:1). |
|||
|
|||
The repository now includes the following implemented baseline pieces: |
|||
|
|||
- `uv`-managed local virtual environment workflow |
|||
- FastAPI application bootstrap and routing shell |
|||
- async SQLAlchemy engine setup for SQLite |
|||
- initial ORM entity definitions for the core schema |
|||
- first Alembic migration for the initial metadata model |
|||
- readiness check backed by a real database ping |
|||
- baseline automated tests for config, system routes, and migration application |
|||
- first auth slice: |
|||
- bootstrap local admin user |
|||
- login, logout, and current-user APIs |
|||
- bearer-token session persistence and route protection |
|||
- first Web shell slice: |
|||
- `/app` browser entry |
|||
- login form and session bootstrap |
|||
- root directory listing |
|||
- backend listing |
|||
- first metadata feature slice for directories: |
|||
- root directory bootstrap |
|||
- create directory |
|||
- list child directories |
|||
- first file metadata slice: |
|||
- internal file metadata creation service for future upload finalization |
|||
- mixed directory and file child listings |
|||
- file detail API |
|||
- recycle-bin file deletion and restore flow |
|||
- first upload slice: |
|||
- tus upload session creation |
|||
- offset inspection |
|||
- sequential patch uploads into temp ingest storage |
|||
- finalize flow wired into file metadata creation |
|||
- finalize flow persists the primary blob into the default local backend |
|||
- local `blob_replicas` records are created for finalized uploads |
|||
- finalize enqueues non-local replication jobs |
|||
- first download slice: |
|||
- file download endpoint resolves local ready replicas |
|||
- downloaded content is served from persisted local backend objects |
|||
- remote fallback can materialize ready replicas into local cache |
|||
- first stream slice: |
|||
- file stream endpoint resolves local ready replicas |
|||
- HTTP Range support for partial content reads |
|||
- first preview slice: |
|||
- inline preview endpoint for images and PDFs persisted to local backend |
|||
- first backend-visibility slice: |
|||
- backend list endpoint for configured backends |
|||
- first backend-management slice: |
|||
- backend creation for local and s3 config metadata |
|||
- local and s3 backend health checks |
|||
- backend disable flow |
|||
- first jobs-and-ops slice: |
|||
- durable SQLite job records |
|||
- in-process polling loop |
|||
- job list/detail/retry/run APIs |
|||
- backend health-check enqueue flow |
|||
- declarative file reconcile enqueue flow |
|||
- metadata export and import APIs |
|||
- first policy slice: |
|||
- persisted placement policies by file class |
|||
- preferred and excluded backend controls |
|||
- size-aware non-local replica caps |
|||
- placement preview API for product-facing inspection |
|||
- upload finalize uses policy-selected secondary targets |
|||
- reconciliation jobs converge actual replicas toward desired state |
|||
- first namespace-mutation slice: |
|||
- directory rename |
|||
- directory move with descendant path updates |
|||
- file rename |
|||
- file move |
|||
|
|||
From a product perspective, the next logical step is no longer more basic metadata CRUD. It is: |
|||
|
|||
- deepen the browser shell into a fuller Web UI |
|||
- deepen browser-facing session handling on top of the current auth backend |
|||
- add post-restore hardening and stronger preview derivative generation |
|||
- add the first consumer-cloud backend |
|||
|
|||
For the product-level gap assessment, use [mvp-status.md](/Users/bytedance/iron/docs/mvp-status.md:1) as the source of truth. |
|||
|
|||
For day-to-day continuation guidance and current repo reality, use [handoff.md](/Users/bytedance/iron/docs/handoff.md:1) first. |
|||
@ -1,137 +0,0 @@ |
|||
# Iron UI Playwright Standard |
|||
|
|||
Last updated: 2026-04-14 |
|||
|
|||
## 1. Purpose |
|||
|
|||
All future Iron Web UI changes must be validated against a real running service, using Python Playwright flows and screenshot review. |
|||
|
|||
This is the default UI modification standard for the project. |
|||
|
|||
## 2. Required Workflow For Any UI Change |
|||
|
|||
Before considering a UI change complete: |
|||
|
|||
1. build the frontend assets |
|||
2. start the real local service |
|||
3. run the Python Playwright regression flow |
|||
4. generate screenshots into `output/playwright/` |
|||
5. review screenshots for layout, spacing, responsiveness, and interaction states |
|||
6. fix issues found in the screenshots or browser flow |
|||
7. rerun the Playwright flow after the fixes |
|||
|
|||
Do not treat UI work as complete based only on code review or unit tests. |
|||
|
|||
## 3. Required Validation Levels |
|||
|
|||
Every meaningful UI change should validate: |
|||
|
|||
- login flow |
|||
- files workspace render |
|||
- primary file operation flow affected by the change |
|||
- upload flow if the change touches file workflows |
|||
- screenshots of the affected page states |
|||
|
|||
## 4. Tooling Standard |
|||
|
|||
Use: |
|||
|
|||
- Python Playwright code for repeatable regression checks |
|||
- a real locally running Iron service |
|||
- screenshot artifacts for visual inspection |
|||
|
|||
Preferred command: |
|||
|
|||
```bash |
|||
./.venv/bin/python scripts/ui_playwright_smoke.py |
|||
``` |
|||
|
|||
Pytest entrypoint for CI or full local regression: |
|||
|
|||
```bash |
|||
./.venv/bin/python -m pytest tests/e2e/test_web_ui_playwright.py |
|||
``` |
|||
|
|||
Artifacts must be written to: |
|||
|
|||
```text |
|||
output/playwright/ |
|||
``` |
|||
|
|||
## 5. Screenshot Review Checklist |
|||
|
|||
Every screenshot review should check: |
|||
|
|||
- overall balance of the layout |
|||
- spacing consistency |
|||
- text truncation or wrapping problems |
|||
- button grouping and hierarchy |
|||
- panel heights and overflow behavior |
|||
- empty-state clarity |
|||
- table/list readability |
|||
- dialog layout and action placement |
|||
- mobile or narrow-width resilience when the changed surface is responsive |
|||
|
|||
## 6. Interaction Review Checklist |
|||
|
|||
Every flow review should check: |
|||
|
|||
- click targets are obvious |
|||
- primary actions are easy to find |
|||
- selection state is clear |
|||
- navigation state is preserved where expected |
|||
- success feedback is visible |
|||
- error feedback is actionable |
|||
- dialogs do not rely on browser-native prompts |
|||
- repetitive tasks do not require unnecessary clicks |
|||
|
|||
## 7. Regression Scope For Iron |
|||
|
|||
Current baseline regression should cover: |
|||
|
|||
- login |
|||
- files page |
|||
- create folder |
|||
- upload from the files page |
|||
- authenticated file download |
|||
- authenticated inline image preview |
|||
- no failing `/api` browser requests during the flow |
|||
- files search/filter visibility |
|||
- uploads page render |
|||
|
|||
As new UI capabilities are added, extend the Python Playwright script to cover them. |
|||
|
|||
## 8. Expected Outputs |
|||
|
|||
Each run should produce: |
|||
|
|||
- pass/fail console output |
|||
- screenshots |
|||
- clear error exit code on failure |
|||
|
|||
Recommended screenshot set: |
|||
|
|||
- `login.png` |
|||
- `files-empty-or-initial.png` |
|||
- `files-after-create-folder.png` |
|||
- `files-after-upload.png` |
|||
- `uploads-page.png` |
|||
|
|||
## 9. Standard For Future UI Optimization |
|||
|
|||
For future layout or interaction polish: |
|||
|
|||
- first reproduce the current state in Playwright |
|||
- capture before screenshots |
|||
- make a focused UI change |
|||
- capture after screenshots |
|||
- compare the changed states visually |
|||
- keep the regression script updated if the flow meaningfully changes |
|||
|
|||
## 10. Non-Negotiable Rule |
|||
|
|||
No future UI optimization should be merged or considered complete without: |
|||
|
|||
- a real service run |
|||
- Python Playwright flow validation |
|||
- screenshot review |
|||
@ -1,342 +0,0 @@ |
|||
# Iron Web UI Technical Design |
|||
|
|||
Last updated: 2026-04-15 |
|||
|
|||
## 1. Goal |
|||
|
|||
This document defines the first real Web UI implementation for Iron as a product, not as a backend demo shell. |
|||
|
|||
The design target is: |
|||
|
|||
- a browser-based personal cloud drive that feels familiar to users of mainstream drive products |
|||
- a file-first experience, with storage and operational controls available when needed |
|||
- a frontend architecture that can grow without forcing a backend rewrite |
|||
|
|||
## 2. Product Direction |
|||
|
|||
Iron should feel like: |
|||
|
|||
- a calm personal drive for everyday browsing, upload, preview, and organization |
|||
- a storage-aware control surface when the user wants to inspect health, jobs, or replica state |
|||
|
|||
Iron should not feel like: |
|||
|
|||
- a generic admin dashboard |
|||
- a developer-only operations console |
|||
- a backend demo that exposes storage complexity too early |
|||
|
|||
The default user mental model should be: |
|||
|
|||
- there is one drive |
|||
- files live in one namespace |
|||
- storage placement is handled by the system |
|||
- operational details are inspectable but not required for normal use |
|||
|
|||
## 3. UX Principles |
|||
|
|||
- file browsing is the center of the product |
|||
- preview before download whenever possible |
|||
- complex storage details stay secondary |
|||
- important system state stays visible but low-noise |
|||
- common actions should be reachable in one or two clicks |
|||
- the desktop layout should resemble familiar drive products, while mobile should collapse into simple list-detail flows |
|||
|
|||
## 4. Primary Information Architecture |
|||
|
|||
Recommended primary navigation: |
|||
|
|||
1. Files |
|||
2. Uploads |
|||
3. Recycle Bin |
|||
4. Storage |
|||
5. Jobs |
|||
|
|||
Secondary entry points: |
|||
|
|||
- search |
|||
- account/session menu |
|||
- future settings/policies entry |
|||
|
|||
## 5. Layout Model |
|||
|
|||
The app should use a three-zone desktop layout: |
|||
|
|||
- left sidebar: primary navigation and directory shortcuts |
|||
- main workspace: listing, toolbar, breadcrumbs, upload flows |
|||
- right detail panel: preview, metadata, storage status, contextual actions |
|||
|
|||
Mobile and narrow tablet should collapse to: |
|||
|
|||
- top bar |
|||
- main content |
|||
- bottom sheet or dedicated route for file detail |
|||
|
|||
## 6. Visual Direction |
|||
|
|||
Reference class: |
|||
|
|||
- mainstream Web drive layout |
|||
- product-first, not enterprise-heavy |
|||
- spacious, legible, and calm |
|||
|
|||
Current visual language: |
|||
|
|||
- ownCloud-inspired file-product structure, without copying exact visual assets |
|||
- desktop-first left navigation, central file workspace, and right contextual panels |
|||
- compact first-screen layouts with pagination for long lists instead of page-length scrolling |
|||
- restrained neutral surfaces, blue primary actions, high-contrast text, and light borders |
|||
- UI changes must be reviewed from real Playwright screenshots before being considered complete |
|||
|
|||
## 7. Frontend Technical Stack |
|||
|
|||
Recommended stack: |
|||
|
|||
- `Vite` |
|||
- `React` |
|||
- `TypeScript` |
|||
- `React Router` |
|||
- `TanStack Query` |
|||
- `Radix UI` primitives only when needed later |
|||
|
|||
State strategy: |
|||
|
|||
- server state: `TanStack Query` |
|||
- local UI state: React state and context |
|||
- persistent auth/session state: small local storage wrapper |
|||
|
|||
Rationale: |
|||
|
|||
- Iron is a long-lived SPA-style product |
|||
- the backend already owns API and routing responsibility |
|||
- Vite keeps build and iteration simple |
|||
- React Router and TanStack Query are enough for current complexity |
|||
|
|||
## 8. App Structure |
|||
|
|||
Recommended source layout: |
|||
|
|||
```text |
|||
frontend/ |
|||
src/ |
|||
app/ |
|||
App.tsx |
|||
router.tsx |
|||
providers.tsx |
|||
components/ |
|||
layout/ |
|||
feedback/ |
|||
files/ |
|||
storage/ |
|||
features/ |
|||
auth/ |
|||
files/ |
|||
uploads/ |
|||
recycle-bin/ |
|||
storage/ |
|||
jobs/ |
|||
lib/ |
|||
api/ |
|||
auth/ |
|||
format/ |
|||
utils/ |
|||
routes/ |
|||
styles/ |
|||
``` |
|||
|
|||
Guidance: |
|||
|
|||
- keep route-level pages under `routes/` |
|||
- keep API wrappers under `lib/api/` |
|||
- keep reusable visual building blocks under `components/` |
|||
- keep feature-specific hooks and rendering helpers in each feature folder |
|||
|
|||
## 9. Route Plan |
|||
|
|||
Initial route map: |
|||
|
|||
- `/app/login` |
|||
- `/app/files` |
|||
- `/app/files/:directoryId` |
|||
- `/app/uploads` |
|||
- `/app/recycle-bin` |
|||
- `/app/storage` |
|||
- `/app/jobs` |
|||
|
|||
Behavior: |
|||
|
|||
- `/app` should redirect authenticated users to `/app/files` |
|||
- unauthenticated users should be sent to `/app/login` |
|||
|
|||
## 10. Data and API Integration |
|||
|
|||
The first Web UI should reuse the current backend API surface. |
|||
|
|||
Auth: |
|||
|
|||
- `POST /api/auth/login` |
|||
- `GET /api/auth/me` |
|||
- `POST /api/auth/logout` |
|||
|
|||
Files and directories: |
|||
|
|||
- `GET /api/directories/{directory_id}/children` |
|||
- `GET /api/files/{file_id}` |
|||
- `GET /api/files/{file_id}/download` |
|||
- `GET /api/files/{file_id}/preview` |
|||
- `GET /api/files/{file_id}/stream` |
|||
- `POST /api/files/{file_id}/rename` |
|||
- `POST /api/files/{file_id}/move` |
|||
- `DELETE /api/files/{file_id}` |
|||
- `POST /api/files/{file_id}/restore` |
|||
- `GET /api/files/recycle-bin` |
|||
- `POST /api/directories` |
|||
- `POST /api/directories/{directory_id}/rename` |
|||
- `POST /api/directories/{directory_id}/move` |
|||
|
|||
Uploads: |
|||
|
|||
- `POST /files` |
|||
- `HEAD /files/{upload_id}` |
|||
- `PATCH /files/{upload_id}` |
|||
- `POST /api/uploads/{upload_id}/finalize` |
|||
|
|||
Operations: |
|||
|
|||
- `GET /api/backends` |
|||
- `POST /api/backends/{backend_id}/check` |
|||
- `POST /api/backends/{backend_id}/disable` |
|||
- `GET /api/jobs` |
|||
- `GET /api/jobs/{job_id}` |
|||
- `POST /api/jobs/{job_id}/retry` |
|||
- `POST /api/jobs/run-pending` |
|||
- `POST /api/jobs/enqueue-health-checks` |
|||
- `POST /api/jobs/enqueue-full-reconcile` |
|||
|
|||
Browser content access: |
|||
|
|||
- JSON APIs use bearer-token `Authorization` headers through the shared API client |
|||
- file download, preview, and stream actions must not use naked `/api/files/...` URLs in media tags or `window.open` |
|||
- browser preview/download should fetch the file with authorization, create an object URL, and revoke it after use |
|||
- Playwright E2E must cover authenticated file access whenever these flows change |
|||
|
|||
## 11. MVP Page Scope |
|||
|
|||
### 11.1 Files |
|||
|
|||
Must include: |
|||
|
|||
- breadcrumb navigation |
|||
- file/folder listing |
|||
- list and grid view toggle |
|||
- select item |
|||
- right-side detail panel |
|||
- preview for image, PDF, and video-capable files |
|||
- rename, move, delete, download actions |
|||
- create folder action |
|||
|
|||
### 11.2 Uploads |
|||
|
|||
Must include: |
|||
|
|||
- file picker |
|||
- drag and drop |
|||
- upload queue |
|||
- progress display |
|||
- finalize into current directory |
|||
|
|||
### 11.3 Recycle Bin |
|||
|
|||
Must include: |
|||
|
|||
- deleted file list |
|||
- restore action |
|||
- metadata visibility |
|||
|
|||
### 11.4 Storage |
|||
|
|||
Must include: |
|||
|
|||
- backend cards/list |
|||
- health state |
|||
- last checked time |
|||
- disable action |
|||
- trigger check action |
|||
|
|||
### 11.5 Jobs |
|||
|
|||
Must include: |
|||
|
|||
- recent jobs list |
|||
- status emphasis |
|||
- retry for retryable/failed jobs |
|||
- trigger run pending |
|||
- enqueue health checks |
|||
- enqueue full reconcile |
|||
|
|||
## 12. Interaction Model |
|||
|
|||
Toolbar behavior in Files: |
|||
|
|||
- primary action: upload |
|||
- secondary actions: new folder, refresh, view toggle |
|||
- selection actions move into detail panel and contextual menus |
|||
|
|||
Detail panel behavior: |
|||
|
|||
- opens on item selection |
|||
- shows metadata immediately |
|||
- shows preview when supported |
|||
- keeps actions grouped by safety |
|||
|
|||
Feedback behavior: |
|||
|
|||
- use inline toasts or banners for successful mutations |
|||
- keep destructive confirmations explicit |
|||
- show loading skeletons instead of blank content |
|||
|
|||
## 13. Accessibility and Responsiveness |
|||
|
|||
The first Web UI should include: |
|||
|
|||
- keyboard reachable navigation |
|||
- visible focus states |
|||
- semantic buttons, forms, lists, and headings |
|||
- color contrast suitable for long sessions |
|||
- responsive behavior for widths down to mobile phone layouts |
|||
|
|||
## 14. Delivery Sequence |
|||
|
|||
Recommended implementation order: |
|||
|
|||
1. frontend scaffold and shared layout |
|||
2. auth flow and route guards |
|||
3. files page and detail panel |
|||
4. uploads page and upload client |
|||
5. recycle bin |
|||
6. storage and jobs pages |
|||
7. polish, responsiveness, and interaction refinement |
|||
|
|||
## 15. Non-Goals For This Slice |
|||
|
|||
Do not block the first Web UI on: |
|||
|
|||
- advanced settings UI |
|||
- full-text search |
|||
- share links |
|||
- policy editor UX |
|||
- multi-window drag/drop complexity |
|||
- perfect media derivative support |
|||
|
|||
The first goal is a strong file-first personal drive UI built on the current backend. |
|||
|
|||
## 16. Current Implementation Snapshot |
|||
|
|||
Implemented as of 2026-04-15: |
|||
|
|||
- login and authenticated route guard |
|||
- files workspace with local folder navigation, breadcrumbs, search, sort, list/grid toggle, pagination, contextual row actions, dialogs, and inspector |
|||
- authenticated browser download and inline image preview via blob-backed object URLs |
|||
- uploads page with drag/drop, file picker, queue, target folder tree, and pagination |
|||
- recycle bin, storage, and jobs pages with compact desktop workspaces |
|||
- Python Playwright smoke/E2E flow with screenshots under `output/playwright/` |
|||
- pytest E2E entry at `tests/e2e/test_web_ui_playwright.py` |
|||
Loading…
Reference in new issue