diff --git a/.gitea/workflows/publish-docs.yml b/.gitea/workflows/publish-docs.yml
new file mode 100644
index 00000000..bbc013b4
--- /dev/null
+++ b/.gitea/workflows/publish-docs.yml
@@ -0,0 +1,125 @@
+name: Publish Documentation
+
+# Renders the markdown docs (docs/*.md) into an mdBook site, builds the Rust
+# API reference with cargo doc, and force-pushes the combined output to the
+# orphan `gitea-pages` branch that the Gitea Pages server serves.
+#
+# The published matrix is regenerated during the build, so it is never stale.
+
+on:
+ push:
+ branches:
+ - master
+
+concurrency:
+ # Only one docs publish at a time; a newer push supersedes an in-flight run.
+ group: publish-docs
+ cancel-in-progress: true
+
+jobs:
+ publish-docs:
+ name: Build & publish docs to gitea-pages
+ runs-on: linux/amd64
+ container:
+ image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup Bun
+ uses: oven-sh/setup-bun@v1
+ with:
+ bun-version: latest
+
+ - name: Install dependencies
+ run: bun install
+
+ - name: Install mdBook
+ run: |
+ set -e
+ MDBOOK_VERSION=v0.4.40
+ URL="https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
+ echo "⬇️ Downloading mdBook ${MDBOOK_VERSION}"
+ curl -fsSL "$URL" | tar -xz -C /usr/local/bin
+ mdbook --version
+
+ - name: Regenerate traceability matrix (keep published copy current)
+ run: bun run traces:markdown
+
+ - name: Assemble mdBook sources
+ run: |
+ set -e
+ # mdBook's src is docs/. Drop in the SUMMARY and the generated
+ # intro + API redirect pages (build artifacts, not committed).
+ cp docs-site/SUMMARY.md docs/SUMMARY.md
+
+ cat > docs/README.md <<'EOF'
+ # JellyTau Documentation
+
+ Cross-platform Jellyfin client — business logic in a Rust backend,
+ SvelteKit + TypeScript frontend, talking over Tauri v2 IPC.
+
+ - **[Requirements Specification](requirements.md)** — user, integration, and development requirements.
+ - **[Traceability Matrix](traceability.md)** — generated map from requirements to code (regenerated on every publish).
+ - **[Architecture](architecture/README.md)** — backend, frontend, data flow, platform backends.
+ - **[Rust API Reference](api/index.html)** — rustdoc for the `src-tauri` backend.
+
+ _This site is published automatically from `master` by the `publish-docs` CI job._
+ EOF
+
+ cat > docs/api-redirect.md <<'EOF'
+ # Rust API Reference
+
+ The full backend API reference is generated by `cargo doc` (rustdoc).
+
+ 👉 **[Open the Rust API Reference](api/index.html)**
+ EOF
+
+ - name: Build mdBook site
+ run: mdbook build docs-site --dest-dir "$GITHUB_WORKSPACE/site"
+
+ - name: Build Rust API docs (cargo doc)
+ working-directory: src-tauri
+ # --no-deps keeps it to our own crate (fast, focused); document private
+ # items so internal modules/commands appear.
+ run: |
+ cargo doc --no-deps --document-private-items
+ # The backend modules/commands live in the LIB crate (jellytau_lib);
+ # the bin crate (jellytau) is a near-empty shim. Land on the lib.
+ echo '' \
+ > target/doc/index.html
+
+ - name: Assemble published output
+ run: |
+ set -e
+ mkdir -p "$GITHUB_WORKSPACE/site/api"
+ cp -r src-tauri/target/doc/. "$GITHUB_WORKSPACE/site/api/"
+ # Disable Jekyll processing on the pages branch.
+ touch "$GITHUB_WORKSPACE/site/.nojekyll"
+ ls -la "$GITHUB_WORKSPACE/site"
+
+ - name: Push to gitea-pages branch
+ env:
+ # PAT preferred; falls back to the auto-provided token (same pattern
+ # as build-release.yml).
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+ AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -e
+ TOKEN="${GITEA_TOKEN:-$AUTO_TOKEN}"
+ REPO="${GITHUB_REPOSITORY}"
+ HOST="$(echo "$GITHUB_SERVER_URL" | sed -E 's#^https?://##')"
+ REMOTE="https://oauth2:${TOKEN}@${HOST}/${REPO}.git"
+
+ cd "$GITHUB_WORKSPACE/site"
+ git init -q
+ git config user.name "gitea-actions"
+ git config user.email "actions@gitea.tourolle.paris"
+ git checkout -q -b gitea-pages
+ git add -A
+ git commit -q -m "docs: publish site from ${GITHUB_SHA::8}"
+ echo "🚀 Force-pushing to gitea-pages"
+ git push -f "$REMOTE" gitea-pages
diff --git a/.gitignore b/.gitignore
index 433fe992..bb917a4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,9 @@ android-keystore/
# Local machine-specific Android NDK toolchain paths (do not commit)
src-tauri/.cargo/config.toml
+
+# Docs site build artifacts (generated by the publish-docs CI job into docs/)
+/docs/SUMMARY.md
+/docs/README.md
+/docs/api-redirect.md
+/docs-site/book/
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 00000000..5d679c39
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,245 @@
+# JellyTau
+
+A cross-platform Jellyfin client. Business logic lives in a Rust backend
+(`src-tauri/`); a SvelteKit + TypeScript frontend (`src/`) handles presentation
+and talks to it over Tauri v2 IPC. Targets **Linux** (libmpv, WebKitGTK HTML5
+`