|
All checks were successful
CD / Build and push images (push) Successful in 3m57s
CI / Lint, typecheck, test (push) Successful in 3m7s
CI / Auth e2e pack (push) Successful in 3m58s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m14s
CD / Promote to Int (push) Successful in 11s
Two export paths, both permission-aware (permissions.md):
- `GET /ponds/:id/export/markdown` streams a ZIP of the pond's readable
pages as Markdown (one `<slug>.md` per page, a `media/` directory,
wikilinks rewritten to relative `[text](slug.md)` links, image sources to
`media/<id>.<ext>`). The `reader` guard is "may see the pond"; the service
filters to the pages the requester may actually read, so a label-restricted
reader gets only their slice. Media is appended as read streams and pages as
small strings, so memory stays bounded for a large pond (500-page test).
- `POST /pages/:id/export {format: docx|odt}` enqueues a `markdown → pandoc →
file` conversion job (the #62 queue): embedded images are inlined as data
URIs so the sidecar embeds them, wikilinks flatten to text. The client polls
`GET /jobs/:id` and downloads `GET /jobs/:id/result`.
Frontend: office-export buttons in the page menu (`.docx`/`.odt` run the job
and download the result; PDF is a disabled placeholder for Gotenberg, #67) and
a "Download pond as ZIP" link in pond settings. New `export` i18n namespace
(de+en). Markdown copy/download stay as-is (#30).
Robustness: the pond ZIP skips an attachment whose bytes are missing on disk
(data drift) rather than letting an unhandled read-stream error crash the api;
`FileStorageService.exists` gates inclusion, with a defensive stream error
handler. The per-page export drops an unreadable image the same way.
- shared: EXPORT_FORMATS + pageExportInputSchema; export-markdown transform
helpers (image/wikilink rewrites, MIME→extension).
- deps: archiver (streaming ZIP; v7 for CommonJS compat), fflate (dev, reads
ZIPs in tests).
- tests: export-markdown unit + export.service.db (ZIP contents & relative
links, label-restricted omission, docx job with inlined images, 500-page
streaming, missing-media skip); e2e export pack (ZIP download; `.docx`
self-skips without a pandoc sidecar, as in the import pack, #64).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
|
||
|---|---|---|
| .gitea/workflows | ||
| apps | ||
| deploy | ||
| docs/architecture | ||
| fixtures/import | ||
| packages/shared | ||
| scripts | ||
| .dockerignore | ||
| .editorconfig | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc.json | ||
| eslint.config.mjs | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.base.json | ||
Dorfteich
Dorfteich is an open-source wiki system built around ponds (German: Teiche) — self-contained wiki spaces that people and teams organize freely with hierarchical labels, directories, and Obsidian-style page relations. Pages are edited in a collaborative WYSIWYG editor with live cursors and offline support.
- Project site: https://dorfteich.cloud
- Public flagship instance: https://dorfteich.online
- License: MIT
Key features
- Real-time collaboration — multiple people edit the same page simultaneously; everyone sees the other participants' cursors and input live. Offline edits merge conflict-free on reconnect (CRDT-based).
- Ponds — isolated wiki spaces with their own members, permissions, fonts, and page organization. Every registered person gets a personal pond.
- Flexible organization — hierarchical labels, free page ordering,
[[wikilinks]]with backlinks. A classic page tree is possible but never enforced. - Fine-grained permissions — roles (Site Admin, Pond Admin, Editor, Reader, Public) can be granted per pond, per label, or per page; the most specific setting wins.
- Import & export — Markdown as the primary exchange format, plus best-effort structural import from Word/OpenOffice and export to Word/OpenOffice/PDF.
- Plugins — sandboxed extensions (custom blocks, styles, page tools) installable at runtime without redeploying the instance.
- Self-hosting first — a single
docker compose upplus a guided first-run setup wizard yields a working instance.
Repository layout
| Path | Contents |
|---|---|
docs/architecture/ |
Architecture documentation: ADRs, data model, permission model, collaboration and plugin concepts, deployment and operations |
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
Requirements: Node.js ≥ 22 and pnpm (npm install -g pnpm).
pnpm install # install all workspace dependencies
pnpm lint # ESLint + Prettier check across the repo
pnpm typecheck # TypeScript --noEmit in every package
pnpm test # Vitest in every package
pnpm build # build every package (dependency order)
The workspace packages live under apps/ (web, api, collab) and
packages/ (shared). Shared logic goes into packages/shared and is
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.
Contributing
Code, comments, and documentation are written in English. Write clear code that humans can follow easily; when in doubt, prefer readability over cleverness. All contributions are accepted under the MIT license.