Skip to content

brown2020/spacesappai

Repository files navigation

Spaces Logo

Spaces

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

Next.js 16 React 19 TypeScript Tailwind CSS AGPL-3.0 License


✨ Features

πŸ”„ Real-time Collaboration

  • 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

πŸ“ Rich Text Editor

  • 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

πŸ€– AI Integration

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 Google 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

πŸ‘₯ User Management

  • Role-based access β€” Owner and Editor roles
  • Easy sharing β€” Invite collaborators via email
  • User management β€” View and remove document access

🌍 Supported Languages

English, French, Spanish, German, Italian, Portuguese, Chinese, Russian, Hindi, Japanese


🎬 Demo

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] [πŸŒ™]       β”‚
β”‚                           β”‚                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ›  Tech Stack

Core Framework

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

Real-time Collaboration

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

AI & Backend

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

UI & Styling

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

πŸš€ Getting Started

Prerequisites

  • 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

Installation

  1. Clone the repository
git clone https://github.com/yourusername/spacesapp.git
cd spacesapp
  1. Install dependencies
npm install
  1. Set up environment variables
cp .env.example .env.local
  1. Configure your environment (see Environment Variables)

  2. Run the development server

npm run dev
  1. Open http://localhost:3000

πŸ” Environment Variables

Create a .env.local file with the following variables:

Real-time Collaboration (Required)

# Liveblocks - https://liveblocks.io/docs/get-started
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEY=pk_...
LIVEBLOCKS_PRIVATE_KEY=sk_...

Firebase (Required)

# 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=...

AI Providers (At least one required)

# 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=...

Optional (Debug)

# Logs room ownership self-heal decisions on the server (dev only)
ROOM_OWNERSHIP_DEBUG=1

πŸ“ Project Structure

src/
β”œβ”€β”€ 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

πŸ— Architecture

Data Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client    │────▢│  Liveblocks │────▢│   Client    β”‚
β”‚  (Editor)   │◀────│   (Yjs)     │◀────│  (Editor)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                                       β”‚
       β–Ό                                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Firebase                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚Documents β”‚  β”‚  Users   β”‚  β”‚ Rooms (per user) β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Authentication Flow

User ──▢ Firebase Auth ──▢ ID Token ──▢ /api/auth/session (HttpOnly cookie)
                                           β”‚
                                           β–Ό
                                 Liveblocks Auth Endpoint
                                           β”‚
                                           β–Ό
                                Firebase Room Access Check
                                           β”‚
                                           β–Ό
                                Liveblocks Session Token

Firestore Data Model

documents/
└── {documentId}/
    β”œβ”€β”€ title: string
    β”œβ”€β”€ createdAt: timestamp
    └── updatedAt: timestamp

users/
└── {uid}/
    └── rooms/
        └── {documentId}/
            β”œβ”€β”€ roomId: string
            β”œβ”€β”€ userId: string
            β”œβ”€β”€ role: "owner" | "editor"
            └── createdAt: timestamp

πŸ“œ Available Scripts

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

🀝 Contributing

We welcome contributions! Here's how you can help:

Development Workflow

  1. Fork the repository
  2. Clone your fork locally
  3. Create a feature branch: git checkout -b feature/amazing-feature
  4. Make your changes
  5. Test thoroughly
  6. Commit with a descriptive message: git commit -m 'Add amazing feature'
  7. Push to your branch: git push origin feature/amazing-feature
  8. Open a Pull Request

Code Style

  • 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)

Commit Messages

Follow conventional commits:

feat: add document export feature
fix: resolve cursor sync delay
docs: update README with new env vars
refactor: simplify auth flow

πŸ› Troubleshooting

Common Issues

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
  1. Check that LIVEBLOCKS_PRIVATE_KEY is set correctly
  2. Verify you are signed in (Header should show your avatar + β€œSign Out”)
  3. Check the auth endpoint logs at /api/auth-endpoint
Firebase permission denied

Deploy the security rules from the project root:

  1. Copy firestore.rules to Firebase Console β†’ Firestore β†’ Rules
  2. Copy storage.rules to Firebase Console β†’ Storage β†’ Rules

Or use Firebase CLI:

firebase deploy --only firestore:rules,storage

See 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)

πŸ“„ License

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.


πŸ™ Acknowledgments


Made with ❀️ by the Spaces team

⭐ Star us on GitHub

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published