Spaces:
Sleeping
Sleeping
| # Implementation Plan: Multi-Tenant Obsidian-Like Docs Viewer | |
| **Branch**: `001-obsidian-docs-viewer` | **Date**: 2025-11-15 | **Spec**: [spec.md](./spec.md) | |
| **Input**: Feature specification from `/specs/001-obsidian-docs-viewer/spec.md` | |
| **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow. | |
| ## Summary | |
| Build a multi-tenant Obsidian-like documentation viewer with AI-first workflow (AI writes via MCP, humans read/edit via web UI). System provides per-user vaults with Markdown notes, full-text search, wikilink resolution, tag indexing, and backlink tracking. Backend exposes FastMCP server (STDIO + HTTP transports) and HTTP API with Bearer auth (JWT). Frontend is React SPA with shadcn/ui, featuring directory tree navigation and split-pane editor. Deployment targets: local PoC (single-user, STDIO) and Hugging Face Space (multi-tenant, OAuth). | |
| **Technical Approach**: Python backend with FastAPI + FastMCP, SQLite per-user indices, filesystem-based vault storage, JWT authentication. React + Vite frontend with react-markdown rendering. Incremental index updates on writes, optimistic concurrency for UI, last-write-wins for MCP. | |
| ## Technical Context | |
| **Language/Version**: Python 3.11+ | |
| **Primary Dependencies**: FastAPI, FastMCP, python-frontmatter, PyJWT, huggingface_hub, SQLite (stdlib) | |
| **Storage**: Filesystem (per-user vault directories), SQLite (per-user indices) | |
| **Testing**: pytest (backend unit/integration), Vitest (frontend unit), Playwright (E2E) | |
| **Target Platform**: Linux server (HF Space), local dev (Windows/macOS/Linux) | |
| **Project Type**: Web application (Python backend + React frontend) | |
| **Performance Goals**: | |
| - MCP operations: <500ms (read/write/search) for vaults with 1,000 notes | |
| - UI rendering: <2s directory tree load, <1s note render, <1s search results | |
| - Index rebuild: <30s for 1,000 notes | |
| **Constraints**: | |
| - 1 MiB max note size | |
| - 5,000 notes max per vault | |
| - 256 char max path length | |
| - 100% tenant isolation (security requirement) | |
| - 409 Conflict on concurrent edits (UI only) | |
| **Scale/Scope**: | |
| - MVP: 10 concurrent users (HF Space), 5,000 notes per user | |
| - Local PoC: single user, unlimited notes (within filesystem limits) | |
| ## Constitution Check | |
| *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* | |
| **Status**: No project constitution file found at `.specify/memory/constitution.md`. Constitution check skipped. | |
| **Justification**: This is a new project without established architectural principles. Design decisions will be documented in research.md and can form the basis of a future constitution if needed. | |
| ## Project Structure | |
| ### Documentation (this feature) | |
| ```text | |
| specs/001-obsidian-docs-viewer/ | |
| βββ plan.md # This file (/speckit.plan command output) | |
| βββ research.md # Phase 0 output (/speckit.plan command) | |
| βββ data-model.md # Phase 1 output (/speckit.plan command) | |
| βββ quickstart.md # Phase 1 output (/speckit.plan command) | |
| βββ contracts/ # Phase 1 output (/speckit.plan command) | |
| β βββ http-api.yaml # OpenAPI 3.1 spec for HTTP API | |
| β βββ mcp-tools.json # MCP tool schemas (JSON Schema) | |
| βββ tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan) | |
| ``` | |
| ### Source Code (repository root) | |
| ```text | |
| # Web application structure (Python backend + React frontend) | |
| backend/ | |
| βββ src/ | |
| β βββ models/ # Pydantic models (Note, User, Index, Config) | |
| β βββ services/ | |
| β β βββ vault.py # Filesystem vault operations | |
| β β βββ indexer.py # Full-text search, tags, link graph | |
| β β βββ auth.py # JWT + HF OAuth integration | |
| β β βββ config.py # Configuration management | |
| β βββ api/ | |
| β β βββ main.py # FastAPI app + middleware | |
| β β βββ routes/ # API endpoints (notes, search, auth, index) | |
| β β βββ middleware/ # Auth middleware, error handlers | |
| β βββ mcp/ | |
| β βββ server.py # FastMCP server (STDIO + HTTP) | |
| βββ tests/ | |
| β βββ unit/ # Service-level tests | |
| β βββ integration/ # API + MCP integration tests | |
| β βββ contract/ # Contract tests for MCP tools + HTTP API | |
| βββ pyproject.toml # Python dependencies (Poetry/pip) | |
| frontend/ | |
| βββ src/ | |
| β βββ components/ | |
| β β βββ ui/ # shadcn/ui components | |
| β β βββ DirectoryTree.tsx | |
| β β βββ NoteViewer.tsx | |
| β β βββ NoteEditor.tsx | |
| β β βββ SearchBar.tsx | |
| β β βββ AuthFlow.tsx | |
| β βββ pages/ | |
| β β βββ App.tsx # Main app layout | |
| β β βββ Login.tsx # HF OAuth landing | |
| β β βββ Settings.tsx # User profile + token management | |
| β βββ services/ | |
| β β βββ api.ts # HTTP API client (fetch wrapper) | |
| β β βββ auth.ts # Token management, OAuth helpers | |
| β βββ lib/ | |
| β β βββ wikilink.ts # Wikilink parsing + resolution | |
| β β βββ markdown.ts # react-markdown config | |
| β βββ types/ # TypeScript types (Note, User, SearchResult) | |
| βββ tests/ | |
| β βββ unit/ # Component tests (Vitest + Testing Library) | |
| β βββ e2e/ # Playwright E2E tests | |
| βββ package.json # Node dependencies | |
| βββ vite.config.ts # Vite build config | |
| data/ # Runtime data (gitignored) | |
| βββ vaults/ | |
| βββ <user_id>/ # Per-user vault directories | |
| .env.example # Environment template (JWT_SECRET, HF OAuth, etc.) | |
| README.md # Setup instructions, MCP client config examples | |
| ``` | |
| **Structure Decision**: Web application structure selected based on spec requirements for Python backend (FastAPI + FastMCP) and React frontend (shadcn/ui). Backend and frontend are separate codebases to support independent development/testing cycles, with backend serving frontend as static files in production (HF Space). Data directory is runtime-only (vaults + SQLite indices), not version controlled. | |
| ## Complexity Tracking | |
| > **No constitution violations to track** (no project constitution exists yet) | |
| ## Phase 0: Research & Technical Decisions | |
| **Status**: Research required for technology integration patterns and best practices. | |
| **Research Topics**: | |
| 1. FastMCP HTTP transport authentication patterns (Bearer token validation) | |
| 2. Hugging Face Space OAuth integration best practices (attach/parse helpers) | |
| 3. SQLite schema design for per-user multi-index storage (full-text + tags + links) | |
| 4. Wikilink normalization and resolution algorithms (slug matching, ambiguity handling) | |
| 5. React + shadcn/ui directory tree component patterns (collapsible, virtualization) | |
| 6. Optimistic concurrency implementation patterns (ETags vs version counters) | |
| 7. Markdown frontmatter parsing with fallback strategies (malformed YAML handling) | |
| 8. JWT token management in React (localStorage vs memory, refresh strategies) | |
| **Output**: See `research.md` for detailed findings and decisions. | |
| ## Phase 1: Data Model & Contracts | |
| **Prerequisites**: `research.md` complete | |
| ### Data Model | |
| **Entities** (see `data-model.md` for full schemas): | |
| 1. **User**: `user_id`, `hf_profile` (optional), `vault_path`, `created_at` | |
| 2. **Note**: `path`, `title`, `metadata`, `body`, `version`, `created`, `updated` | |
| 3. **Wikilink**: `source_path`, `link_text`, `target_path` (nullable), `is_resolved` | |
| 4. **Tag**: `tag_name`, `note_paths[]` | |
| 5. **Index**: `user_id`, `note_count`, `last_full_rebuild`, `last_incremental_update` | |
| 6. **Token**: `jwt` (claims: `sub`, `exp`, `iat`) | |
| ### API Contracts | |
| **HTTP API** (see `contracts/http-api.yaml`): | |
| - Authentication: `POST /api/tokens`, `GET /api/me` | |
| - Notes CRUD: `GET /api/notes`, `GET /api/notes/{path}`, `PUT /api/notes/{path}`, `DELETE /api/notes/{path}` | |
| - Search: `GET /api/search?q=<query>` | |
| - Navigation: `GET /api/backlinks/{path}`, `GET /api/tags` | |
| - Index: `GET /api/index/health`, `POST /api/index/rebuild` | |
| **MCP Tools** (see `contracts/mcp-tools.json`): | |
| - `list_notes`: `{folder?: string}` β `[{path, title, last_modified}]` | |
| - `read_note`: `{path: string}` β `{path, title, metadata, body}` | |
| - `write_note`: `{path, title?, metadata?, body}` β `{status, path}` | |
| - `delete_note`: `{path: string}` β `{status}` | |
| - `search_notes`: `{query: string}` β `[{path, title, snippet}]` | |
| - `get_backlinks`: `{path: string}` β `[{path, title}]` | |
| - `get_tags`: `{}` β `[{tag, count}]` | |
| ### Quickstart | |
| **Output**: See `quickstart.md` for: | |
| - Local development setup (Python venv, Node install, env config) | |
| - Running backend (STDIO MCP + HTTP API) | |
| - Running frontend (Vite dev server) | |
| - MCP client configuration (Claude Code STDIO example) | |
| - Testing workflows (unit, integration, E2E) | |
| ## Phase 2: Task Generation | |
| **Not included in this command** - run `/speckit.tasks` to generate dependency-ordered implementation tasks based on this plan and the data model. | |
| --- | |
| ## Execution Summary | |
| ### Phase 0: Research & Technical Decisions β COMPLETE | |
| **Generated**: `research.md` (1,407 lines) | |
| **Researched and Resolved**: | |
| 1. β FastMCP HTTP transport authentication patterns β Bearer token with `BearerAuth`, JWT validation | |
| 2. β Hugging Face Space OAuth integration β `attach_huggingface_oauth` + `parse_huggingface_oauth` helpers | |
| 3. β SQLite schema design β FTS5 contentless + separate tags/links tables with per-user isolation | |
| 4. β Wikilink normalization β Case-insensitive normalized slug matching, same-folder preference | |
| 5. β React + shadcn/ui directory tree β shadcn-extension Tree View with TanStack Virtual virtualization | |
| 6. β Optimistic concurrency β Version counter in SQLite + `if_version` parameter, 409 on mismatch | |
| 7. β Markdown frontmatter parsing β `python-frontmatter` with try-except fallback for malformed YAML | |
| 8. β JWT token management β Memory storage (MVP) or memory + HttpOnly cookie (production) | |
| **Key Decisions**: | |
| - FTS5 with porter tokenizer and `prefix='2 3'` for autocomplete | |
| - shadcn-extension tree handles 5,000+ notes with <200ms render | |
| - Version counter is simpler and faster than content hashing | |
| - Hybrid JWT approach (memory + HttpOnly) is 2025 security best practice | |
| ### Phase 1: Data Model & Contracts β COMPLETE | |
| **Generated**: | |
| - `data-model.md` - Complete entity definitions, Pydantic models, TypeScript types, SQLite schema, validation rules, state transitions | |
| - `contracts/http-api.yaml` - OpenAPI 3.1 spec with 11 endpoints, auth, all error responses, examples | |
| - `contracts/mcp-tools.json` - 7 MCP tool schemas with JSON Schema validation, usage examples | |
| - `quickstart.md` - Complete setup, run, test, deploy guide for local PoC and HF Space | |
| **Data Model Highlights**: | |
| - 7 core entities (User, Vault, Note, Wikilink, Tag, Index, Token) | |
| - Complete Pydantic models with validators | |
| - TypeScript types for frontend | |
| - SQLite DDL with 5 tables (metadata, FTS, tags, links, health) | |
| - State machines for note lifecycle and index updates | |
| **API Contract Highlights**: | |
| - HTTP API: 11 endpoints (auth, CRUD, search, navigation, index) | |
| - MCP Tools: 7 tools (list, read, write, delete, search, backlinks, tags) | |
| - All error codes documented (400, 401, 403, 409, 413, 500) | |
| - Request/response examples for all operations | |
| **Agent Context Updated**: | |
| - β Updated `/home/wolfe/Projects/Document-MCP/CLAUDE.md` with Python 3.11+, FastAPI, FastMCP, SQLite tech stack | |
| ### Constitution Re-Check β N/A | |
| **Status**: No project constitution exists. Design decisions documented in research.md can form future constitution baseline. | |
| --- | |
| ## Next Steps | |
| Run `/speckit.tasks` to generate dependency-ordered implementation tasks based on this plan, data model, and contracts. | |
| **Planning Phase Complete**: 2025-11-15 | |