Skip to content

Wiki spaces

Free-form markdown notes per space, with vault import, a directed page graph view, and page search in the workspace tree (title/path substring, then semantic similarity when the space is indexed). Toggle: wikiSpaces (default on).

Semantic indexing / pgvector: run python scripts/ensure_pgvector.py from the backend/ directory (same backend/.env as the API). The script uses app.config.settings, verifies a real vector distance query (not only CREATE EXTENSION), and on Docker localhost it may install postgresql-*-pgvector, restart the container, then wait before retrying. If indexing still returns 503, compare the host/port/database in the error to the script’s printed target.

Feature Status Description
Wiki space CRUD ✅ /api/wiki-spaces; list/create/update/delete; resource ACL on each space (wiki_space); create bootstraps owner ACL; mutations require write/manage on the space when ACL applies
Wiki space sharing ✅ Space settings Sharing section (ResourceSharePanel); GET/PUT /api/resource-acl/wiki_space/{id}. New spaces: owner-only ACL bootstrap (Others denied). Pre-existing spaces (before migration h8i9j0k1l2m3): seeded Others r/w/m to preserve open-by-default.
Wiki pages ✅ Path-per-space (e.g. guides/onboarding); GET/POST/PATCH/DELETE by id; PUT upsert .../pages/by-path/{path} for CLI; markdown body; cached page_index JSONB; GET .../pages/{id}/page-index; GET .../pages optional limit (1–500) + offset + path_prefix — total is full match count; omit limit to return all (e.g. editor tree); list rows omit body (id/path/title/metadata/timestamps only) so the workspace tree does not download every page’s markdown at once — full content via GET .../pages/{id}; GET .../pages/semantic-matches — { string_matched_page_ids, semantic_matched_pages: [{ page_id, similarity }], semantic_skipped } for workspace tree filter and match-type badges (title/path substring, then embeddings); optional embedding per row (pgvector) filled only by POST .../semantic-index in space settings (offline; default embedding ApiModel) — not updated on every page save yet
Wiki files ✅ POST .../files (multipart), GET .../files/{id}/content (presigned redirect), DELETE .../files/{id}; S3/MinIO uses wiki/{space_id}/vault/{relative-path} when the multipart filename is a valid vault-relative path (folder import + CLI), else wiki/{space_id}/files/{file_id}/…; same vault path re-upload updates existing wiki_files row and overwrites the object (no duplicate storage_key)
Graph View ✅ GET .../graph — directed page graph from [[wikilinks]] and relative markdown links (excluding fenced code blocks); response { nodes, links, source_max_updated_at? }; when S3 is enabled, JSON cache at wiki/{space_id}/link-graph.json — used if object LastModified ≥ max(wiki_pages.updated_at) for the space, else recomputed and uploaded; SPA Graph tab: /wikis/:id/pages/graph (optional ?focus= page id); pages/graph is registered before pages/:pageId so graph is not treated as a page id.
Vault import ✅ Zip: POST .../import/vault with archive. Folder (UI): Import folder opens an in-app dialog (skip .pdf / Office extensions), then Choose vault folder…; the browser's mandatory upload confirmation appears, then import starts immediately (no extra in-app confirm); paths omit the picked OS folder name (first segment of webkitRelativePath stripped so wiki paths start at vault contents); sequential uploads with progress; same skip rules, limits (~2000 files, 80 MB total, 25 MB/file), and image rewrites as bulk import; binaries require storage; markdown mirrored to wiki/{space_id}/vault/…/*.md (rewritten body) when storage is enabled; NUL bytes stripped from markdown/title/path text before insert (PostgreSQL UTF-8)
Permissions ✅ wikis:read / wikis:write with default SPA/API patterns; strict pattern middleware coverage via seeded security_permissions
UI ✅ /wikis; /wikis/:id redirects to /wikis/:id/pages/graph; /wikis/:id/settings — Space settings (sectioned: space name/description with save, vault Import folder / Import zip, New page, paginated Pages list with row links into the workspace, Linked documents + add modal); /wikis/:id/pages/graph, /wikis/:id/pages/:pageId — Wiki workspace (left page tree: loads page catalog without bodies; debounced server match — substring in title/path, else semantic from embeddings — with small badges; local substring filter on title/path only while typing); (tab strip: open page paths + Graph view tab; open tabs are in-memory for the SPA session; Edit / Preview / Save); Page preview markdown: GFM, KaTeX (+ mhchem), AI delimiter normalize via shared RichMarkdown, rehype-raw, Mermaid; linked docs: GET/POST/DELETE /api/wiki-spaces/{id}/documents (picker from document library; persisted in DB); workspace settings icon → /wikis/:id/settings; sidebar Wiki Spaces
Wiki ↔ documents ✅ wiki_space_documents join table; link/unlink/list on /api/wiki-spaces/{id}/documents with scope + wikis:write for mutations; GET list includes each linked document updated_at (in addition to linked_at)
openkms-cli ✅ openkms-cli wiki put, wiki sync, wiki upload-file (auth: OIDC or local Basic)
openkms-skill (HTTP) ✅ Personal API key: wiki-spaces documents list|link|unlink (linked channel docs); wiki files list, wiki files delete — operate on the space file store (vault imports including .md, images, PDFs, ad-hoc uploads; not “attachments only”); see openkms-skill