docs: Initial Documentation

This commit is contained in:
2026-08-12 19:08:30 +01:00
parent fe69fdff6e
commit 0bfb1039a0
4 changed files with 149 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
# CLAUDE.md
Context file for Claude Code. Read this before making changes. See `docs/ARCHITECTURE.md` for deep technical rationale.
## Project
Native Apple ecosystem client for a self-hosted [Outline](https://github.com/outline/outline) instance (wiki/knowledge base). Targets **iOS, iPadOS, macOS**, single SwiftUI multiplatform codebase. Goal is **full editing parity** with Outline's web app — not a read-only viewer.
Working name: `OutlineClient` (rename freely — placeholder only, not a branding decision).
## License context (do not re-litigate)
Outline server is BSL 1.1 licensed. This restricts *hosting/reselling Outline itself as a service*. It does **not** restrict building an API client. This app only ever talks to Outline's public REST/WebSocket API — it never vendors, forks, or redistributes Outline's server source. No license concerns for this codebase.
## Architecture summary
- **REST layer** — Outline's RPC-style API (`/api/*`), Bearer token auth (`Authorization: Bearer <token>`). Handles collections, documents (non-realtime CRUD), search, users.
- **Realtime collab layer** — Outline runs a **Hocuspocus** server (Yjs CRDT over WebSocket) at `wss://<host>/collaboration/document.<id>`. This is the actual editing transport when a document is open — not the REST API. Full parity requires speaking this protocol, including the Yjs awareness protocol for remote cursors/presence.
- **CRDT engine** — [YSwift](https://github.com/y-crdt/yswift) (Swift bindings over `yrs`, the Rust Yjs port, via UniFFI). This is the only realistic native path to binary-compatible Yjs sync. It is pre-1.0 / WIP — expect to patch or contribute upstream, don't assume full feature coverage going in.
- **Editor UI** — native TextKit 2 (`NSTextLayoutManager` / `AttributedString`) rendering mapped from Outline's ProseMirror document schema (headings, lists, checklists, tables, code blocks, embeds, comments). This is the largest single scope item in the project — treat it as its own subsystem, not a UI detail.
## Phased build order
1. **Phase 1 — Read/browse + REST-only editing.** Auth, collections tree, document list, search, markdown-rendered read view, basic edit-and-PUT (last-write-wins, no live collab). Ship this before touching Yjs at all.
2. **Phase 2 — Realtime collaboration.** Integrate YSwift + Hocuspocus WebSocket, map Yjs XML fragment ↔ native editor state, add awareness/presence.
3. **Phase 3 — Polish.** Offline cache, conflict UI, embeds/attachments, tables, comments, macOS-specific affordances (menu bar, multiple windows).
Do not start Phase 2 work until Phase 1 is stable and shipped to the device. The CRDT/editor layer is high-risk; de-risk everything else first.
## Conventions
- Swift, SwiftUI-first. No UIKit/AppKit escape hatches unless SwiftUI genuinely can't do it (flag these explicitly in PR/commit messages).
- Networking: `URLSession` + `async/await`, no third-party HTTP client.
- API tokens stored in Keychain only — never UserDefaults, never logged.
- Prefer protocol-oriented boundaries between the REST layer, the CRDT/sync layer, and the editor UI layer so any one of them (especially YSwift) can be swapped without touching the others.
- Target iOS 17+ / macOS 14+ minimum (needed for mature `AttributedString`/TextKit 2 APIs).
## Do not
- Do not attempt to reimplement Yjs's CRDT algorithm from scratch — use YSwift/yrs. This has been tried by others and is a multi-year effort (see Yrs project history).
- Do not fall back to polling the REST API for "realtime" — it will visibly diverge from true collaborative editing and defeats the point of this project.
- Do not vendor or copy Outline's server source into this repo.
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2026 Puranjay Savar Mattas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+47
View File
@@ -0,0 +1,47 @@
# Outpost
A native Apple ecosystem client for [Outline](https://github.com/outline/outline) — built for iOS, iPadOS, and macOS from a single SwiftUI codebase, aiming for full editing parity with Outline's web app, including realtime collaborative editing.
## Why
Outline's web app is great, but there's no native Apple client with full editing parity. This project connects to a self-hosted Outline instance over its REST API and realtime collaboration socket to provide a proper native experience across the Apple ecosystem.
## Status
Early development. See `CLAUDE.md` for the current architecture and phased build plan.
- [ ] Phase 1 — Auth, browse, search, REST-only editing
- [ ] Phase 2 — Realtime collaborative editing (Yjs/Hocuspocus)
- [ ] Phase 3 — Offline cache, tables, embeds, comments, macOS polish
## Requirements
- Xcode 16+
- iOS 17+ / iPadOS 17+ / macOS 14+
- A self-hosted (or hosted) Outline instance with API access
> They will be updated. These are old requirements.
## Setup
1. Clone the repo and open the `.xcodeproj` in Xcode.
2. Generate a scoped API key on your Outline instance (Settings → API Keys).
3. On first launch, enter your instance URL and API key — these are stored in Keychain, never in app config or source.
## Architecture
See [`CLAUDE.md`](./CLAUDE.md) and [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md) for the full technical breakdown: REST layer, Yjs/Hocuspocus realtime sync via [YSwift](https://github.com/y-crdt/yswift), and the ProseMirror-schema-to-native-editor mapping.
## Disclaimer
This project is being built to solve a personal problem — I wanted a genuinely good native knowledge-base client for my own self-hosted Outline instance and none of the existing options fit. It's a personal-use tool first, not a polished product with support guarantees.
Parts of this codebase are AI-assisted (built with the help of AI coding tools). Treat that however you like — review, use, fork, or ignore the code accordingly. No warranty of quality, security, or fitness for any particular use is implied beyond what's stated in the license below.
## License
This project is a client only — it does not include, vendor, or redistribute any of Outline's (BSL 1.1 licensed) server source. See [`LICENSE`](./LICENSE) for this repository's own license.
## Not affiliated with Outline
This is an independent, unofficial client. Not affiliated with or endorsed by General Outline, Inc.
+38
View File
@@ -0,0 +1,38 @@
# Architecture Notes
Deeper technical reference backing `CLAUDE.md`. Update this as decisions are made — treat it as a living design doc, not a one-time spec.
## 1. Outline API surface
- **Base**: `https://<your-instance>/api/*`, RPC-style (POST for nearly everything, not strict REST verbs).
- **Auth**: `Authorization: Bearer <API_KEY>` header. Keys are created per-user under Settings → API Keys on the Outline instance. Store in Keychain, scope a dedicated key to this app rather than reusing a personal one.
- **Core endpoints to wrap first**: `documents.info`, `documents.list`, `documents.search`, `documents.create`, `documents.update`, `collections.list`, `collections.info`, `users.info`.
- Full reference: your instance's `/developers` page (same docs as getoutline.com/developers, versioned per Outline release — check against your self-hosted version, not just the public docs).
## 2. Realtime collaboration transport
- Endpoint: `wss://<your-instance>/collaboration/document.<document-id>`.
- Protocol: Hocuspocus (a Yjs-CRDT-over-WebSocket server implementation). This is **not** the same socket as any notification/presence channel — it's the actual document edit transport.
- Payload: binary Yjs update messages (Yjs update format v1/v2) plus the Yjs awareness protocol for cursor/selection presence.
- Your reverse proxy (Caddy, in your homelab) must forward `Upgrade`/`Connection` headers correctly or collaboration silently falls back to "no live sync" while REST edits still work — worth a smoke test against your own Caddy config early.
## 3. CRDT engine — YSwift
- Repo: `y-crdt/yswift`. Swift bindings over `yrs` (Rust) via UniFFI, distributed with a prebuilt XCFramework.
- Status as of mid-2026: WIP, pre-1.0, small but active contributor base. Not all Yrs/Yjs features are exposed yet.
- Integration point: YSwift gives you a local `Y.Doc` you mutate; a Hocuspocus-compatible WebSocket provider (you'll likely need to write this provider yourself in Swift — no off-the-shelf Swift Hocuspocus client exists yet) syncs that doc's binary updates with the server.
- Fallback if YSwift blocks progress: vendor the C FFI (`yffi`) directly and write a thinner Swift wrapper for just the operations you need (XML fragment read/write, update encode/decode, state vector diffing).
## 4. Document schema mapping
Outline's editor is ProseMirror-based; the Yjs doc stores document structure as a `Y.XmlFragment` mirroring the ProseMirror schema (paragraphs, headings, bullet/ordered/checklist lists, tables, code blocks, blockquotes, embeds, comments-as-marks). Native editor work breaks into:
- **Read path**: Y.XmlFragment → your own document model → `AttributedString`/TextKit 2 layout.
- **Write path**: local edit → diff against your document model → Yjs transaction on the XmlFragment → binary update sent over the Hocuspocus socket.
- Build the node-type mapping table (ProseMirror node/mark name → native representation) as an explicit, tested module — this is the piece most likely to silently drift from Outline's actual schema as Outline ships updates.
## 5. Known risk areas (revisit as the project progresses)
- YSwift feature gaps vs. full Yjs (undo/redo manager, relative positions) — check current state before Phase 2 starts, this library moves fast.
- Table and embed support are the least standardized part of ProseMirror schemas generally — budget them last.
- Outline server version drift: self-hosted instance upgrades could change API shapes or the collaboration payload; pin against your actual running version, not assumptions from docs.