Commit Graph

19 Commits

Author SHA1 Message Date
Jeff Emmett e7e921665d Add Y.js real-time collaboration to rNotes editor
- Add yjs, y-websocket, @tiptap/extension-collaboration,
  @tiptap/extension-collaboration-caret dependencies
- Create collab-provider.ts: WebsocketProvider wrapper
- Create CollabStatus.tsx: connection/sync state indicator
- NoteEditor.tsx: add collaborative mode with Y.js document,
  awareness cursors, and auto-disable built-in history
- docker-compose.yml: add y-websocket sidecar (rnotes-yws)
  at collab-ws.rnotes.online, add NEXT_PUBLIC_COLLAB_WS_URL

Enable by passing collaborative={true} noteId="..." user={...}
to NoteEditor. Non-collaborative mode unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 19:22:18 -07:00
Jeff Emmett b55362032d Switch IPFS from standalone kubo to rSpace collab-server endpoints
- Update IPFS_API_URL to ipfs-api.rspace.online (was kubo:5001)
- Update IPFS_GATEWAY_URL to ipfs.rspace.online (was ipfs.jeffemmett.com)
- Enhance image button: file upload via /api/uploads with IPFS encryption
  instead of manual URL prompt, with fallback on failure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 18:53:27 -07:00
Jeff Emmett 022a99f753 fix: use kubo container name for IPFS API
Renamed from 'ipfs' to 'kubo' to avoid Docker DNS collision with
the collab-server's IPFS service on the same network.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 17:57:56 -07:00
Jeff Emmett f475ed0462 feat: integrate encrypted IPFS file storage
- Add src/lib/ipfs.ts: AES-256-GCM encryption + kubo upload/download
- Add /api/ipfs/[cid] proxy route: decrypt + serve with LRU cache
- Upload route: encrypt + pin to IPFS alongside local disk (fallback)
- Prisma: add ipfsCid/ipfsEncKey fields to File model
- FileUpload: prefer IPFS proxy URL when available
- Feature-flagged via IPFS_ENABLED env var

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 17:21:53 -07:00
Jeff Emmett 55ceb55aa1 refactor: migrate EncryptID URLs from encryptid.jeffemmett.com to auth.ridentity.online
Part of the ridentity.online branding migration. The EncryptID auth
server is now accessible at auth.ridentity.online (with the legacy
encryptid.jeffemmett.com kept as a backward-compatible alias).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 22:20:09 -08:00
Jeff Emmett c27290ee80 feat: add username-based personal subdomains (<username>.rnotes.online)
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>
2026-02-24 20:46:24 -08:00
Jeff Emmett 6fc4bd7c17 Merge dev into main: add rVoice PWA + browser extension voice recorder
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>
2026-02-24 17:47:31 -08:00
Jeff Emmett 17f2d49f12 feat: add article unlock feature for paywalled content
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>
2026-02-24 15:32:37 -08:00
Jeff Emmett c4141802cc Host Open Notebook at /opennotebook with wildcard subdomain support
Add /opennotebook route embedding Open Notebook via iframe with space-aware
nav breadcrumb. Middleware detects subdomain (e.g. cca.rnotes.online) and sets
rnotes-space cookie. /ai redirects to /opennotebook. Traefik wildcard router
at priority 100 catches *.rnotes.online subdomains.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 09:45:31 +00:00
Jeff Emmett 2c3e28b8d1 fix: use Array.from for Map iteration (ES5 target compat)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:37:45 +00:00
Jeff Emmett 26602e4197 fix: relax ExportNote.children type for Prisma select compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:37:01 +00:00
Jeff Emmett 7b1d120379 feat: implement Memory Card spec — hierarchy, dual-format body, Logseq interop
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>
2026-02-22 22:33:48 +00:00
Jeff Emmett fbbe8d38d1 Replace Whisper-tiny offline fallback with Parakeet.js (NVIDIA 0.6B v2)
Swap @xenova/transformers (whisper-tiny, ~45MB) for parakeet.js
(Parakeet TDT 0.6B v2, ~634MB) loaded from CDN at runtime. Much higher
transcription accuracy at the cost of larger initial model download.
Uses indirect dynamic import to avoid Next.js/webpack bundling issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 23:48:48 +01:00
Jeff Emmett 5e21e0fa5c feat: add SpaceRole bridge for cross-module membership sync
Maps notebook collaborator roles (OWNER/EDITOR/VIEWER) to SpaceRoles
(ADMIN/PARTICIPANT/VIEWER). Falls back to EncryptID server for
cross-space membership when notebook is linked via canvasSlug.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:32:17 -07:00
Jeff Emmett 441403fd14 feat: add offline Whisper transcription fallback via Transformers.js
When both WebSocket streaming and server batch API are unavailable,
falls back to in-browser Whisper (Xenova/whisper-tiny, ~45MB, cached).
Shows download progress bar and transcription status during processing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 13:38:15 -07:00
Jeff Emmett 30f3383d1b feat: rewrite demo page with live rSpace data via useDemoSync
Replace static mock data with real-time WebSocket connection to the
shared demo community. Notes are expandable, packing items toggleable,
all changes sync across the r* ecosystem in real-time.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 09:39:07 -07:00
Jeff Emmett d64d8a0d57 feat: add internal API key for rSpace service-to-service auth
pushShapesToCanvas now sends X-Internal-Key header from
RSPACE_INTERNAL_KEY env var for authenticated canvas writes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:02:20 -07:00
Jeff Emmett 2351339241 feat: integrate EncryptID SDK for passkey authentication
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>
2026-02-13 14:20:00 -07:00
Jeff Emmett 118710999b Add full application: schema, API routes, components, pages
- Prisma schema: User, Notebook, Note (6 types), Tag, SharedAccess
- API: CRUD for notebooks/notes, full-text search, canvas sync
- Components: CanvasEmbed, NoteEditor, NoteCard, NotebookCard, SearchBar, TagBadge
- Pages: landing, notebooks list/new/detail/canvas, notes new/detail
- Canvas integration: bidirectional sync with rSpace (folk-notebook, folk-note shapes)
- Amber/orange theme consistent across all pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:00:44 -07:00