Implements workspace-scoped data isolation via subdomain routing:
- Schema: add workspaceSlug to Notebook model + migration
- Middleware: extract subdomain → x-workspace-slug header
- API: filter notebooks/notes/search by workspace on subdomains
- AppSwitcher: generate <username>.r*.online links when logged in
- Sessions: SubdomainSession component syncs auth across subdomains
via .rnotes.online domain-wide cookie
- Auth: auto-migrate unscoped notebooks to user's workspace
- New /api/me endpoint for client-side auth + workspace state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves merge conflicts between dev (voice/transcription features) and
main (logseq import/export, memory cards, attachments). Both feature
sets coexist cleanly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Multi-strategy approach to find readable versions of paywalled articles:
1. Wayback Machine (check existing + Save Page Now)
2. Google Web Cache
3. archive.ph (read-only check for existing snapshots)
Adds archiveUrl field to Note model, /api/articles/unlock endpoint,
unlock button on note detail page, and browser extension integration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Evolve rNotes schema and API to support the Memory Card data model:
- Add parentId self-relation for note hierarchy (NoteTree)
- Dual-format body storage (bodyJson + bodyMarkdown) with HTML fallback
- New cardType field (note/link/file/task/person/idea/reference)
- Structured properties (Logseq-compatible key-value JSON)
- Soft-delete via archivedAt (FUN model: Forget, not Delete)
- File + CardAttachment models for structured attachments
- Tag model evolved with spaceId for scoped tags
- Content conversion library (HTML/JSON/Markdown bidirectional)
- Logseq import/export (ZIP with pages/ + assets/)
- NoteEditor emits TipTap JSON as canonical format
- NoteCard shows cardType badges, child count, properties
- Canvas sync enriched with Memory Card fields
- Backfill script for existing notes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add AUDIO to NoteType enum, duration field to Note model
- New VoiceRecorder component (MediaRecorder API, upload, transcribe)
- New /api/voice/transcribe proxy route to voice-command-api container
- Audio MIME types added to upload whitelist
- Audio player + transcript display on note detail page
- AUDIO type button on new note page with recorder UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up EncryptID SDK for user authentication with WebAuthn passkeys.
All write API routes (POST/PUT/DELETE) now require auth, while reads
remain public. First user auto-claims orphaned notebooks/notes.
New files:
- src/lib/auth.ts: getAuthUser, requireAuth, getNotebookRole helpers
- src/lib/authFetch.ts: client-side fetch wrapper with JWT token
- src/components/AuthProvider.tsx: EncryptIDProvider wrapper
- src/components/UserMenu.tsx: sign in/out UI for nav bar
- src/app/auth/signin/page.tsx: passkey login/register page
Protected routes: notebooks CRUD, notes CRUD, canvas create, uploads.
Ownership checks: notebook collaborator roles, note author verification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upload API at /api/uploads with 50MB limit, MIME type validation, and
path traversal protection
- Serve uploaded files at /api/uploads/[filename] with immutable caching
- FileUpload component with drag-and-drop, progress, and preview
- IMAGE notes show uploaded image preview in detail view
- FILE notes show download button in detail view
- Docker volume for persistent upload storage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Prisma contains-based search with raw SQL using ts_vector/ts_query
for ranked results and headline snippets with <mark> highlighting. Falls
back to ILIKE for partial matches. GIN index applied to production DB.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>