diff --git a/INSTALL.md b/INSTALL.md index 7f69e16..2bf5e37 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -50,6 +50,14 @@ Open `http://your-host:8080` and log in with the admin credentials above. | `MH_LDAP_USER_FILTER` | No | `(&(objectClass=inetOrgPerson)(uid=%s))` | LDAP search filter (`%s` = username) | | `MH_LDAP_SKIP_TLS` | No | `false` | Skip TLS verification (for self-signed certs) | +### LDAP Notes + +- Use `ldaps://host:636` for SLDAP (LDAP over TLS) +- LDAP settings can also be configured from the **Admin panel** (⚙️ → 👤) without restarting +- If a required group is set, only users who are members of that group can log in +- On first LDAP login, a local user is auto-created (for preferences, file storage, etc.) +- Local accounts still work alongside LDAP — local auth is tried first + ## Data Volume Mount a persistent volume to `/app/data`. This contains: diff --git a/README.md b/README.md index e66a6b4..1001842 100644 --- a/README.md +++ b/README.md @@ -4,50 +4,41 @@ Self-hosted collaborative markdown workspace with real-time editing, Git integra ## Features -- **Three editor modes**: WYSIWYG (Milkdown), raw markdown (CodeMirror-style), and split-pane with live preview -- **File management**: Tree-based file browser, folders, search, create/delete +- **Three editor modes**: WYSIWYG (Milkdown), raw markdown, and split-pane with live preview +- **File management**: Tree-based file browser, folders, search, drag-and-drop, rename, trash - **Git versioning**: Auto-commit on save, full history, diff viewer, restore previous versions - **External Git sync**: Per-user remotes (Gitea, GitHub, etc.), push/pull on demand +- **Real-time collaboration**: Yjs CRDT via WebSocket — multiple users editing simultaneously - **Sharing**: Share files/folders with other users (read-only or read-write) - **AI integration**: Verify specs, generate prompts, summarize — via LiteLLM/vLLM - **AI Build Pipeline**: Write a spec → verify → build entire project → push to Gitea -- **2FA**: TOTP-based two-factor authentication +- **Authentication**: Local accounts, LDAP/SLDAP, TOTP 2FA, group-based access control - **Light/Dark theme**: Toggle in UI, persisted in preferences - **Export**: PDF, HTML, raw markdown download -- **Offline-ready**: PWA architecture (planned) -- **Multi-device**: Responsive, works on desktop and iPad +- **Image upload**: Drag-drop images into the editor +- **PWA / Offline**: Service worker, IndexedDB caching, sync on reconnect +- **Multi-device**: Responsive with mobile hamburger menu - **Docker deployment**: Single container, easy backup +- **Admin panel**: User management, LDAP configuration (no restart needed) +- **Security**: Rate limiting, encrypted tokens, audit log, password complexity ## Quick Start -### Docker (recommended) - ```bash +git clone https://git.aholck.net/anders-pub/markdown-hub.git +cd markdown-hub docker build -t markdownhub . docker run -d --name markdownhub \ + --restart unless-stopped \ -p 8080:8080 \ -v ./data:/app/data \ - -e MH_SECRET=your-random-secret \ + -e MH_SECRET="$(openssl rand -hex 32)" \ markdownhub ``` -Default admin: `admin@localhost` / `admin` +Default admin: `admin@localhost` / `admin` — **change password immediately**. -### Development - -**Backend:** -```bash -go run ./cmd/server -``` - -**Frontend:** -```bash -cd frontend -npm install -npm run dev -``` - -Frontend dev server proxies API calls to `localhost:8080`. +See [INSTALL.md](INSTALL.md) for full deployment guide. ## Configuration @@ -63,6 +54,15 @@ Environment variables: | `MH_AI_ENDPOINT` | — | LiteLLM-compatible API URL | | `MH_AI_API_KEY` | — | API key for AI endpoint | | `MH_AI_MODEL` | `gpt-4` | Default model for AI features | +| `MH_LDAP_URL` | — | LDAP server (`ldap://` or `ldaps://`) | +| `MH_LDAP_BIND_DN` | — | Service account DN | +| `MH_LDAP_BIND_PASS` | — | Service account password | +| `MH_LDAP_BASE_DN` | — | Base DN for user search | +| `MH_LDAP_USER_FILTER` | `(&(objectClass=inetOrgPerson)(uid=%s))` | User search filter | +| `MH_LDAP_GROUP_FILTER` | — | Required group DN for login | +| `MH_LDAP_SKIP_TLS` | `false` | Skip TLS verification | + +LDAP settings can also be configured from the **Admin panel** (no restart needed). ## Architecture @@ -72,6 +72,7 @@ Environment variables: │ (Vue 3) │◀────│ (net/http) │ └────────┘ └─────────────┘ │ │────▶ Filesystem (.md files) │ │────▶ Git (per-user repos) + │ │◀───▶ LDAP (optional) └──────────────┘ │ ┌──────▼───────┐ ┌────────┐ @@ -80,50 +81,55 @@ Environment variables: └──────────────┘ ``` -- **Backend**: Go, stdlib `net/http`, SQLite (pure Go via modernc.org/sqlite) -- **Frontend**: Vue 3, Vite, Milkdown, CodeMirror 6, marked -- **Auth**: JWT + bcrypt + TOTP +- **Backend**: Go 1.23, stdlib `net/http`, SQLite (modernc.org/sqlite), gorilla/websocket +- **Frontend**: Vue 3, Vite, Milkdown, marked, Yjs +- **Auth**: JWT + bcrypt + TOTP + LDAP/SLDAP - **Git**: Shell-based git operations (auto-commit, remotes, push/pull) - **AI**: LiteLLM-compatible OpenAI API calls -- **Build Daemon**: Python (stdlib only), polls for build jobs, runs Pi coding agent +- **Build Daemon**: Python (stdlib only), polls for build jobs ## Project Structure ``` cmd/server/ — Web server entry point -cmd/mdsync/ — CLI sync tool (planned) +cmd/mdsync/ — CLI sync tool internal/api/ — HTTP handlers & routing -internal/auth/ — JWT, bcrypt, TOTP -internal/db/ — SQLite schema & connection +internal/auth/ — JWT, bcrypt, TOTP, LDAP +internal/collab/ — Real-time collaboration (Yjs WebSocket hub) +internal/db/ — SQLite schema & migrations internal/files/ — File CRUD & search internal/git/ — Git operations -internal/crypto/ — AES-256-GCM encryption (for private vault) +internal/crypto/ — AES-256-GCM encryption daemon/ — Build daemon (Python) frontend/ — Vue 3 SPA ``` -## Build Daemon - -The build daemon runs on a separate Linux machine and processes AI build jobs: +## CLI Tool ```bash -export MH_URL=http://your-markdownhub:8080 -export MH_DAEMON_TOKEN=your-token -export MH_WORKSPACE=~/builds -python3 daemon/build_daemon.py +go build -o mdsync ./cmd/mdsync +mdsync login https://md.example.com you@example.com password +mdsync pull . +mdsync push . +mdsync status ``` -It polls MarkdownHub for pending jobs, creates Gitea repos, runs the Pi coding agent, and pushes results. - ## Backup & Restore All data lives in the `data/` volume: - `data/db/markdownhub.db` — SQLite database - `data/files/{user_id}/` — User markdown files (also git repos) -**Backup**: Copy the `data/` directory. -**Restore**: Stop container, replace `data/`, start container. +```bash +# Backup +cp -r ./data ./backup-$(date +%Y%m%d) + +# Restore +docker stop markdownhub +rm -rf ./data && cp -r ./backup-YYYYMMDD ./data +docker start markdownhub +``` ## License -MIT +MIT — Anders Holck 2026