You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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
  • 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:

{
  "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 401 for 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:

  • cursor
  • limit
  • sort
  • order

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=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:

{
  "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 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:

{
  "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_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:

{
  "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_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:

{
  "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:

{
  "status": "ok"
}

10.2 Readiness

  • GET /api/system/ready

Response:

{
  "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:

{
  "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.