13 KiB
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
tusfor resumable upload transport- stable logical file identifiers
- backend topology hidden from normal users
Base prefix:
/api
Non-API upload transport prefix:
/files
Notes:
tusendpoints 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:
{
"username": "admin",
"password": "secret"
}
Response:
{
"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
401for invalid credentials
2.2 Logout
POST /api/auth/logout
Response:
{
"success": true
}
Behavior:
- implemented in current codebase
- revokes the current bearer-token session
2.3 Current Session
GET /api/auth/me
Response:
{
"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:
cursorlimitsortorder
Response:
{
"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:
{
"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:
{
"name": "vacation-photos"
}
Implemented status:
- implemented in current codebase
3.4 Move Directory
POST /api/directories/{directory_id}/move
Request:
{
"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=trueis explicitly supported later
Current implementation status:
GET /api/directories/{directory_id}/childrenis 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:
{
"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:
{
"name": "movie-final.mp4"
}
Implemented status:
- implemented in current codebase
4.3 Move File
POST /api/files/{file_id}/move
Request:
{
"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
Rangerequests - 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
404if 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-binPOST /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-ResumableUpload-LengthUpload-Metadata
Behavior:
- creates a new upload session
- returns
201withLocation
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-ResumableUpload-OffsetContent-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:
{
"directory_id": "dir_root",
"filename": "movie.mp4"
}
Response:
{
"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_replicasrecord 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:
{
"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:
{
"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_localstable_replica_countopportunistic_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:
{
"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_typesize_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:
kindstatuslimit
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=truefor destructive import - current backend also requires a fresh
validation_tokenfromPOST /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/validateGET /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:
{
"status": "ok"
}
10.2 Readiness
GET /api/system/ready
Response:
{
"status": "ready",
"database": "ok"
}
10.3 Backends
GET /api/backendsPOST /api/backendsPOST /api/backends/{backend_id}/checkPOST /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-pendingis implemented in current codebasePOST /api/jobs/enqueue-health-checksis implemented in current codebaseGET /api/exports/metadatais implemented in current codebasePOST /api/exports/metadata/validateis implemented in current codebaseGET /api/exports/metadata/integrityis implemented in current codebasePOST /api/exports/metadata/importis implemented in current codebasePOST /api/files/{file_id}/reconcileis implemented in current codebase
11. Error Shape
All JSON API errors should use one consistent envelope:
{
"error": {
"code": "file_not_found",
"message": "File does not exist.",
"details": null
}
}
Suggested error codes:
unauthorizedforbiddenvalidation_errordirectory_not_foundfile_not_foundupload_not_foundbackend_unavailablebackend_config_invalidconflictinternal_error
12. Versioning Approach
MVP can stay unversioned internally if the API is changing quickly.
Recommendation:
- keep
/apiin code - be prepared to introduce
/api/v1before external client surface becomes stable
13. Implementation Notes
tustransport 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.