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

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:
Claude Fable 5 2026-07-12 17:18:30 +02:00
parent 6d710caa50
commit eeb0ef6794
9 changed files with 891 additions and 10 deletions

View File

@ -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
View 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
View 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
View 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
View 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
View 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.

View 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: AZ, 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.

View 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
View 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 AZ, 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
(H1H4), 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.