Documentation set: features, manuals (user/pond-admin/site-admin), API, MCP, developer guide
All checks were successful
CD / Build and push images (push) Successful in 1m9s
CD / Deploy to Test (push) Successful in 10s
CD / Smoke tests against Test (push) Successful in 1m10s
CD / Promote to Int (push) Successful in 11s
CI / Lint, typecheck, test (push) Successful in 4m7s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 5m34s
CI / Import/export fidelity gate (push) Successful in 47s
All checks were successful
CD / Build and push images (push) Successful in 1m9s
CD / Deploy to Test (push) Successful in 10s
CD / Smoke tests against Test (push) Successful in 1m10s
CD / Promote to Int (push) Successful in 11s
CI / Lint, typecheck, test (push) Successful in 4m7s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 5m34s
CI / Import/export fidelity gate (push) Successful in 47s
Seven audience-targeted documents (English first, German translation to follow), linked from the README and a new docs/manual/ index: - docs/features.md — public-facing feature overview: what Dorfteich can do and why that matters - docs/manual/user-guide.md — everyday use: editor, wikilinks, labels, search, comments, watches/digests, import/export, settings - docs/manual/pond-admin-guide.md — pond configuration: members/roles, access rules incl. label scoping and public pages, labels, comment policy, plugins, API/MCP opt-ins, files, export - docs/manual/site-admin-guide.md — instance administration: wizard, settings, quotas, uploads, API/MCP switches, legal pages, plugins, users, and the system panel (jobs/backups/audit/storage) - docs/manual/api-guide.md — example-driven public-API walkthrough (tokens, reading, writing through the collab-safe path, labels, comments, error semantics) - docs/manual/mcp-guide.md — connecting AI assistants: switches, token scopes, Claude Code one-liner, mcp-remote bridge, tool table, audit and safety properties - docs/developer/extending.md — plugin development (sandbox contract, SDK, block plugins, bundled apps/fullscreen, shipping) and core contributions (stack, dev environment, gates, house rules) README: documentation index, repository-layout rows for docs/manual and docs/developer, and the stale "architecture phase" status brought up to reality. All relative links verified. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
This commit is contained in:
parent
6d710caa50
commit
eeb0ef6794
33
README.md
33
README.md
@ -32,15 +32,27 @@ offline support.
|
||||
first-run setup wizard yields a working instance. Start here:
|
||||
[`docs/self-hosting/README.md`](docs/self-hosting/README.md).
|
||||
|
||||
## Documentation
|
||||
|
||||
- **What is Dorfteich?** — [`docs/features.md`](docs/features.md)
|
||||
- **Manuals** (user / pond admin / site admin / API / MCP) —
|
||||
[`docs/manual/`](docs/manual/README.md)
|
||||
- **Extending it** (plugins, core) —
|
||||
[`docs/developer/extending.md`](docs/developer/extending.md)
|
||||
- **Running it** — [`docs/self-hosting/`](docs/self-hosting/README.md)
|
||||
- **How it works inside** — [`docs/architecture/`](docs/architecture/README.md)
|
||||
|
||||
## Repository layout
|
||||
|
||||
| Path | Contents |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `docs/architecture/` | Architecture documentation: ADRs, data model, permission model, collaboration and plugin concepts, deployment and operations |
|
||||
| `docs/self-hosting/` | Install, update, backup, and troubleshooting guide for running your own instance |
|
||||
| `apps/` | Application packages (web frontend, API server, collaboration server) — created as implementation proceeds |
|
||||
| `packages/` | Shared packages (types, permission logic, plugin SDK) |
|
||||
| `deploy/` | Docker Compose stacks and deployment tooling |
|
||||
| Path | Contents |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `docs/manual/` | User-facing manuals: user, pond-admin, site-admin, API, and MCP guides (start at [`docs/manual/README.md`](docs/manual/README.md)) |
|
||||
| `docs/developer/` | Extending Dorfteich: plugin development and core contributions |
|
||||
| `docs/architecture/` | Architecture documentation: ADRs, data model, permission model, collaboration and plugin concepts, deployment and operations |
|
||||
| `docs/self-hosting/` | Install, update, backup, and troubleshooting guide for running your own instance |
|
||||
| `apps/` | Application packages (web frontend, API server, collaboration server) — created as implementation proceeds |
|
||||
| `packages/` | Shared packages (types, permission logic, plugin SDK) |
|
||||
| `deploy/` | Docker Compose stacks and deployment tooling |
|
||||
|
||||
## Development
|
||||
|
||||
@ -60,9 +72,10 @@ imported as `@dorfteich/shared` — never copy code between apps.
|
||||
|
||||
## Status
|
||||
|
||||
The project is in the architecture and backlog phase. Implementation stories
|
||||
are tracked as issues in this repository. Start reading at
|
||||
[`docs/architecture/README.md`](docs/architecture/README.md).
|
||||
Feature-complete for a 1.0: collaboration, permissions, import/export,
|
||||
plugins, public REST API + MCP, backups with off-host copies and in-app
|
||||
restore — all shipped and release-gated. Work is tracked as issues in
|
||||
this repository.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
154
docs/developer/extending.md
Normal file
154
docs/developer/extending.md
Normal file
@ -0,0 +1,154 @@
|
||||
# Developer guide — extending Dorfteich
|
||||
|
||||
Two ways to make Dorfteich do more: write a **plugin** (no fork, no
|
||||
redeploy, safe by construction) or contribute to the **core**. Start
|
||||
with a plugin unless you need to change how the product itself works.
|
||||
|
||||
## Writing a plugin
|
||||
|
||||
Read [`docs/architecture/plugin-architecture.md`](../architecture/plugin-architecture.md)
|
||||
once — it is the contract. The short version:
|
||||
|
||||
A plugin is a ZIP with a `manifest.json`, a single ES-module bundle
|
||||
`plugin.js`, optional `styles.css`, `i18n/*.json`, and `assets/…`. It
|
||||
contributes one or more **extension points**:
|
||||
|
||||
| Type | You build | Example |
|
||||
| -------------- | ------------------------------------------------------ | ---------------------- |
|
||||
| `sectionStyle` | named CSS styles for content sections (no code at all) | `section-styles-basic` |
|
||||
| `pageTool` | a read-only widget in the page-tools panel | `toc`, `page-index` |
|
||||
| `block` | a custom editor block with its own data and edit UI | `mermaid`, `drawio` |
|
||||
|
||||
### The sandbox — what your code can and cannot do
|
||||
|
||||
Your `plugin.js` runs in an `<iframe sandbox="allow-scripts">` with an
|
||||
opaque origin and a strict CSP: **no cookies, no storage, no parent DOM,
|
||||
and network/frames only to your own bundled assets** — never to the api
|
||||
or any external host. Everything else goes through the typed RPC the
|
||||
SDK provides, executed with the _viewing user's_ permissions:
|
||||
|
||||
```ts
|
||||
import { createPlugin, windowTransport } from '@dorfteich/plugin-sdk';
|
||||
|
||||
const { host } = createPlugin({
|
||||
transport: windowTransport({
|
||||
target: { postMessage: (m) => window.parent.postMessage(m, '*') },
|
||||
source: window,
|
||||
}),
|
||||
onRender: async (ctx) => {
|
||||
const outline = await host.readCurrentPage.getOutline();
|
||||
document.body.textContent = outline.map((e) => e.text).join('\n');
|
||||
void host.ui.resize(document.body.scrollHeight + 16);
|
||||
},
|
||||
onEdit: async (ctx) => {
|
||||
/* block plugins: editing UI; persist via host.blockData.setData(...) */
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Capabilities you may declare in the manifest `permissions` and what they
|
||||
unlock: `readCurrentPage` (outline/content/meta), `readPond` (page
|
||||
lists + contents), `readBlock` (cross-page block reads), `blockData`
|
||||
(your block's `getData`/`setData` — writes become normal document
|
||||
changes, replicated and versioned), `ui` (`resize`, `openPage`, `toast`,
|
||||
`scrollToHeading`, `enterFullscreen`/`exitFullscreen`). Calls outside
|
||||
the declared set are rejected at runtime.
|
||||
|
||||
### Block plugins in three sentences
|
||||
|
||||
The host mounts your frame per block and calls `render` (view) or
|
||||
`edit` (the user pressed the block's edit button). Persist
|
||||
`{ …yourData }` via `host.blockData.setData` — collaborators' frames
|
||||
re-render live when the data changes under them. Store a static
|
||||
snapshot (e.g. an `svg` string) alongside your source data: exports and
|
||||
the public view show it through the manifest `fallback` machinery
|
||||
without ever executing plugin code.
|
||||
|
||||
### Bundled apps and fullscreen
|
||||
|
||||
A plugin may ship an entire sub-application as assets and run it in a
|
||||
child iframe of its own asset path — that is how the `drawio` plugin
|
||||
embeds the real draw.io editor. Combine with
|
||||
`host.ui.enterFullscreen()` for editors that need the whole screen.
|
||||
Size limits: 64 MiB ZIP, 256 MiB unpacked.
|
||||
|
||||
### Developing and shipping
|
||||
|
||||
The reference plugins under `packages/plugins/` are the templates —
|
||||
copy the closest one. Each has a `build.mjs` that bundles `src/plugin.ts`
|
||||
with esbuild and packs the installable ZIP into `dist/`:
|
||||
|
||||
```sh
|
||||
cd packages/plugins/<your-plugin>
|
||||
pnpm build # → dist/<id>-<version>.zip
|
||||
```
|
||||
|
||||
Install the ZIP via Admin → Plugins (or the dropzone), open the
|
||||
sandboxed preview at `/admin/plugins/<id>/preview`, iterate. The install
|
||||
gate validates structure, manifest, size and CSS scoping and rejects
|
||||
with a precise error code. Publishing an update = same id, higher
|
||||
version.
|
||||
|
||||
Conventions that will be enforced on review: UI strings via the plugin's
|
||||
`i18n/` files in **both** `de` and `en`; the fallback must make sense in
|
||||
a printed document.
|
||||
|
||||
## Working on the core
|
||||
|
||||
### Stack at a glance
|
||||
|
||||
TypeScript monorepo (pnpm workspaces): `apps/api` (NestJS + Prisma,
|
||||
PostgreSQL), `apps/collab` (Hocuspocus/Yjs realtime server),
|
||||
`apps/web` (React + Vite + TipTap), `apps/backup` (backup sidecar),
|
||||
`packages/shared` (types, schemas, editor schema, i18n catalogs),
|
||||
`packages/plugin-sdk`, `packages/plugins/*`. Architecture decisions live
|
||||
in [`docs/architecture/adr/`](../architecture/adr/) — read the relevant
|
||||
ADR before touching a subsystem; `docs/architecture/` has the deep dives
|
||||
(permissions, data model, realtime collaboration, security, plugins).
|
||||
|
||||
### Getting a dev environment
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
cd deploy/compose && cp .env.example .env
|
||||
# Full containerized dev stack (hot reload; first start installs deps):
|
||||
docker compose -f docker-compose.yml -f compose.dev.yml up
|
||||
# → web http://localhost:5173, api :3001, db :5434
|
||||
```
|
||||
|
||||
Fastest feedback: run only the database in Docker and web/api natively —
|
||||
the exact recipe is documented at the top of
|
||||
[`deploy/compose/compose.dev.yml`](../../deploy/compose/compose.dev.yml).
|
||||
Seed fixture users/ponds with `pnpm --filter @dorfteich/api db:seed`
|
||||
(fixture password: see `apps/api/prisma/seed.ts`).
|
||||
|
||||
### The gates every change must pass
|
||||
|
||||
```sh
|
||||
pnpm lint # ESLint + Prettier — no pipes that swallow exit codes
|
||||
pnpm typecheck
|
||||
pnpm test # vitest everywhere; DB-backed suites need TEST_DATABASE_URL
|
||||
pnpm i18n:check # every UI string in de AND en
|
||||
```
|
||||
|
||||
DB-backed tests run against the compose dev database:
|
||||
`TEST_DATABASE_URL=postgresql://dorfteich:dorfteich@localhost:5434/dorfteich pnpm test`.
|
||||
Playwright e2e packs live in `apps/web/e2e/` and run against a seeded
|
||||
local stack (see `.gitea/workflows/ci.yml` for the exact recipe).
|
||||
|
||||
### House rules worth knowing before your first PR
|
||||
|
||||
- **Permissions**: never answer an access question outside
|
||||
`PermissionService`/the route decorators; denied reads are 404, denied
|
||||
writes on readable things are 403
|
||||
([permissions.md](../architecture/permissions.md)).
|
||||
- **i18n**: no hard-coded UI strings; add keys to
|
||||
`packages/shared/i18n/{de,en}/…` (ADR 0012).
|
||||
- **No third-party requests** from the product, ever — fonts, editors,
|
||||
everything ships self-hosted (ADR 0016 sets the precedent).
|
||||
- **Migrations**: additive and reversible within one minor release; the
|
||||
release pipeline's QA gate replays an upgrade from the previous
|
||||
release against real data.
|
||||
- **Document contracts**: anything two services share (status files,
|
||||
NOTIFY channels, wire types) lives in `packages/shared` with a comment
|
||||
saying who reads and who writes.
|
||||
111
docs/features.md
Normal file
111
docs/features.md
Normal file
@ -0,0 +1,111 @@
|
||||
# Dorfteich — what it is and why you might want it
|
||||
|
||||
Dorfteich is an open-source wiki for people who want to think and write
|
||||
together — in real time, on their own server, without handing their
|
||||
knowledge to a cloud company.
|
||||
|
||||
The name means "village pond": the place where everyone in the village
|
||||
comes together. Your wiki is organized into **ponds** — one personal pond
|
||||
for every member, plus shared ponds for teams, clubs, families, or
|
||||
projects.
|
||||
|
||||
## Writing together, live
|
||||
|
||||
- **Real-time collaboration.** Open the same page as a colleague and
|
||||
watch each other type — with named cursors and a presence strip showing
|
||||
who is on the page. No locking, no "someone else is editing" dialogs,
|
||||
no lost changes.
|
||||
- **Works offline.** Keep typing when the connection drops; your edits
|
||||
merge back in automatically when you are online again.
|
||||
- **A friendly editor.** Headings, lists, task lists, tables, quotes,
|
||||
code blocks, and images — with full **Markdown** round-trip: what you
|
||||
write can always leave the system as clean Markdown again.
|
||||
- **Wikilinks.** Type `[[page-name]]` to link pages. Links to pages that
|
||||
do not exist yet are collected for you, one click creates them.
|
||||
Backlinks show you where every page is referenced.
|
||||
|
||||
## Never lose anything
|
||||
|
||||
- **Version history.** Every page keeps automatic snapshots plus named
|
||||
versions you save yourself. Compare, see who contributed, and restore
|
||||
any earlier state — restores are visible live in every open editor.
|
||||
- **Trash with a grace period.** Deleted pages sit in a per-pond trash
|
||||
and can be restored for weeks before they are purged.
|
||||
- **Real backups.** Nightly database + file backups, optional off-host
|
||||
copies to any **Nextcloud** you control, and a tested one-click restore
|
||||
— including a documented path to rebuild an instance from nothing.
|
||||
|
||||
## Organize the way you think
|
||||
|
||||
- **Labels**, hierarchical if you like, to slice a pond any way you want
|
||||
— and to scope access rules (see below).
|
||||
- **Fast full-text search** across everything you may read — accent- and
|
||||
umlaut-insensitive, with substring matching.
|
||||
- **A table of contents, page indexes, diagrams** and more through
|
||||
built-in plugins (see "Extensible" below).
|
||||
|
||||
## Share exactly as much as you want
|
||||
|
||||
- **Fine-grained permissions.** Grant read or write access per pond, per
|
||||
label, or per page — to individual people, to all signed-in members, or
|
||||
to the public internet. Deny rules carve out exceptions. A built-in
|
||||
inspector explains _why_ someone can or cannot see a page.
|
||||
- **Public pages.** Publish selected pages read-only to the world, with
|
||||
clean URLs — the rest of the pond stays private.
|
||||
- **Comments.** Discuss in threads next to the content, resolve what is
|
||||
settled, and choose per pond whether every reader or only editors may
|
||||
comment.
|
||||
- **Notifications you control.** Watch pages or whole ponds, get an
|
||||
in-app inbox, and choose e-mail digests (hourly, daily, or off) with a
|
||||
working unsubscribe link.
|
||||
|
||||
## Your documents come and go freely
|
||||
|
||||
- **Import** Word (`.docx`), LibreOffice (`.odt`), and Markdown files —
|
||||
including embedded images.
|
||||
- **Export** any page as Markdown, Word, LibreOffice, or **PDF** (with
|
||||
your pond's typography), and any pond as a ZIP of Markdown files. No
|
||||
lock-in, ever.
|
||||
|
||||
## Machines are welcome too — on your terms
|
||||
|
||||
- **REST API.** A clean, token-authenticated public API to read, write,
|
||||
search, label, and comment — with an OpenAPI description. Tokens carry
|
||||
exactly the permissions of their owner, never more.
|
||||
- **Built-in MCP endpoint.** Connect Claude Code or any MCP-capable AI
|
||||
assistant directly to your wiki — it can search, read, and (if you
|
||||
allow it) write pages. Both interfaces are **off by default** and each
|
||||
pond opts in separately.
|
||||
|
||||
## Extensible, but safely
|
||||
|
||||
- **Plugins** add block types (Mermaid diagrams, full **draw.io**
|
||||
editing), page tools (table of contents, page index), and section
|
||||
styles. Every plugin runs in a strict sandbox: no cookies, no storage,
|
||||
no network — it cannot read more than the person looking at it.
|
||||
- Reference plugins ship with the product and double as documented
|
||||
examples for writing your own.
|
||||
|
||||
## Private by design
|
||||
|
||||
- **Self-hosted.** One `docker compose up`, a friendly first-run wizard,
|
||||
and it is yours. Everything — fonts included — is served from your own
|
||||
domain: pages make **zero requests to third parties**.
|
||||
- **GDPR-friendly.** Imprint and privacy-policy pages built in (with
|
||||
templates), personal data export as ZIP, account deletion with
|
||||
content-preserving pseudonymization, and an audit trail of
|
||||
administrative actions.
|
||||
- **Bilingual.** The entire interface speaks German and English; every
|
||||
user picks their language.
|
||||
|
||||
## Honest operations
|
||||
|
||||
- Health endpoints that distinguish "down" from "degraded", an admin
|
||||
system panel with job status, backup state, audit log and storage
|
||||
overview, monthly automated restore drills — the operator can _prove_
|
||||
the backups work, not just hope.
|
||||
|
||||
---
|
||||
|
||||
_Dorfteich is MIT-licensed open source. If you can run Docker, you can
|
||||
run Dorfteich — see [self-hosting](self-hosting/README.md)._
|
||||
18
docs/manual/README.md
Normal file
18
docs/manual/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Dorfteich manuals
|
||||
|
||||
User-facing documentation, by audience. (German translations are
|
||||
planned; English is authoritative for now.)
|
||||
|
||||
| Guide | For |
|
||||
| -------------------------------------------- | ------------------------------------ |
|
||||
| [Feature overview](../features.md) | anyone wondering what Dorfteich is |
|
||||
| [User guide](user-guide.md) | everyday members |
|
||||
| [Pond-admin guide](pond-admin-guide.md) | people administering a pond |
|
||||
| [Site-admin guide](site-admin-guide.md) | instance administrators |
|
||||
| [API guide](api-guide.md) | scripts and integrations |
|
||||
| [MCP guide](mcp-guide.md) | connecting AI assistants |
|
||||
| [Developer guide](../developer/extending.md) | plugin authors and core contributors |
|
||||
|
||||
Operating an instance (install, update, backup, monitoring):
|
||||
[self-hosting](../self-hosting/README.md). Internals:
|
||||
[architecture](../architecture/README.md).
|
||||
131
docs/manual/api-guide.md
Normal file
131
docs/manual/api-guide.md
Normal file
@ -0,0 +1,131 @@
|
||||
# API guide
|
||||
|
||||
How to talk to Dorfteich from scripts and integrations. The public REST
|
||||
API lives at `/api/public/v1`; its machine-readable description is
|
||||
served at `/api/public/v1/openapi.json`.
|
||||
|
||||
## Switching it on
|
||||
|
||||
The API is **off by default**, twice:
|
||||
|
||||
1. A **site admin** enables the instance switch (Admin → Settings →
|
||||
Public API).
|
||||
2. Each **pond** that should be reachable opts in (pond settings →
|
||||
"Expose this pond through the public API").
|
||||
|
||||
Anything not enabled answers `404` — indistinguishable from an instance
|
||||
without the feature.
|
||||
|
||||
## Personal access tokens
|
||||
|
||||
Create tokens under **Settings → API tokens**: a name, a scope
|
||||
(`read` or `read+write`), an optional expiry date, and optionally a
|
||||
restriction to selected ponds. The secret (`dt_pat_…`) is shown **once**
|
||||
— copy it immediately. Tokens are revocable and show their last use.
|
||||
|
||||
A token acts **as you**: it can read and write exactly what you can,
|
||||
narrowed by its scope and pond restriction — never more. Token
|
||||
management itself always requires the browser session; a leaked token
|
||||
cannot mint new tokens.
|
||||
|
||||
Authenticate with a bearer header:
|
||||
|
||||
```sh
|
||||
curl -H "Authorization: Bearer dt_pat_..." \
|
||||
https://wiki.example.com/api/public/v1/me
|
||||
```
|
||||
|
||||
`GET /me` is the smoke test — it returns your user, the token scope,
|
||||
and any pond restriction.
|
||||
|
||||
## Reading
|
||||
|
||||
```sh
|
||||
# The ponds this token can reach
|
||||
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds
|
||||
|
||||
# Pages of a pond: slug, title, labels, timestamps
|
||||
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds/team/pages
|
||||
|
||||
# One page — Markdown source AND rendered, sanitized HTML
|
||||
curl -H "$AUTH" https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
|
||||
|
||||
# Full-text search (optionally ?pond=<slug>&label=<labelId>)
|
||||
curl -H "$AUTH" "https://wiki.example.com/api/public/v1/search?q=seerose"
|
||||
|
||||
# The whole pond as a Markdown ZIP
|
||||
curl -H "$AUTH" -o team.zip \
|
||||
https://wiki.example.com/api/public/v1/ponds/team/export/markdown
|
||||
```
|
||||
|
||||
Search snippets mark hits with `**…**`; results carry pond and page
|
||||
slugs for follow-up calls.
|
||||
|
||||
## Writing (requires the `write` scope)
|
||||
|
||||
```sh
|
||||
# Create a page from Markdown
|
||||
curl -H "$AUTH" -H 'Content-Type: application/json' \
|
||||
-d '{"title": "Meeting notes", "markdown": "# Agenda\n\n- Ducks\n"}' \
|
||||
https://wiki.example.com/api/public/v1/ponds/team/pages
|
||||
|
||||
# Rename and/or REPLACE the content
|
||||
curl -X PATCH -H "$AUTH" -H 'Content-Type: application/json' \
|
||||
-d '{"markdown": "New content."}' \
|
||||
https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
|
||||
|
||||
# Move a page to the trash
|
||||
curl -X DELETE -H "$AUTH" \
|
||||
https://wiki.example.com/api/public/v1/ponds/team/pages/meeting-notes
|
||||
```
|
||||
|
||||
A content `PATCH` **replaces** the whole page. It is applied through the
|
||||
live collaborative document: anyone editing the page at that moment sees
|
||||
the change appear, nothing forks, and the previous state remains in the
|
||||
version history as a restorable snapshot (the update itself shows up as
|
||||
a version named "API update").
|
||||
|
||||
## Labels
|
||||
|
||||
```sh
|
||||
GET /ponds/{pond}/labels # the label tree
|
||||
POST /ponds/{pond}/labels # {name, color?, parentId?}
|
||||
PATCH /ponds/{pond}/labels/{labelId} # rename/recolor/move in one call
|
||||
DELETE /ponds/{pond}/labels/{labelId}
|
||||
PUT /ponds/{pond}/pages/{page}/labels/{labelId} # assign
|
||||
DELETE /ponds/{pond}/pages/{page}/labels/{labelId} # unassign
|
||||
```
|
||||
|
||||
Label-tree management needs pond-admin rights (like in the app).
|
||||
|
||||
## Comments
|
||||
|
||||
```sh
|
||||
GET /ponds/{pond}/pages/{page}/comments?filter=all|open|resolved
|
||||
POST /ponds/{pond}/pages/{page}/comments # {body, parentId?} — Markdown
|
||||
POST /ponds/{pond}/pages/{page}/comments/{id}/resolve
|
||||
DELETE /ponds/{pond}/pages/{page}/comments/{id}/resolve # reopen
|
||||
```
|
||||
|
||||
The pond's comment policy applies exactly as in the app.
|
||||
|
||||
## Errors, limits, semantics
|
||||
|
||||
- Errors carry the uniform body `{ "code": "...", "message": "...",
|
||||
"details": {...} }`. The `code` is stable and machine-checkable.
|
||||
- **404 vs 403**: what you may not _read_ answers 404 (existence stays
|
||||
hidden — including ponds without the API opt-in); a write on
|
||||
something you may read but not change answers 403. A token without
|
||||
the `write` scope gets `403 scope_required` on every write route.
|
||||
- **Rate limit** per token; `429` responses carry a `Retry-After`
|
||||
header.
|
||||
- No cookies are involved anywhere — there is no CSRF surface, and
|
||||
browser sessions cannot call the public API.
|
||||
|
||||
## Out of scope (for now)
|
||||
|
||||
Attachment upload, version endpoints, and webhooks are deliberately not
|
||||
part of v1.
|
||||
|
||||
_Operator's view of the same feature (switches, security notes):
|
||||
[`docs/self-hosting/public-api.md`](../self-hosting/public-api.md)._
|
||||
100
docs/manual/mcp-guide.md
Normal file
100
docs/manual/mcp-guide.md
Normal file
@ -0,0 +1,100 @@
|
||||
# MCP guide — connecting your AI to Dorfteich
|
||||
|
||||
Dorfteich ships its own [MCP](https://modelcontextprotocol.io) endpoint
|
||||
at `/api/mcp` (Streamable HTTP). Any MCP-capable assistant — Claude
|
||||
Code, Claude Desktop via a bridge, and others — can search, read, and
|
||||
(if you allow it) write your wiki, with **exactly your permissions**.
|
||||
There is no extra server to run: the endpoint is part of the instance.
|
||||
|
||||
## Switching it on
|
||||
|
||||
Like the REST API, MCP is **off by default** and has its **own,
|
||||
independent switches**:
|
||||
|
||||
1. **Site admin**: Admin → Settings → Public API → "Enable the built-in
|
||||
MCP endpoint".
|
||||
2. **Each pond** that the assistant should see: pond settings → "Expose
|
||||
this pond to AI assistants (MCP)".
|
||||
|
||||
A pond without the opt-in is invisible to MCP clients — even to your own
|
||||
token.
|
||||
|
||||
## Get a token
|
||||
|
||||
MCP uses the same **personal access tokens** as the REST API: create one
|
||||
under **Settings → API tokens**. Pick the scope deliberately:
|
||||
|
||||
- `read` — the assistant can list, read, and search, nothing else.
|
||||
- `read+write` — it may also create/update pages, comment, and set
|
||||
labels.
|
||||
|
||||
Consider restricting the token to the specific pond(s) you want the
|
||||
assistant to work in.
|
||||
|
||||
## Connect Claude Code
|
||||
|
||||
```sh
|
||||
claude mcp add --transport http dorfteich https://wiki.example.com/api/mcp \
|
||||
--header "Authorization: Bearer dt_pat_..."
|
||||
```
|
||||
|
||||
That's it — Claude Code lists the tools on the next start. Stdio-only
|
||||
clients bridge with `mcp-remote`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"dorfteich": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"mcp-remote",
|
||||
"https://wiki.example.com/api/mcp",
|
||||
"--header",
|
||||
"Authorization: Bearer dt_pat_..."
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What the assistant can do
|
||||
|
||||
| Tool | Does |
|
||||
| -------------------------------------------- | ------------------------------------------- |
|
||||
| `list_ponds` | the ponds this token can reach |
|
||||
| `list_pages(pond)` | pages with slug, title, labels, timestamps |
|
||||
| `read_page(pond, page)` | a page as Markdown plus metadata |
|
||||
| `search(query, pond?, label?)` | full-text search with snippets |
|
||||
| `create_page(pond, title, markdown)` | new page from Markdown _(write)_ |
|
||||
| `update_page(pond, page, markdown?, title?)` | rename and/or replace content _(write)_ |
|
||||
| `add_comment(pond, page, text)` | comment on a page _(write)_ |
|
||||
| `list_labels(pond)` | the pond's label tree |
|
||||
| `set_page_labels(pond, page, labelIds)` | replace a page's labels _(write)_ |
|
||||
| `export_pond(pond)` | a download link for the Markdown-ZIP export |
|
||||
|
||||
Content updates travel the same collaborative path as human edits: open
|
||||
editors converge live, and the previous state stays in the version
|
||||
history — an AI edit can always be reviewed and reverted like any other
|
||||
change.
|
||||
|
||||
## Good to know
|
||||
|
||||
- **Permissions are yours.** The assistant sees precisely the pages your
|
||||
account may read; label-scoped rules, public/private, everything
|
||||
applies unchanged.
|
||||
- **Every write is audit-logged** with the token attributed — the site
|
||||
admin's audit viewer shows what the assistant changed.
|
||||
- **Rate-limited** per token; a runaway agent gets `429`, not a melted
|
||||
instance.
|
||||
- **Stateless**: each request stands alone; revoking the token under
|
||||
Settings → API tokens cuts the assistant off immediately.
|
||||
- The endpoint speaks MCP over Streamable HTTP (POST). GET/SSE session
|
||||
resumption is not offered — clients fall back to plain request/response,
|
||||
which every current client supports.
|
||||
|
||||
## A sensible first session
|
||||
|
||||
Ask your assistant to `list_ponds`, then `search` for something you know
|
||||
is there, `read_page` it, and — with a write token — draft a new page.
|
||||
Check the page's version history afterwards: you will find the
|
||||
assistant's edit as a normal, restorable version.
|
||||
104
docs/manual/pond-admin-guide.md
Normal file
104
docs/manual/pond-admin-guide.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Pond-admin guide
|
||||
|
||||
What you can configure on a pond you administer. You are a pond admin on
|
||||
your own personal pond and on every pond where you hold the
|
||||
`pond_admin` role. All of this lives behind the **gear icon** in the top
|
||||
bar (visible on pond routes when you may modify the pond).
|
||||
|
||||
## Ponds in one minute
|
||||
|
||||
Every member gets a **personal pond** automatically. Additional
|
||||
**shared ponds** are created through the API (`POST /api/v1/ponds`) and
|
||||
are subject to the per-user quota the site admin sets ("additional
|
||||
shared ponds per user", default 0). The creator becomes the pond admin.
|
||||
|
||||
## Name, description, appearance
|
||||
|
||||
- **Name and description** of the pond.
|
||||
- **Fonts**: pick heading/body/code typefaces per pond from the built-in,
|
||||
self-hosted catalog (browse it at `/fonts`) — they apply to the app
|
||||
view, public pages, and PDF exports.
|
||||
- **Sidebar sort** for everyone: A–Z, creation date, or manual order.
|
||||
|
||||
## Members and roles
|
||||
|
||||
The **members** section manages who is in the pond:
|
||||
|
||||
| Role | May |
|
||||
| ------------ | ----------------------------------------------- |
|
||||
| `reader` | read pages (as far as rules allow) |
|
||||
| `editor` | read + write pages, upload files |
|
||||
| `pond_admin` | everything, including settings, members, labels |
|
||||
|
||||
Member counts are limited by the instance quotas (editors/readers per
|
||||
pond). Personal ponds take members too — that is how you share yours.
|
||||
|
||||
## Access rules (the fine print)
|
||||
|
||||
Beyond plain membership, the **access rules** section edits grants
|
||||
directly. A grant is: _subject_ (a user, all signed-in users, or the
|
||||
public) + _role_ (reader/editor/pond admin) + _scope_ (whole pond, one
|
||||
label, or one page) + _effect_ (allow or deny).
|
||||
|
||||
- **Label-scoped rules** are the power tool: give the "board" label to
|
||||
the confidential pages and allow only the board members' grant on that
|
||||
label — or deny a label to someone who may otherwise read everything.
|
||||
- **Public pages:** an _allow, reader, public_ grant on a page (or a
|
||||
label) publishes it read-only at `/public/<pond>/<page>`.
|
||||
- Deny beats allow; reads that are denied look like "not found" (the
|
||||
system never reveals what exists).
|
||||
- The **permission inspector** on a page explains the effective result
|
||||
for any user — use it whenever a rule combination surprises you.
|
||||
|
||||
## Labels
|
||||
|
||||
Manage the pond's label tree (create, rename, recolor, nest, move,
|
||||
delete). Deleting a label that is still on pages asks for confirmation.
|
||||
Labels also appear in the page label picker, where creating new ones is
|
||||
reserved for you.
|
||||
|
||||
## Comments policy
|
||||
|
||||
Choose whether **all readers** may comment or **editors only**. Existing
|
||||
comments stay readable either way.
|
||||
|
||||
## Watching the pond
|
||||
|
||||
The bell in the pond settings header watches the whole pond — you will
|
||||
be notified about every page change and comment in it.
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugins the site admin has installed with mode _optional_ appear here
|
||||
with a per-pond toggle. _Required_ plugins are always active; _disabled_
|
||||
ones never show up. (Which plugins exist and what they do:
|
||||
[site-admin guide](site-admin-guide.md#plugins).)
|
||||
|
||||
## Machine access: API and MCP opt-in
|
||||
|
||||
Two separate switches expose this pond to token-based access — **both
|
||||
off by default**, and both only effective if the site admin has enabled
|
||||
the matching instance switch:
|
||||
|
||||
- **Public REST API** (`apiEnabled`): scripts and integrations may reach
|
||||
the pond with personal access tokens — with exactly the permissions of
|
||||
the token's owner.
|
||||
- **MCP / AI assistants** (`mcpEnabled`): MCP clients such as Claude
|
||||
Code may reach the pond the same way.
|
||||
|
||||
A pond that has not opted in is invisible through those interfaces, even
|
||||
to its own members' tokens.
|
||||
|
||||
## Files
|
||||
|
||||
The **file manager** lists the pond's uploads with their usage (which
|
||||
page references them) and lets you delete orphans. Storage counts
|
||||
against the pond's quota; the current usage is shown.
|
||||
|
||||
## Export and deletion
|
||||
|
||||
- **Export**: the whole pond as a ZIP of Markdown files plus media.
|
||||
- **Delete pond**: shared ponds can be moved to the site-level trash by
|
||||
their admin via the API (`DELETE /api/v1/ponds/<id>` — there is no UI
|
||||
button yet); a site admin can restore them. Your personal pond cannot
|
||||
be deleted — it is your account's home.
|
||||
132
docs/manual/site-admin-guide.md
Normal file
132
docs/manual/site-admin-guide.md
Normal file
@ -0,0 +1,132 @@
|
||||
# Site-admin guide
|
||||
|
||||
How to administer a Dorfteich instance from the browser. Installation,
|
||||
updates, and host-level operations are covered by the
|
||||
[self-hosting guide](../self-hosting/README.md); this guide is about the
|
||||
two admin pages: **Admin → Settings** (`/admin`) and **Admin → System**
|
||||
(`/admin/system`).
|
||||
|
||||
A site admin sees and may do everything — use a normal account for
|
||||
daily work.
|
||||
|
||||
## First contact: the setup wizard
|
||||
|
||||
A fresh instance greets you with a six-step wizard: language → the
|
||||
site-admin account → instance name and default language → SMTP relay
|
||||
(with a live test mail; skippable) → registration mode → done. Until it
|
||||
finishes, the instance answers everything with `503 setup_required`.
|
||||
Unattended installs pre-seed the wizard via `SETUP_ADMIN_*` environment
|
||||
variables.
|
||||
|
||||
## Admin → Settings
|
||||
|
||||
### Instance
|
||||
|
||||
- **Name** (shown in the top bar and mails) and **default language**
|
||||
(used for anonymous visitors and server-rendered pages).
|
||||
- **Registration mode**: `open` (anyone may sign up, with e-mail
|
||||
verification) or `closed` (only existing accounts sign in).
|
||||
|
||||
### Quotas
|
||||
|
||||
Instance-wide defaults: editors/readers per pond, additional shared
|
||||
ponds per user (default 0 — raise it or grant per-user overrides to let
|
||||
people create shared ponds), storage per pond, maximum file size. The
|
||||
**quota manager** below sets per-user/per-pond overrides that win over
|
||||
the defaults.
|
||||
|
||||
### Uploads
|
||||
|
||||
The allow-list of non-image file extensions users may attach, and the
|
||||
SVG policy (`sanitize` strips scripts from uploaded SVGs, `reject`
|
||||
refuses them).
|
||||
|
||||
### Public API and MCP
|
||||
|
||||
Two independent master switches, both **off by default**:
|
||||
|
||||
- **Public REST API**: lets users mint personal access tokens and use
|
||||
`/api/public/v1` (see the [API guide](api-guide.md)).
|
||||
- **Built-in MCP endpoint**: exposes `/api/mcp` for AI assistants
|
||||
([MCP guide](mcp-guide.md)).
|
||||
|
||||
Either switch alone does nothing per pond — each pond additionally opts
|
||||
in via its pond settings. Off means the endpoints answer 404.
|
||||
|
||||
### Legal pages
|
||||
|
||||
Imprint and privacy policy as Markdown, published at `/legal/imprint`
|
||||
and `/legal/privacy` and linked from every page footer. A template with
|
||||
a review checklist ships in
|
||||
[`docs/self-hosting/legal-template.md`](../self-hosting/legal-template.md).
|
||||
Until configured, the pages show a notice (and you a warning banner).
|
||||
|
||||
### Backups
|
||||
|
||||
See **Admin → System → Backups** below.
|
||||
|
||||
### Plugins
|
||||
|
||||
Install plugins by uploading a ZIP (alternatively: drop the ZIP into the
|
||||
`_dropzone/` folder on the plugins volume — a watcher installs it within
|
||||
seconds and moves rejected packages to `_quarantine/` with the reason).
|
||||
|
||||
Each installed plugin has an **instance mode**:
|
||||
|
||||
| Mode | Meaning |
|
||||
| ---------- | ----------------------------------------------- |
|
||||
| `disabled` | inactive everywhere (the default after install) |
|
||||
| `optional` | pond admins decide per pond |
|
||||
| `required` | active in every pond, no opt-out |
|
||||
|
||||
Every plugin has a sandboxed **preview** page for trying it before
|
||||
enabling. Uninstalling is blocked while a plugin is `required`;
|
||||
documents keep their plugin blocks either way and show the plugin's
|
||||
fallback text when it is missing.
|
||||
|
||||
Shipped reference plugins: `toc` (table of contents), `page-index`
|
||||
(label-filtered page list), `mermaid` (diagram blocks), `drawio`
|
||||
(full draw.io editing), `section-styles-basic` (colored callouts).
|
||||
|
||||
### Users
|
||||
|
||||
The user manager: search accounts, disable/enable, resend verification
|
||||
mails, promote/demote site admins, and delete accounts. Deletion offers
|
||||
**pseudonymization**: the account and its personal data disappear, but
|
||||
shared content survives attributed to a neutral placeholder. Guards
|
||||
prevent disabling yourself or removing the last site admin.
|
||||
|
||||
## Admin → System
|
||||
|
||||
The operator's single glance:
|
||||
|
||||
- **Jobs**: every maintenance job (trash purge, version thinning, page
|
||||
compaction, data-export purge, notification digests) with cadence,
|
||||
last run, duration and outcome — plus a manual **Run** button (itself
|
||||
audit-logged).
|
||||
- **Backups**: the status card mirrors the sidecar's last run and its
|
||||
freshness verdict, with a **Back up now** button. Below it:
|
||||
- **Backup settings**: local retention (overrides the container
|
||||
default), and the **Nextcloud target** — server address, username,
|
||||
app password (kept in the file-based secret store on the secrets
|
||||
volume, never in the database), folder, upload schedule (after every backup / weekly
|
||||
/ manual), remote retention, and a **Test connection** button that
|
||||
verifies credentials and creates the folder.
|
||||
- **Restore**: lists local and Nextcloud sets; restoring asks you to
|
||||
re-type the backup id, then the instance enters maintenance mode,
|
||||
restores itself, and restarts. Everything else about backups (mirror
|
||||
to a private host, disaster recovery) lives in the
|
||||
[self-hosting guide](../self-hosting/README.md#backups--restore) and
|
||||
the [restore runbook](../operations/restore-runbook.md).
|
||||
- **Audit log**: administrative and auth events (grants, members, user
|
||||
admin, quotas, plugins, settings, setup, tokens, API writes, backup
|
||||
actions) with actor/action/time filters, 50 per page.
|
||||
- **Storage**: the twenty largest ponds and the instance total.
|
||||
|
||||
## Health, monitoring, go-live
|
||||
|
||||
- `GET /api/v1/readyz` is the instance's own diagnosis; monitor it
|
||||
(down vs. degraded semantics and a ready-made monitor set:
|
||||
[`deploy/monitoring.md`](../../deploy/monitoring.md)).
|
||||
- Going live checklist for a fresh production instance:
|
||||
[`deploy/go-live.md`](../../deploy/go-live.md).
|
||||
118
docs/manual/user-guide.md
Normal file
118
docs/manual/user-guide.md
Normal file
@ -0,0 +1,118 @@
|
||||
# User guide
|
||||
|
||||
How to find your way around Dorfteich as a regular member. For pond
|
||||
configuration see the [pond-admin guide](pond-admin-guide.md); for
|
||||
instance administration the [site-admin guide](site-admin-guide.md).
|
||||
|
||||
## Signing up and signing in
|
||||
|
||||
- **Sign up** (if the instance allows open registration): username,
|
||||
e-mail, display name, password, language. You confirm your e-mail via
|
||||
the link in the verification mail; that also creates your **personal
|
||||
pond** — your own space that only you can see until you share it.
|
||||
- **Sign in** with username _or_ e-mail. Forgot your password? The
|
||||
sign-in page has a reset link (requires the instance to have mail
|
||||
configured).
|
||||
- Your sessions are listed under **Settings → Sessions**; you can revoke
|
||||
any device from there.
|
||||
|
||||
## Ponds and pages
|
||||
|
||||
- The **pond switcher** in the top bar moves you between the ponds you
|
||||
can see. The **sidebar** lists the pages of the current pond — sort
|
||||
them A–Z, by creation date, or drag them into a manual order (the sort
|
||||
mode is a pond setting).
|
||||
- **+ New page** at the bottom of the sidebar creates a page. Page
|
||||
addresses are readable: `/p/<pond>/<page>`.
|
||||
- The **trash** link sits at the very bottom of the sidebar: deleted
|
||||
pages can be restored from there until the retention period ends.
|
||||
|
||||
## The editor
|
||||
|
||||
Click the **pencil icon** in the top bar to switch a page between
|
||||
reading and editing. In edit mode a toolbar offers paragraph styles
|
||||
(H1–H4), bold/italic/strikethrough/inline code, bullet/numbered/task
|
||||
lists, quotes, code blocks, horizontal rules, images, and tables. The
|
||||
toolbar stays visible while you scroll.
|
||||
|
||||
- **Everyone edits together.** Other people on the page appear in the
|
||||
presence strip in the top bar and as named cursors in the text.
|
||||
There is no save button for content — every keystroke is persisted and
|
||||
replicated live.
|
||||
- **Offline?** The status icon in the footer (bottom left) shows your
|
||||
connection. You can keep typing offline; changes sync on reconnect.
|
||||
- **Markdown in, Markdown out.** You can paste or type Markdown; the
|
||||
page can always be copied or downloaded as Markdown again (**…**
|
||||
overflow menu → Copy/Download Markdown).
|
||||
- **Wikilinks:** type `[[page-slug]]` or `[[page-slug|shown text]]`.
|
||||
Links to pages that do not exist yet are listed on the pond home page
|
||||
("phantom pages") — one click creates the target. The **backlinks**
|
||||
panel of a page shows every page that links to it.
|
||||
- **Images and attachments:** paste or drag images straight into the
|
||||
text. Other file types (PDFs etc., as allowed by the instance) attach
|
||||
to the page via the **paperclip icon**.
|
||||
- **Named versions:** the **save icon** in edit mode stores a named
|
||||
snapshot ("before the big rewrite"). The **history icon** lists all
|
||||
versions — automatic and named — with their contributors; you can view
|
||||
any version and restore it. Restoring never deletes history.
|
||||
|
||||
## The top-bar page actions
|
||||
|
||||
When a page is open you find, next to the pencil: **watch** (bell for
|
||||
this page), **comments** (with unread count), **attachments**,
|
||||
**plugin tools** (table of contents, page index — when enabled),
|
||||
**labels**, **history**, and the **…** overflow menu (copy/download
|
||||
Markdown, export to Word/LibreOffice/PDF, delete).
|
||||
|
||||
## Labels
|
||||
|
||||
Open the **label icon** to tag the page. You can pick existing labels or
|
||||
create one on the spot (creating is for pond admins). Labels organize
|
||||
pages and can carry access rules — a page inherits every rule of its
|
||||
labels.
|
||||
|
||||
## Search
|
||||
|
||||
The search field in the top bar searches every page you are allowed to
|
||||
read, across all ponds — tolerant of accents ("Baume" finds "Bäume") and
|
||||
of partial words. Recent searches are remembered (and can be cleared).
|
||||
|
||||
## Comments
|
||||
|
||||
The **speech-bubble icon** opens the comment panel: threads with one
|
||||
reply level, Markdown supported, edit and delete for your own comments,
|
||||
**resolve** to fold finished discussions away. Whether every reader or
|
||||
only editors may comment is a pond setting.
|
||||
|
||||
## Watches, notifications, digests
|
||||
|
||||
- **Watch** a page (bell in the page actions) or a whole pond (bell in
|
||||
the pond settings header) to be notified about changes and comments.
|
||||
By default you automatically watch pages you create or comment on —
|
||||
both switches live under **Settings → Profile**.
|
||||
- The **bell in the top bar** is your notification inbox; entries link
|
||||
straight to the change (comment notifications open the panel).
|
||||
- **E-mail digests** bundle unread notifications hourly or daily —
|
||||
configure under Settings, unsubscribe from any digest mail directly.
|
||||
|
||||
## Import and export
|
||||
|
||||
- **Import a document** (sidebar link): `.docx`, `.odt`, or `.md`
|
||||
becomes a new page, embedded images included.
|
||||
- **Export a page**: overflow menu → Markdown / Word / LibreOffice /
|
||||
PDF. **Export a pond**: pond settings → ZIP of all pages you may read,
|
||||
as Markdown plus media.
|
||||
|
||||
## Your settings (top-right → Settings)
|
||||
|
||||
Profile (display name, e-mail, language, watch defaults, digest
|
||||
frequency), password, active sessions, your watches, **API tokens** (for
|
||||
scripts and AI assistants — see the [API guide](api-guide.md) and
|
||||
[MCP guide](mcp-guide.md)), and **data export**: a ZIP with your profile
|
||||
data and the full content of your own ponds.
|
||||
|
||||
## Public pages
|
||||
|
||||
If a pond admin has published a page for the public, it is readable
|
||||
without an account at `/public/<pond>/<page>` — with the pond's
|
||||
typography and a link to the instance's legal pages.
|
||||
Loading…
Reference in New Issue
Block a user