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
- Presence awareness β Know who's currently viewing the document
- 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
- 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
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
- π¬ Chat with Document β Ask questions about your content
- β‘ Streaming responses β See AI responses in real-time
- Role-based access β Owner and Editor roles
- Easy sharing β Invite collaborators via email
- User management β View and remove document access
English, French, Spanish, German, Italian, Portuguese, Chinese, Russian, Hindi, Japanese
Add screenshots or GIFs of your application here
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π£ 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.1.1 | React framework with App Router |
| React | 19.0.0 | UI library |
| TypeScript | 5.6.2 | Type safety |
| Technology | Version | Purpose |
|---|---|---|
| Liveblocks | 3.12.1 | Real-time infrastructure |
| Yjs | 13.6.19 | CRDT for conflict-free sync |
| BlockNote | 0.45.0 | Rich text editor |
| Technology | Version | Purpose |
|---|---|---|
| Vercel AI SDK | 6.0.3 | AI streaming & providers |
| Firebase | 12.7.0 | Database & storage |
| Firebase Admin | 13.0.1 | Server auth & Firestore |
| Technology | Version | Purpose |
|---|---|---|
| Tailwind CSS | 4.0.9 | Utility-first CSS |
| Radix UI | Latest | Accessible primitives |
| Framer Motion | 12.4.7 | Animations |
| Lucide | 0.562.0 | Icons |
| Sonner | 2.0.1 | Toast notifications |
- Node.js 20.9 or later (required by Next.js 16.1.1)
- npm 9.0 or later (or pnpm/yarn)
- A Liveblocks account (real-time)
- A Firebase project (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)
-
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=...# 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-endpoint/ # Liveblocks authentication
β βββ doc/[id]/ # Document pages
β β βββ page.tsx # Document view
β β βββ layout.tsx # Room provider wrapper
β β βββ loading.tsx # Loading state
β β βββ error.tsx # Error boundary
β βββ layout.tsx # Root layout
β βββ page.tsx # Home page
β
βββ components/ # React components
β βββ ui/ # Shadcn UI primitives
β βββ AIDialog.tsx # Shared AI dialog base
β βββ AIModelSelect.tsx # AI model dropdown
β βββ Avatars.tsx # User presence avatars
β βββ ChatToDocument.tsx # AI Q&A feature
β βββ Document.tsx # Main document component
β βββ Editor.tsx # BlockNote editor wrapper
β βββ LiveCursorProvider.tsx # Cursor tracking
β βββ TranslateDocument.tsx # AI translation feature
β βββ ...
β
βββ hooks/ # Custom React hooks
β βββ use-document-title.ts # Document title management
β βββ 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
β βββ ...
β
βββ lib/ # Utilities & server actions
β βββ documentActions.ts # Document CRUD operations
β βββ generateActions.ts # AI generation actions
β βββ firebase-session.ts # Server session + auth helpers (cookie -> user)
β βββ room-ownership.ts # Targeted self-heal for corrupted room ownership
β βββ migrations.ts # Best-effort legacy room migrations
β βββ action-utils.ts # Consistent server-action responses
β βββ document-utils.ts # Document helpers
β βββ ...
β
βββ firebase/ # Firebase configuration
β βββ firebaseConfig.ts # Client SDK setup
β βββ firebaseAdmin.ts # Admin SDK setup
β
βββ constants/ # App constants
β βββ index.ts # AI models, languages, prompts
β
βββ types/ # TypeScript definitions
βββ index.ts # Shared types
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Client ββββββΆβ Liveblocks ββββββΆβ Client β
β (Editor) βββββββ (Yjs) βββββββ (Editor) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Firebase β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β
β βDocuments β β Users β β Rooms (per user) β β
β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User βββΆ Firebase Auth βββΆ ID Token βββΆ /api/auth/session (HttpOnly cookie)
β
βΌ
Liveblocks Auth Endpoint
β
βΌ
Firebase Room Access Check
β
βΌ
Liveblocks Session Token
documents/
βββ {documentId}/
βββ title: string
βββ createdAt: timestamp
βββ updatedAt: timestamp
users/
βββ {uid}/
βββ rooms/
βββ {documentId}/
βββ roomId: string
βββ userId: string
βββ role: "owner" | "editor"
βββ createdAt: timestamp
| 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)
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
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.
Migration warns about missing index (FAILED_PRECONDITION)
On first sign-in, the app runs a best-effort migration (migrateUserRoomsToUid) that may query a collection group index on rooms.userEmail.
If you see:
Skipping collectionGroup userEmail migration (likely missing index): FAILED_PRECONDITION
You can either ignore it (the app still works), or create the index:
- Collection:
rooms(collection group) - Fields:
userEmail(Ascending)
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
Made with β€οΈ by the Spaces team