πŸ—οΈ ArchitectureΒΆ

This document describes TINO’s high-level architecture and links to the individual Architecture Decision Records (ADRs) that explain key design choices.

ComponentsΒΆ

TINO is a single Python process (FastAPI) that serves both the REST/WebSocket API and the static frontend. There is no separate frontend build step and no external runtime dependencies beyond a filesystem and an optional OIDC provider.

        graph TD
    subgraph Browser
        JS[Vanilla JS]
        CM[CodeMirror 6]
        YC[Yjs CRDT client]
    end

    subgraph FastAPI
        R["REST routers<br/>auth Β· buckets Β· files Β· git Β· compile Β· …"]
        C["Collab<br/>Yjs room manager"]
    end

    FS[("Filesystem<br/>git repos")]
    T["Typst CLI<br/>subprocess"]
    O["OIDC provider<br/>optional"]

    Browser -->|HTTP / REST| R
    YC -->|WebSocket| C
    R --> FS
    C --> FS
    R --> T
    R --> O
    

Storage layoutΒΆ

All persistent state lives on the filesystem β€” no database is required.

TINO_DATA_DIR/
β”œβ”€β”€ buckets/                  ← TINO_BUCKET_DIR
β”‚   β”œβ”€β”€ <slug>/               ← one directory per bucket
β”‚   β”‚   β”œβ”€β”€ .git/             ← full git repository
β”‚   β”‚   β”œβ”€β”€ .meta.yml         ← bucket metadata (description, access rules)
β”‚   β”‚   └── *.typ, img/, …   ← source files
β”‚   └── packages/             ← TINO_PACKAGE_DIR (local Typst packages)
└── fonts/                    ← TINO_FONT_DIR (custom fonts)

Request lifecycleΒΆ

A typical editing session follows this flow:

        sequenceDiagram
    actor User
    participant Browser
    participant FastAPI
    participant Collab as Yjs rooms
    participant Typst as Typst CLI
    participant FS as Filesystem

    User->>Browser: open TINO
    Browser->>FastAPI: GET /
    FastAPI-->>Browser: static frontend

    User->>Browser: log in
    Browser->>FastAPI: GET /oidc/login
    FastAPI-->>Browser: redirect β†’ OIDC provider β†’ session cookie

    User->>Browser: select bucket
    Browser->>FastAPI: GET /api/buckets
    FastAPI->>FS: list bucket dirs
    FastAPI-->>Browser: bucket list

    User->>Browser: open file
    Browser->>FastAPI: GET /api/buckets/{slug}/files/{path}
    FastAPI->>FS: read file
    FastAPI-->>Browser: file content

    Browser->>Collab: WS /api/buckets/{slug}/collab/{path}
    Collab->>FS: load saved state
    Collab-->>Browser: sync Yjs document

    User->>Browser: type
    Browser->>Collab: Yjs update (WebSocket)
    Collab-->>Browser: broadcast to other clients

    Note over Browser: auto-save debounce fires
    Browser->>FastAPI: PUT /api/buckets/{slug}/files/{path}
    FastAPI->>FS: write file

    Note over Browser: save triggers preview
    Browser->>FastAPI: GET /api/buckets/{slug}/compile/svg/{path}
    FastAPI->>Typst: typst compile --format svg
    Typst->>FS: read source + fonts
    Typst-->>FastAPI: SVG pages
    FastAPI-->>Browser: SVG pages
    

Architecture Decision RecordsΒΆ