Skip to content

Repository files navigation

Docs

A collaborative document editor with real-time editing, comments, and organization support. Create documents from templates, edit with a rich WYSIWYG editor, and collaborate with presence and threaded comments.

Live deployment: https://docs-seven-peach.vercel.app


Table of Contents


Technologies

Layer Technology Role
Framework Next.js 15 (App Router) SSR, RSC, file-based routing, API routes
Backend Convex Document persistence, pagination, full-text search, server-side auth
Auth Clerk Sign-in, user/org identity, Convex token integration
Real-time Liveblocks Collaborative editing, presence, comments, room-based sync
Editor TipTap + Liveblocks React TipTap Rich text (headings, lists, tables, images, links), CRDT-based collaboration
State Zustand Global editor instance for toolbar/menus; nuqs for URL search params
UI Radix UI + Tailwind CSS Accessible primitives and utility-first styling
Feedback Sonner Toasts for success and error messages

Why these choices

  • Next.js 15: Server components for document preloading and auth checks; single codebase for app and API.
  • Convex: Type-safe queries/mutations, real-time subscriptions, and search indexes without managing a separate database or WebSocket layer.
  • Clerk: Handles auth flows and org membership; integrates with Convex and Liveblocks via server-side token/session checks.
  • Liveblocks: Off-the-shelf real-time collaboration (presence, comments, document sync) with a TipTap extension, reducing custom CRDT/OT work.
  • TipTap: Extensible ProseMirror-based editor with a large extension ecosystem (tables, tasks, images, etc.) and first-class Liveblocks support.

Architecture

High-level flow

  1. Entry: Middleware runs Clerk on all non-static routes. Root layout wraps the app in NuqsAdapter, ConvexClientProvider (Clerk + Convex), and toaster.
  2. Home (/): Client fetches paginated documents from Convex (with optional search). User picks a template or opens an existing document; creating a doc runs a Convex mutation and redirects to /documents/[documentId].
  3. Document (/documents/[documentId]): Server gets Clerk Convex token, preloads the document with Convex preloadQuery, then renders the client Document component. Only authenticated users with a valid token reach this page.
  4. Document session: Document is wrapped in a Room (Liveblocks). Room auth is handled by POST /api/liveblocks-auth: it validates the user with Clerk, loads the document from Convex, enforces owner or organization membership, then returns a Liveblocks session scoped to that room.
  5. Editor: TipTap is wired with useLiveblocksExtension (and optional offline support). Toolbar and menus read/write the editor via a Zustand store. Comments and presence use Liveblocks React UI (e.g. Threads, Avatars). Document metadata (title, rename, delete) is persisted in Convex via mutations.

Data and access

  • Convex: documents table (title, initialContent, ownerId, organizationId). Indexes by owner and organization; search index on title. Mutations: create, updateById, removeById. Queries: getById, getByIds, GetDocument (paginated, optionally filtered by search).
  • Liveblocks: One room per document (room id = document id). Storage holds editor state and layout (e.g. margins). Access is granted only to document owner or members of the document’s organization (resolved in the auth API using Convex + Clerk).

Auth chain

  • Clerk → session and org membership.
  • Convex → JWT from Clerk (getToken({ template: "convex" })), used for Convex RPC and preload.
  • Liveblocks → Custom auth endpoint that checks Clerk session, fetches document from Convex, and allows access for owner or org members, then returns a Liveblocks-authorized body.

Running Locally

Prerequisites

Steps

  1. Clone and install:

    git clone <repository-url>
    cd Docs
    npm install
  2. Environment variables (e.g. .env.local):

    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY – Clerk publishable key
    • CLERK_SECRET_KEY – Clerk secret (server)
    • NEXT_PUBLIC_CONVEX_URL – Convex deployment URL (e.g. from npx convex dashboard)
    • LIVEBLOCKS_SECRET_KEY – Liveblocks secret (used in /api/liveblocks-auth)

    Configure Clerk to issue Convex JWTs (e.g. Convex JWT template in Clerk dashboard) and use the same Convex deployment URL in the app.

  3. Convex dev (separate terminal):

    npx convex dev

    Pushes schema and functions; keep it running while developing.

  4. Next.js dev:

    npm run dev

    Open http://localhost:3000. Sign in with Clerk; create a document from the home page or a template, then open it to use the editor and collaboration.

  5. Production build:

    npm run build
    npm run start

Project Structure

src/
  app/
    (home)/                    # Home route group
      page.tsx                 # Dashboard: templates + document list
      navbar.tsx               # Logo, search, org switcher, user
      search-input.tsx         # Search tied to URL (nuqs)
      templates-gallery.tsx    # Template carousel, create doc via Convex
      document-table..tsx      # Paginated table, load more
      document-row.tsx         # Row + menu (open, rename, delete)
      document-menu.tsx
    documents/[documentId]/
      page.tsx                 # RSC: auth + preload, render Document
      document.tsx             # Layout: Room, Navbar, Toolbar, Editor
      room.tsx                 # Liveblocks provider, auth endpoint, resolveUsers
      editor.tsx               # TipTap + Liveblocks extension, ruler
      toolbar.tsx              # Formatting, font, color, links, images, etc.
      navbar.tsx               # Doc title, File/Edit/Insert/Format, avatars
      threads.tsx              # Liveblocks anchored/floating threads
      avatars.tsx              # Presence avatars
      inbox.tsx                # Comments inbox
      document-input.tsx       # Editable title, rename mutation
      ruler.tsx                # Margin ruler using Liveblocks storage
      actions.ts               # Server actions: getUsers, getDocuments (Convex)
    api/
      liveblocks-auth/
        route.ts               # POST: Clerk + Convex doc check, Liveblocks authorize
    layout.tsx                 # Root layout, fonts, Convex + Clerk + nuqs
    globals.css
    error.tsx
  components/
    convex-client-provider.tsx # ClerkProvider, ConvexProviderWithClerk, auth gates
    fullscreen-loader.tsx
    remove-dialog.tsx
    rename-dialog.tsx
    ui/                        # Radix-based UI primitives
  hooks/
    use-debounce.ts
    use-mobile.tsx
    use-search-param.ts        # nuqs wrapper for search
    use-toast.ts
  store/
    use-editor-store.ts        # Zustand: current TipTap editor instance
  lib/
    utils.ts
  constants/
    templates.ts               # Template definitions (title, initialContent, image)
  extensions/
    font-size.ts               # TipTap custom extension
    line-height.ts
  middleware.ts                # Clerk middleware matcher
convex/
  schema.ts                    # documents table, indexes, search index
  documents.ts                 # Queries and mutations for documents
  auth.config.ts               # Convex auth provider (Clerk)

Deploy

The app is deployed on Vercel. Set the same environment variables in the Vercel project, ensure Convex is deployed and the Convex URL points to the production deployment, and connect the repo for automatic builds and previews.

Releases

Packages

Contributors

Languages