Full-featured web editor PWA for noz, built with Next.js and CodeMirror 6. Editor: - CM6-based Markdown editor with iA Writer aesthetic and Typora-style marker hiding - Live preview with KaTeX math, highlight.js syntax highlighting, wikilink rendering - Wikilink autocomplete via server note graph ([[ triggers suggestion list) - Floating selection toolbar, format toolbar, status bar - Split / editor-only / preview-only view modes with resizable panels - Visual frontmatter panel (no raw YAML editing required) Navigation: - Folder tree with topics, sub-topics, drafts section - Create / rename / move / delete notes and folders - Diagram editor (TOML definition → canvas visualization) Search: - ⌘K command palette with scoped search (@topic, @web, @draft) Preview: - Broken wikilink detection with visual indicator and toast notification - Fragment links: [[note#section]] navigates and scrolls to heading - In-page links: [[#section]] scrolls without switching notes - Heading anchors auto-generated from heading text Auth: - Token / Authentik SSO / both — driven by noosphere.toml - sessionStorage only (no localStorage — prevents credential leaks on shared devices) i18n: German + English
9.1 KiB
noz-studio — Projektübersicht für Claude
Kommunikation: Deutsch. Alle Konversationen, Commit-Messages, Kommentare und UI-Labels auf Deutsch.
Was ist noz-studio?
noz-studio ist der Web-Editor für noz — ein vollständiger Markdown-Editor als PWA, optimiert für Desktop und Mobile (Touch). Gedacht für Situationen wo noz-cli nicht verfügbar ist (Arbeit, unterwegs, fremdes Gerät).
noz-studio ist ein Client. Es schreibt keinen eigenen Content-Store — es spricht ausschließlich gegen die noz-API. Die einzige Verbindung zwischen noz und noz-studio sind API-Endpunkte.
noz (Server + API) ←──────────────────────────
↑ ↑ ↑
noz-cli noz (public) noz-studio
(Terminal) (Leser) (Web-Editor)
Stack
- Next.js (App Router) — gleicher Stack wie noz
- CodeMirror 6 — Editor-Engine (MIT-Lizenz) — NUR als Engine, alles außen rum ist custom
- Tailwind CSS v4 — OKLCH-Farben, gleiche Palette wie noz aber eigene Design-Sprache
- PWA —
manifest.json+ Service Worker — installierbar auf iOS/Android/Desktop
Design-Prinzipien
- iA Writer-Feel — fokussiert, clean, Typografie im Vordergrund
- Affine-like — immer offen, kein "speichern"-Stress
- Kein localStorage für Credentials — Token in
sessionStorage(Tab zu → Token weg, kein Datenleak auf Arbeitsrechnern) - noosphere.toml als Single Source of Truth — Studio liest Config vom Server, nie hardcoden
- CM6 ist swappable — EditorEngine-Interface abstrahiert die Implementierung
Auth-System
Konfiguriert in noosphere.toml des noz-Servers:
[studio]
auth = "token" # "token" | "authentik" | "both"
allow_delete = true
allow_push = true
allow_rebuild = false
Studio macht beim Start einen public Request ohne Token:
GET /api/studio/config → { auth: "token" | "authentik" | "both", name: "...", lang: "..." }
Daraufhin zeigt der Login-Screen die passende UI (Token-Formular, Authentik-SSO-Button, oder beides).
Token-Handling:
- Gespeichert in
sessionStorage— nielocalStorage - Tab schließen = Token weg = kein Datenleak auf fremden Geräten
- Gleicher Token wie
[cli]innoosphere.toml
Draft-System (3 Stufen)
[ Draft ] → [ In Review ] → [ Live ]
| Stufe | Speicherort | Sichtbar auf noz? | Wer sieht es? |
|---|---|---|---|
| Draft | content/noosphere/_drafts/notiz.md |
Nein (Index-Builder überspringt _-Ordner) |
Nur Studio |
| In Review | content/noosphere/topic/notiz.md + draft: true im Frontmatter |
Nur via Authentik/Vault | Eingeloggte User |
| Live | content/noosphere/topic/notiz.md (kein draft-Flag) |
Ja, öffentlich | Alle |
Der Draft-Button im Editor-StatusBar toggelt zwischen den Stufen. Studio kümmert sich um:
- Datei verschieben (
_drafts/→ topic-Ordner) - Frontmatter
draft: true/falsesetzen - Index-Rebuild triggern (wenn
allow_rebuild = true)
EditorEngine-Interface (CM6 swappable)
// src/components/editor/engine.ts
interface EditorEngine {
getValue(): string
setValue(content: string): void
onSave(callback: (value: string) => void): void
focus(): void
destroy(): void
}
// src/components/editor/cm6-adapter.ts
class CM6Adapter implements EditorEngine { ... }
// src/components/editor/editor-wrapper.tsx
// Kennt nur EditorEngine, nie direkt CM6
Wenn CM6 irgendwann getauscht wird → nur cm6-adapter.ts anfassen.
Projektstruktur
noz-studio/
src/
app/
page.tsx # → redirect /editor oder /login
login/
page.tsx # Login-Screen (token | authentik | both — je nach config)
editor/
page.tsx # Haupt-Editor: Sidebar + Editor + Preview
components/
editor/
engine.ts # EditorEngine Interface
cm6-adapter.ts # CM6 implementiert EditorEngine
editor-wrapper.tsx # React Component — bindet Adapter ein
toolbar.tsx # Formatting-Toolbar (Bold, Italic, Link, Bild...)
status-bar.tsx # Wortanzahl, Status-Badge, Draft-Button, Sprache
sidebar/
folder-tree.tsx # Topic/Folder Navigation (wie noz Folder-View)
note-list.tsx # Notes im aktuellen Ordner
draft-badge.tsx # Visueller Draft-Indikator
preview/
preview.tsx # Live-Preview (KaTeX, Wikilinks, Bilder, Tabellen)
auth/
token-form.tsx # Token-Login Formular
authentik-button.tsx # Authentik SSO Button
lib/
api.ts # Alle API-Calls zu noz (einzige Stelle die fetch aufruft)
auth.ts # Token lesen/schreiben (sessionStorage)
config.ts # Studio-Config vom Server cachen
hooks/
use-notes.ts # Notes laden, CRUD
use-editor.ts # Editor-State, Auto-Save
use-config.ts # noosphere.toml Config
public/
manifest.json # PWA Manifest
icons/ # App-Icons (512x512, 192x192, maskable)
next.config.ts
Features
Editor — gebaut ✓
- Markdown-Editor (CM6, iA Writer-Feel)
- Live-Preview (rechts, togglebar — raw / split / rendered)
- KaTeX Math (
$...$und$$...$$) - Syntax-Highlighting für Code-Blöcke (highlight.js)
- Formatierungs-Toolbar (Bold/Italic/Strike/H1–H3/Link/Code/Bild/Mathe/Wikilink/…)
- Floating Selection-Toolbar (erscheint bei Textauswahl)
- Einstellungs-Modal (Affine-Stil, vollseitig)
- ⌘K Command Palette (Scoped Search:
@topic,@web,@draft) - Resizable Sidebar (160–360px) + Resizable Preview (200–640px)
- Glassmorphism Navbar (vereint Format-Toolbar + View-Toggle + Suche)
Editor — geplant
- Typora-Style:
**fett**sofort fett (CM6 Decorations) /Slash-Command-Menü (wie Notion/AFFiNE)- Wikilink-Autocomplete (
[[→ Vorschläge) - Bild-Upload (Drag & Drop → Upload →
)
Navigation — gebaut ✓
- Folder-Tree (Topics → Notes, Unterordner-Unterstützung via
subTopics) - Draft-Bereich (eigener
_drafts-Bereich) - Note umbenennen (inline, im Tree)
- Ordner erstellen (root + Unterordner)
- Ordner umbenennen (inline)
- Note verschieben (Kontextmenü → Ordner-Auswahl)
Navigation — geplant
- Meilisearch-Integration (
/api/search) - Note löschen (mit Bestätigungs-Dialog)
Verwaltung — geplant
- Neue Notiz (Frontmatter-Wizard)
- 3-Stufen Draft-Button (Draft → In Review → Live)
- Frontmatter visuell editieren
PWA / Mobile — geplant
- Installierbar (manifest.json)
- Touch-optimiert (Bottom-Navigation auf Mobile)
Verbindung zu noz
noz-studio braucht neue API-Routen in noz (noch nicht gebaut — werden nach dem Studio-Design spezifiziert):
GET /api/studio/config # public — Auth-Methode + Site-Config
GET /api/cli/notes # alle Notes (meta)
GET /api/cli/notes/:slug # Raw Markdown
POST /api/cli/notes # neue Note — { slug, title, topic, status, lang, content }
PUT /api/cli/notes/:slug # Note aktualisieren
DELETE /api/cli/notes/:slug # Note löschen
POST /api/cli/notes/:slug/rename # umbenennen — { newTitle } — Server rewritet Wikilinks
POST /api/cli/notes/:slug/move # Note verschieben — { newTopic } — Server rewritet Wikilinks
GET /api/cli/templates # Templates
POST /api/cli/rebuild # build:index triggern
POST /api/cli/folders # Neuer Ordner — { slug, parent? } — legt _index.md an
PUT /api/cli/folders/:slug # Ordner umbenennen — { newSlug } — Server rewritet ALLE internen Links
DELETE /api/cli/folders/:slug # Ordner löschen (nur wenn leer — sonst 409)
Alle außer /api/studio/config erfordern Authorization: Bearer <token>.
Link-Rewriting beim Verschieben/Umbenennen (Serverseite)
Wenn eine Note verschoben wird (/move) oder ein Ordner umbenannt wird (PUT /folders):
- Datei/Verzeichnis physisch verschieben
- In allen
.md-Dateien des Content-Stores Wikilinks ersetzen:- Note-Move:
[[alter-topic/note-slug]]→[[neuer-topic/note-slug]] - Folder-Rename:
[[alter-ordner/...]]→[[neuer-ordner/...]]
- Note-Move:
- Index-Rebuild triggern (wenn
allow_rebuild = true)
Kurzform: [[slug]] ohne Topic-Prefix bleibt unverändert — nur vollqualifizierte Slugs werden rewritten.
Design-System
Gleiche OKLCH-Palette wie noz (globals.css), aber eigene Layout-Sprache:
- Dark by default (Editor-Feeling)
- Newsreader für Headings (italic), Inter für UI, JetBrains Mono im Editor
- Kein Prose-Layout — Editor ist das Zentrum
Layouts:
- Desktop:
[Sidebar 260px] [Editor flex] [Preview flex] - Mobile: Bottom-Nav + Fullscreen-Editor + Swipe zwischen Editor/Preview