Architektura a tech stack

Tech stack

  • Backend: Rust (edition 2024), Axum 0.8, Tokio async runtime
  • Databáze: PostgreSQL přes SeaORM 1.x; migrace běží automaticky při startu serveru
  • Veřejné stránky: MiniJinja šablony renderované serverem (loader z assets/<NAMESPACE>/templates/)
  • Admin UI: Vue 3 SPA (Pinia, Vue Router, Tailwind 4, Vite, TypeScript), buildovaná do client/dist/ a embedovaná do binárky přes rust-embed
  • Markdown: pulldown-cmark s vlastními direktivami (transclusion, obrázky, galerie, šachové pozice/partie)
  • Auth: Argon2 hashování hesel, session cookies pro SPA, service tokeny (legacy) a OAuth2 (PKCE, RFC 7591) pro API/MCP klienty
  • Logging: tracing + tracing-subscriber s env filtrem
  • AI: vlastní assistant podsystém v src/ai/ (více v about/blog/ai)

Struktura projektu

src/
  bin/
    site_server.rs       # Hlavní HTTP server (port 3000)
    site_migration.rs    # Migration CLI (up/down/fresh/status)
    site_cli.rs          # Admin CLI (create-user, change-password)
  routes/
    public/              # Veřejné routes (catch-all, files, search, sitemap, tags)
    api/                 # JSON API (auth, pages, tags, files, galleries,
                         #            menu, tokens, markdown, paths,
                         #            assistant, llm, tool-permissions)
    mcp.rs               # MCP JSON-RPC endpoint pro Claude
    oauth.rs             # OAuth2 server (register, authorize, token, well-known)
    revision.rs          # Revize stránek
  entity/                # SeaORM entity modely
    user, token, page, page_revision, tag, menu,
    file, file_blob, file_thumbnail, gallery,
    oauth_{client,code,token},
    llm_{provider,model},
    assistant_{session,message},
    user_mcp_server, tool_permission
  migration/             # m_001 … m_022 (vč. fulltext indexu, OAuth, AI tabulek)
  ai/                    # Assistant: loop_driver, tool_registry, mcp_client,
                         # tool_permissions, local_tools, llm, handlers, config
  auth.rs assets.rs config.rs files.rs
  markdown.rs path_util.rs repo state.rs

client/                  # Vue 3 SPA — Pinia, Vue Router, Tailwind 4, Vite
  src/                   # Komponenty, views, stores, router
  dist/                  # Build output (embedovaný do binárky)

assets/<NAMESPACE>/      # Multi-tenant statické bundly
  css/  js/  img/  templates/   # MiniJinja šablony pro veřejné stránky

Jak server funguje

Při spuštění site_server proběhne:

  1. Inicializace tracing (env filter z RUST_LOG).
  2. Načtení Config z prostředí (DATABASE_URL, PORT, NAMESPACE, …).
  3. Vytvoření AppState (DB pool + MiniJinja env naplněný z assets/<NAMESPACE>/templates/).
  4. Spuštění SeaORM migrací (Migrator::up) — automaticky.
  5. Sestavení Axum routeru s podtřídami mcp, oauth, public, api, admin SPA z rust-embed.
  6. Listen na 0.0.0.0:$PORT.

Veřejné stránky — catch-all

Fallback handler GET /{*path} (viz src/routes/public/mod.rs):

  1. Hledá shodu v tabulce menus → renderuje její markdown.
  2. Hledá shodu v tabulce pages → renderuje obsah stránky (skryté soukromé stránky pro nepřihlášené).
  3. Jinak 404.

Markdown se renderuje custom direktivami (viz about/blog/mcp) a obalí se MiniJinja šablonou path_page.html.

Admin SPA

Routes GET /admin a GET /admin/{*path} čtou statické soubory z embedu client/dist/. Pokud cesta neexistuje (typický SPA hluboký link), server vrací index.html a Vue Router se postará o zbytek. Admin UI komunikuje výhradně přes JSON API /api/* — žádné serverové šablony.

Revize a diffy

Při každém uložení stránky se automaticky uloží řádek do page_revisions s diffem oproti předchozí verzi (knihovna diffy). Šetří místo, zachovává historii a dovoluje rollback přes POST /api/pages/:id/revisions/:rev_id/restore.