A modern, real-time collaborative document editor with AI superpowers.
Built with Next.js 16, React 19, and Liveblocks.
Features β’ Demo β’ Tech Stack β’ Getting Started β’ Architecture β’ Contributing
- Live cursors β See where others are editing in real-time with colored name tags
- Presence awareness β Know who's currently viewing the document with avatars
- Instant sync β Changes appear immediately for all collaborators
- Conflict-free β Powered by Yjs CRDT for seamless merging
- Block-based editing β Notion-style blocks with BlockNote 0.46
- Slash commands β Quick formatting with
/menu - Markdown support β Write in markdown, see it rendered
- Dark/Light mode β Easy on the eyes, any time of day
- Document icons β Customize documents with emoji icons
Choose from 5 powerful AI models:
| Model | Provider | Best For |
|---|---|---|
| GPT-4o | OpenAI | General tasks, reasoning |
| Claude 3.5 Sonnet | Anthropic | Long documents, analysis |
| Gemini 1.5 Pro | Multi-modal, large context | |
| Mistral Large | Mistral | European data compliance |
| LLaMA 3.1 405B | Fireworks | Open-source, self-hostable |
AI Features:
- π Document Translation β Translate to 10 languages with streaming responses
- π¬ Chat with Document β Ask questions about your content
- β‘ Streaming responses β See AI responses in real-time
- π Smart truncation β Handles large documents intelligently (up to 400K chars)
- Role-based access β Owner and Editor roles with different permissions
- Easy sharing β Invite collaborators via email with validation
- User management β View and remove document access
- Ownership self-healing β Automatic recovery of corrupted ownership data
- Firebase Auth β Secure Google Sign-In authentication
- httpOnly cookies β Session tokens are not accessible via JavaScript
- Server-side validation β All sensitive operations verified on the server
- Firestore security rules β Granular access control at the database level
English, French, Spanish, German, Italian, Portuguese, Chinese, Russian, Hindi, Japanese
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π£ Spaces [Avatar] [Avatar] β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β π My Documents β π Document Title [Update] β
β βββ π Project Notes β βββββββββββββββββββββββββββββ β
β βββ π Meeting Summary β β
β βββ π‘ Ideas β Start typing here... β
β β β
β π€ Shared with me β π Cursor (You) β
β βββ πΊοΈ Team Roadmap β π Cursor (Jane) β
β β β
β [+ New Document] β [Translate] [Chat] [π] β
β β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 16.0.3 | React framework with App Router |
| React | 19.0.0 | UI library |
| TypeScript | 5.6.2 | Type safety |
| Technology | Version | Purpose |
|---|---|---|
| Liveblocks | 3.7.1 | Real-time infrastructure |
| Yjs | 13.6.19 | CRDT for conflict-free sync |
| BlockNote | 0.46.0 | Rich text editor |
| Technology | Version | Purpose |
|---|---|---|
| Vercel AI SDK | 6.0.3 | AI streaming & providers |
| Firebase | 12.7.0 | Auth & Firestore DB |
| Firebase Admin | 13.0.1 | Server auth & Firestore |
| Package | Version | Provider |
|---|---|---|
| @ai-sdk/openai | 3.0.1 | OpenAI |
| @ai-sdk/anthropic | 3.0.1 | Anthropic |
| @ai-sdk/google | 3.0.1 | |
| @ai-sdk/mistral | 3.0.1 | Mistral |
| Technology | Version | Purpose |
|---|---|---|
| Tailwind CSS | 4.0.9 | Utility-first CSS |
| Radix UI | Latest | Accessible primitives |
| Mantine | 8.3.8 | UI components |
| Framer Motion | 12.4.7 | Animations |
| Lucide | 0.563.0 | Icons |
| Sonner | 2.0.1 | Toast notifications |
| next-themes | 0.4.4 | Theme management |
| vaul | 1.0.0 | Drawer component |
- Node.js 20.9 or later (required by Next.js 16)
- npm 9.0 or later (or pnpm/yarn)
- A Liveblocks account (real-time)
- A Firebase project (auth & database)
- At least one AI provider API key
- Clone the repository
git clone https://github.com/yourusername/spacesapp.git
cd spacesapp- Install dependencies
npm install- Set up environment variables
cp .env.example .env.local-
Configure your environment (see Environment Variables)
-
Deploy Firestore security rules
Copy firestore.rules to Firebase Console β Firestore β Rules, or use Firebase CLI:
firebase deploy --only firestore:rules- Run the development server
npm run devCreate a .env.local file with the following variables:
# Liveblocks - https://liveblocks.io/docs/get-started
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY=pk_...
LIVEBLOCKS_PRIVATE_KEY=sk_...# Client-side (from Firebase Console > Project Settings)
NEXT_PUBLIC_FIREBASE_APIKEY=...
NEXT_PUBLIC_FIREBASE_AUTHDOMAIN=...
NEXT_PUBLIC_FIREBASE_PROJECTID=...
NEXT_PUBLIC_FIREBASE_STORAGEBUCKET=...
NEXT_PUBLIC_FIREBASE_MESSAGINGSENDERID=...
NEXT_PUBLIC_FIREBASE_APPID=...
NEXT_PUBLIC_FIREBASE_MEASUREMENTID=... # Optional
# Server-side (from Firebase Console > Service Accounts > Generate Key)
FIREBASE_TYPE=service_account
FIREBASE_PROJECT_ID=...
FIREBASE_PRIVATE_KEY_ID=...
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=...
FIREBASE_CLIENT_ID=...
FIREBASE_AUTH_URI=https://accounts.google.com/o/oauth2/auth
FIREBASE_TOKEN_URI=https://oauth2.googleapis.com/token
FIREBASE_AUTH_PROVIDER_X509_CERT_URL=https://www.googleapis.com/oauth2/v1/certs
FIREBASE_CLIENT_CERTS_URL=...
FIREBASE_UNIVERSE_DOMAIN=googleapis.com# OpenAI - https://platform.openai.com/api-keys
OPENAI_API_KEY=sk-...
# Anthropic - https://console.anthropic.com/
ANTHROPIC_API_KEY=sk-ant-...
# Google AI - https://makersuite.google.com/app/apikey
GOOGLE_GENERATIVE_AI_API_KEY=...
# Mistral - https://console.mistral.ai/
MISTRAL_API_KEY=...
# Fireworks (for LLaMA) - https://fireworks.ai/
FIREWORKS_API_KEY=...# Logs room ownership self-heal decisions on the server (dev only)
ROOM_OWNERSHIP_DEBUG=1src/
βββ app/ # Next.js App Router
β βββ api/ # API routes
β β βββ auth/session/ # Session cookie management (POST/DELETE)
β β βββ auth-endpoint/ # Liveblocks authentication
β β βββ firebase-diagnostics/ # Firebase config debugging
β βββ doc/[id]/ # Document pages
β β βββ page.tsx # Document view
β β βββ layout.tsx # Room provider + auth wrapper
β β βββ loading.tsx # Loading state
β β βββ error.tsx # Error boundary
β βββ layout.tsx # Root layout
β βββ page.tsx # Home page
β
βββ components/ # React components
β βββ ui/ # Shadcn UI primitives
β β βββ avatar.tsx # User avatar with fallback
β β βββ button.tsx # Button variants
β β βββ dialog.tsx # Modal dialogs
β β βββ drawer.tsx # Mobile drawer
β β βββ input.tsx # Form inputs
β β βββ popover.tsx # Popovers
β β βββ select.tsx # Dropdowns
β β βββ sheet.tsx # Sheet/drawer
β β βββ sonner.tsx # Toast notifications
β β βββ spinner.tsx # Loading spinner
β β βββ tooltip.tsx # Tooltips
β βββ AIDialog.tsx # Shared AI dialog base
β βββ AIModelSelect.tsx # AI model dropdown
β βββ Avatars.tsx # User presence avatars
β βββ Breadcrumbs.tsx # Navigation breadcrumbs
β βββ ChatToDocument.tsx # AI Q&A feature
β βββ ClientOnly.tsx # SSR-safe wrapper
β βββ DeleteDocument.tsx # Document deletion dialog
β βββ Document.tsx # Main document component
β βββ Editor.tsx # BlockNote editor wrapper
β βββ EmojiPicker.tsx # Document icon picker
β βββ ErrorBoundary.tsx # Error boundary components
β βββ FirebaseAuthBridge.tsx # Auth state β session sync
β βββ FollowPointer.tsx # Live cursor display
β βββ Header.tsx # Top navigation bar
β βββ InviteUser.tsx # User invitation dialog
β βββ LiveBlocksProvider.tsx # Liveblocks context provider
β βββ LiveCursorProvider.tsx # Cursor tracking provider
β βββ ManageUsers.tsx # User management dialog
β βββ NewDocumentButton.tsx # Create document button
β βββ PageIcon.tsx # Document icon display
β βββ RoomProvider.tsx # Document room wrapper
β βββ Sidebar.tsx # Document navigation
β βββ SidebarOption.tsx # Sidebar document item
β βββ ThemeProvider.tsx # Dark mode provider
β βββ TranslateDocument.tsx # AI translation feature
β
βββ hooks/ # Custom React hooks
β βββ use-document-icon.ts # Document icon with optimistic updates
β βββ use-document-title.ts # Document title management
β βββ use-is-mounted.ts # Component mount tracking
β βββ use-latest.ts # Latest value ref
β βββ use-owner.ts # Ownership check
β βββ use-room-id.ts # URL room ID extraction
β βββ use-room-users.ts # Room users query
β βββ use-streaming-request.ts # AI streaming handler
β βββ use-user-documents.ts # User's documents query
β βββ index.ts # Central exports
β
βββ lib/ # Utilities & server actions
β βββ action-utils.ts # Server action response helpers
β βββ document-utils.ts # Yjs document helpers
β βββ documentActions.ts # Document CRUD (server actions)
β βββ env.ts # Environment variable validation
β βββ firebase-session.ts # Session cookie utilities
β βββ firestore-helpers.ts # Firestore path helpers
β βββ generateActions.ts # AI operations (server actions)
β βββ liveblocks.ts # Liveblocks server client
β βββ room-ownership.ts # Ownership self-healing
β βββ stringToColor.ts # Color generation for users
β βββ utils.ts # General utilities
β
βββ firebase/ # Firebase configuration
β βββ firebaseConfig.ts # Client SDK setup
β βββ firebaseAdmin.ts # Admin SDK setup
β
βββ constants/ # App constants
β βββ index.ts # AI models, languages, prompts, limits
β
βββ types/ # TypeScript definitions
βββ index.ts # Shared types
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Client ββββββΆβ Liveblocks ββββββΆβ Client β
β (Editor) βββββββ (Yjs) βββββββ (Editor) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Firebase β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β
β βDocuments β β Users β β Rooms (per user) β β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User βββΆ Firebase Auth (Google) βββΆ ID Token
β
βΌ
POST /api/auth/session
β
βΌ
httpOnly Session Cookie (5 days)
β
βΌ
POST /api/auth-endpoint (per room)
β
βΌ
Room Access Check (Firestore)
β
βΌ
Liveblocks Session Token
documents/
βββ {documentId}/
βββ title: string
βββ icon: string | null # Emoji icon
βββ createdAt: timestamp
βββ updatedAt: timestamp
users/
βββ {uid}/
βββ rooms/
βββ {documentId}/
βββ roomId: string
βββ userId: string
βββ role: "owner" | "editor"
βββ userEmail?: string # For lookup
βββ createdAt: timestamp
All server actions use a standardized response format:
type ActionResponse<T> =
| { success: true; data: T }
| { success: false; error: { code: ActionErrorCode; message: string } };| Action | Purpose | Auth Required |
|---|---|---|
createNewDocument |
Create document + owner role | β |
deleteDocument |
Delete document + all room entries | β (owner) |
inviteUserToDocument |
Add editor by email | β (owner) |
removeUserFromDocument |
Remove user access | β (owner) |
updateDocumentIcon |
Update document emoji icon | β |
generateSummary |
AI translation/summary | β |
generateAnswer |
AI Q&A on document | β |
| Command | Description |
|---|---|
npm run dev |
Start development server with hot reload |
npm run build |
Build for production |
npm run start |
Start production server |
npm run lint |
Run ESLint for code quality |
We welcome contributions! Here's how you can help:
- Fork the repository
- Clone your fork locally
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Test thoroughly
- Commit with a descriptive message:
git commit -m 'Add amazing feature' - Push to your branch:
git push origin feature/amazing-feature - Open a Pull Request
- We use TypeScript strict mode
- Follow the existing code patterns
- Use functional components with hooks
- Prefer Server Components where possible
- Write descriptive variable names (e.g.,
isLoading,hasError) - Use CSS variables for theming (
bg-brand,text-muted-foreground) - Constants go in
src/constants/index.tsβ no magic numbers inline
Follow conventional commits:
feat: add document export feature
fix: resolve cursor sync delay
docs: update README with new env vars
refactor: simplify auth flow
Hydration mismatch errors
This can happen with components using browser APIs. Wrap them in ClientOnly:
import ClientOnly from "@/components/ClientOnly";
<ClientOnly fallback={<Skeleton />}>
<BrowserOnlyComponent />
</ClientOnly>;Liveblocks authentication fails
- Check that
LIVEBLOCKS_PRIVATE_KEYis set correctly - Verify you are signed in (Header should show your avatar + "Sign Out")
- Check the auth endpoint logs at
/api/auth-endpoint - Ensure the user has a room entry in Firestore (
users/{uid}/rooms/{docId})
Firebase permission denied
Deploy the security rules from the project root:
- Copy
firestore.rulesto Firebase Console β Firestore β Rules - Copy
storage.rulesto Firebase Console β Storage β Rules
Or use Firebase CLI:
firebase deploy --only firestore:rules,storageSee firestore.rules and storage.rules for the full rule definitions.
AI features not working
- Ensure at least one AI provider API key is set in
.env.local - Check the browser console for errors
- Verify the selected model has a corresponding API key configured
- For large documents, AI processing may take longer β streaming will show partial results
Debug ownership issues
Add ?debugOwner=1 to any document URL to enable detailed ownership logging in the browser console.
Server-side logging can be enabled with ROOM_OWNERSHIP_DEBUG=1 in .env.local.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0) β see LICENSE.md for the full license text.
Note: AGPL includes network-use/source-availability requirements when you run modified versions as a service. If you're unsure how this impacts your use case, please review the license terms.
- BlockNote β Amazing open-source editor
- Liveblocks β Real-time infrastructure
- Vercel AI SDK β Unified AI interface
- Shadcn UI β Beautiful UI components
- Firebase β Authentication and database
Made with β€οΈ by the Spaces team