ποΈ 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ΒΆ
- ADR-01: Typst as the document format
- ADR-02: No database
- ADR-03: Git as the storage backend
- ADR-04: The bucket model
- ADR-05: FastAPI single-process architecture
- ADR-06: Vanilla JS frontend
- ADR-07: OIDC for authentication
- ADR-08: Yjs CRDT for real-time collaboration
- ADR-09: API keys for REST automation
- ADR-10: MCP server