# diwan **Repository Path**: AJiangS/diwan ## Basic Information - **Project Name**: diwan - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-04 - **Last Updated**: 2026-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
Diwan # Diwan [![CI](https://github.com/vul-os/diwan/actions/workflows/ci.yml/badge.svg)](https://github.com/vul-os/diwan/actions/workflows/ci.yml) [![Latest release](https://img.shields.io/github/v/release/vul-os/diwan?sort=semver&label=release)](https://github.com/vul-os/diwan/releases) [![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE-MIT) [![Go 1.25](https://img.shields.io/badge/Go-1.25-00ADD8?logo=go&logoColor=white)](go.mod) [![React 18](https://img.shields.io/badge/React-18-61DAFB?logo=react&logoColor=white)](web/package.json) ### A real, self-hostable collaborative office suite you own. Documents, spreadsheets, slides, and whiteboards — **CRDT-native** and **real-time**, shipped as a single binary, running on **your own storage**. No cloud account, no telemetry, no lock-in. **[Changelog](CHANGELOG.md) · [MIT OR Apache-2.0](LICENSE-MIT) · [Self-hostable, single binary](docs/SELFHOST.md) · [CRDT, real-time P2P](docs/COLLABORATION.md) · Go 1.25 · React 18** [**Quickstart**](#quick-start) · [**Docs**](docs/) · [**Collaboration**](docs/COLLABORATION.md) · [**Architecture**](docs/ARCHITECTURE.md) · [**Self-hosting**](docs/SELFHOST.md)
Diwan — documents, sheets, slides, and whiteboards in one warm, self-hosted suite
--- ## What is Diwan? Diwan is a **standalone, self-hostable office suite** — documents, spreadsheets, slides, and whiteboards in one clean, modern web app, shipped as a **single Go binary** with the entire frontend embedded. There is no cloud account to create, nothing phones home, and your files live in **your own storage**. Real-time co-editing is **peer-to-peer and CRDT-native**: there is no central document server. Peers sync directly over an end-to-end-encrypted channel, and because edits are conflict-free (CRDTs), everyone converges with no authority in the middle. What you run is what you own. It carries the torch lit by **LibreOffice** and **OpenOffice** — the projects that proved productivity software can be free, open, and community-driven — into the browser, on a fast React frontend and a lightweight Go backend. ```mermaid %%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-monospace, SFMono-Regular, Menlo, monospace','primaryColor':'#2A241C','primaryBorderColor':'#8E8677','primaryTextColor':'#F1EBE0','lineColor':'#D0471F','edgeLabelBackground':'#201B15','tertiaryTextColor':'#F1EBE0','clusterBorder':'#8E8677','clusterBkg':'transparent'}}}%% flowchart LR classDef entry fill:#201B15,stroke:#8E8677,color:#C3BAAC classDef subject fill:#AE3917,stroke:#FF8759,color:#FFF1EA classDef downstream fill:#2A241C,stroke:#8E8677,color:#F1EBE0 you["you (browser)"] -->|edits| diwan["Diwan
single binary"] peer["a collaborator"] -.->|"E2E-encrypted P2P (WebRTC)"| you diwan --> store["your storage
files · SQLite · Postgres · S3"] diwan --> surfaces["Docs · Sheets · Slides
Whiteboards · PDF signing"] class you,peer entry class diwan subject class store,surfaces downstream ``` > *A diwan was a register of records, and a collected volume of work. This one is yours.* The mark is an **iwan** — the vaulted portal at the heart of Persian and Ottoman architecture, the arch you pass through to reach the room where the registers were kept. Give it a quarter turn clockwise and it becomes a **D**: the arch's two legs are the bars, the teal threshold is the stem. --- ## Features | | | |---|---| | 📝 **Documents** | Rich-text editing (TipTap) — headings, tables, inline images, footnotes, task lists, links; anchored **comments**, **suggestions** (track-changes with accept/reject), **version history** with restore, find/replace, live outline + word count. | | 📊 **Spreadsheets** | A full grid (Fortune Sheet) — formulas, number formats, conditional formatting, **data validation**, **charts**, **filters**, **pivot tables**, **named ranges**, freeze panes. | | 🖼️ **Slides** | A from-scratch positioned-object canvas — free drag/resize/rotate of text, shapes, and images; per-element **animations**, **themes**, editable **master slides**, per-slide **transitions**, and a **presenter view** (notes + timer). | | 🎨 **Whiteboards** | An infinite hand-drawn canvas built on the MIT [Excalidraw](https://github.com/excalidraw/excalidraw) editor — shapes, arrows, freehand, text, and images. The scene is a **Yjs CRDT** synced over the **same** E2E-encrypted P2P engine as Docs. | | ⚡ **Real-time co-editing** | **Always peer-to-peer, no central document server.** Edits sync as CRDT updates inside an **end-to-end-encrypted** room; peers connect directly over WebRTC with a **content-blind relay** only as a hard-NAT fallback. Share by invite link — the key rides the URL fragment and never reaches any server. | | 📄 **PDF import / export & signing** | Import and export `.docx` · `.xlsx` · `.csv` · `.pptx` · Markdown · HTML · **PDF**. View, annotate, fill AcroForm fields, and **sign** PDFs, including multi-party signing envelopes with a cryptographic audit trail. | | 💾 **Your own storage** | Local files + SQLite by default; optional **PostgreSQL** (schema `office`) for multi-user; optional **S3-compatible** object store. Nothing is hosted for you unless you choose it. | | 🔓 **No lock-in** | Open formats in and out, MIT-licensed, single self-contained binary. Every editor is also published as an npm library (the `diwan` package — `diwan/docs`, `diwan/sheets`, `diwan/slides`, `diwan/whiteboard`, `diwan/pdf`) so you can embed any surface in your own app. | Diwan is **documents-only** by design: Docs, Sheets, Slides, Whiteboards, and PDF signing. Chat, video, and mail are deliberately *not* part of it. --- ## Screenshots Diwan wears a warm, **light-first** "Workshop" identity — an ember/terracotta accent, a paper-tinted canvas, Fraunces on the page and Hanken Grotesk in the chrome — with a full dark theme (and *System*) one click away. | | | | :---: | :---: | | **Documents** — the Fraunces "paper", comments & suggestions | **Spreadsheets** — formulas, formats, charts, pivots | | Diwan Documents editor | Diwan Spreadsheets editor | | **Slides** — masters, themes, transitions, present | **Whiteboards** — Excalidraw canvas on the P2P CRDT engine | | Diwan Slides editor | Diwan Whiteboard editor | | **Files** — your docs, sheets, slides & local drive | **Signing** — annotate & sign PDFs | | Diwan Docs file list | Diwan PDF signing | **Light & dark** — every surface ships both, light-first: | | | | :---: | :---: | | Diwan workspace, dark theme | Diwan Documents editor, dark theme | > Regenerate anytime with `npm run screenshots` — it boots the app with seeded > demo data (no real backend or credentials needed) and captures every surface > in light **and** dark at retina. See [docs/SCREENSHOTS.md](docs/SCREENSHOTS.md). --- ## Quick start Diwan runs **by itself** — no account, no cloud, no external service required. ### Docker (one-liner) ```bash docker run -d \ --name diwan \ -p 8080:8080 \ -v diwan-data:/srv/data \ ghcr.io/vul-os/diwan:latest ``` Open . ### From source (single binary) Prerequisites: [Go 1.25+](https://golang.org/dl/) and [Node.js 18+](https://nodejs.org/) with npm. ```bash git clone https://github.com/vul-os/diwan.git cd diwan # Install deps and build the frontend + single binary npm install npm run build # Run — single-user, local storage, no auth, no cloud ./diwan ``` Open . Data lives in `./data` and `./uploads` — that's the whole app, in one file. The Go module and the binary it builds are named `diwan`; the npm package and the product are **Diwan**. To require login (still fully standalone): ```bash # config.yaml → auth.enabled: true export DIWAN_JWT_SECRET="$(openssl rand -hex 32)" ./diwan ``` ### Develop ```bash npm run dev:web # Vite dev server (:5173) + Go API (:8080), live reload ``` Open . ### Install from the Vulos app store Diwan also installs as a one-click app on a **Vulos OS** box (`DEPLOY_MODE=os`), where it runs behind the box gateway with scoped storage and single sign-on. It is the **same binary** — the app store just wires identity and storage for you. Self-hosting it yourself is always the default path, and never second-class. --- ## Architecture ```mermaid %%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-monospace, SFMono-Regular, Menlo, monospace','primaryColor':'#2A241C','primaryBorderColor':'#8E8677','primaryTextColor':'#F1EBE0','lineColor':'#D0471F','edgeLabelBackground':'#201B15','tertiaryTextColor':'#F1EBE0','clusterBorder':'#8E8677','clusterBkg':'transparent'}}}%% flowchart TD classDef entry fill:#201B15,stroke:#8E8677,color:#C3BAAC classDef subject fill:#AE3917,stroke:#FF8759,color:#FFF1EA classDef downstream fill:#2A241C,stroke:#8E8677,color:#F1EBE0 FE["React + Vite + Tailwind frontend
Docs · Sheets · Slides · Whiteboards · PDF signing"] BE["Go backend (Gin)
handlers · userauth · signing · storage · obs"] Seam["backend/seam — Identity · Entitlements · Usage
standalone defaults (local, unlimited, no-op)"] Adapter["backend/integration
(optional identity/entitlements adapter, opt-in)"] FE -->|"embedded into the binary"| BE BE --> Seam Seam -->|optional| Adapter class FE entry class BE subject class Seam,Adapter downstream ``` Diwan is a **single Go binary with the whole frontend embedded** — one file to deploy. With zero configuration it runs as a single-user, local-storage app on your own machine. Everything that *could* tie it to an external service lives behind a small set of Go interfaces in `backend/seam`; the standalone build wires local, unlimited, no-op defaults and never imports the optional adapter. Real-time collaboration is **CRDT-based and always peer-to-peer**: Docs and whiteboards sync as Yjs updates, Sheets and Slides use LWW/tree CRDTs, all inside an end-to-end-encrypted room whose key never reaches any server. The only server role is **content-blind peer discovery** — it learns *that* peers share a random room id, never any content — and **this binary serves that itself**, at `/api/rendezvous/*`, on by default. So one `diwan` on one box is all two people need: **no Vulos OS, no Pier, no relay, no account, nothing to configure**. You *may* delegate discovery to your own `vulos-relayd` instead (`collab.rendezvous_url` / `VULOS_RENDEZVOUS_URL`), and it then takes precedence — the browser talks to that relay directly and Diwan's server is not in the discovery path at all. See [docs/COLLABORATION.md](docs/COLLABORATION.md) §3 and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). --- ## Documentation Full documentation lives in **[`docs/`](docs/)**. | Document | Description | |----------|-------------| | [Getting started](docs/GETTING-STARTED.md) | Run it locally, in Docker, or in production | | [Self-hosting](docs/SELFHOST.md) | Run fully standalone; the optional identity/entitlements seam | | [Collaboration](docs/COLLABORATION.md) | How real-time P2P CRDT editing works, end to end | | [Architecture](docs/ARCHITECTURE.md) | Component map and design decisions | | [Configuration](docs/CONFIGURATION.md) | Env vars, `config.yaml`, storage, OTEL reference | | [API](docs/API.md) | REST API — files, versions, collab, signing | | [Admin guide](docs/ADMIN-GUIDE.md) | Deploy, back up, and operate the server | | [Deploy](docs/DEPLOY.md) | Docker, single-box co-location, static CDN | | [Testing](docs/TESTING.md) | Vitest unit + RTL/MSW integration, Playwright E2E | | [Roadmap](ROADMAP.md) · [Changelog](CHANGELOG.md) | Plans and version history | --- ## Development ```bash npm run dev:web # Vite (:5173) + Go API (:8080) npm test # unit + RTL/MSW integration tests (Vitest) npm run test:e2e # browser E2E (Playwright, backend mocked) npm run test:e2e:p2p # REAL P2P: one real binary + two real browsers, no external deps npm run build # frontend dist/ + Go binary npm run screenshots # regenerate the docs/screenshots gallery go build ./... && go test ./... && go vet ./... ``` > **Frozen invariants:** pure Go (no CGO), JSX only (never `.tsx`), no third-party > SSO or payment lock-in in the standalone build. See [CONTRIBUTING.md](CONTRIBUTING.md). --- ## Security Diwan centralises HTML sanitisation in one audited DOMPurify policy, treats CRDT ingress as fail-closed, gates read-only collaborators cryptographically, and enforces per-file ACLs when multi-user auth is on. Found a vulnerability? Please report it **privately** — see [SECURITY.md](SECURITY.md), [THREAT-MODEL.md](docs/THREAT-MODEL.md), and [SECURITY-TESTING.md](docs/SECURITY-TESTING.md). Do not open public issues for security reports. --- ## Contributing Pull requests are welcome — bug fixes, signing robustness, accessibility, tests, and docs especially. For major changes, open an issue first. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, code style, and the frozen invariants. No CLA required. --- ## Brand The mark in [`brand/`](brand/) is the source of truth. Every icon this repo ships — favicon, PWA and app icons, the mark in the README and on the site — is rendered from `brand/logo.svg` rather than redrawn, so there is one approved drawing and no second copy to drift. Copy it outward, never edit a derived copy, and never edit `brand/` to match something downstream. ## License [MIT](LICENSE-MIT) OR [Apache-2.0](LICENSE-APACHE) — © VulOS. Diwan is a VulOS project; source and issues at [github.com/vul-os/diwan](https://github.com/vul-os/diwan). ---

vulos
vulos — open by design