# Tutorial: Deploying Collaboration Client and Server Separately

## Content

The SpreadJS Collaboration system enables real-time, multi-user editing experiences using the **Collaboration Client** (frontend) and **Collaboration Server** (backend).
This manual describes how to deploy these components **independently**, allowing full separation between the frontend (static website) and backend (Node.js WebSocket service).

## Prerequisites

* Complete the [Real-Time Collaborative Workbook](/spreadjs/docs/spreadjs-collaboration-server/spreadjs-sheets-collaboration/tutorial-real-time-collaborative-spreadjs-designer)
* Foundational knowledge of [Database Adapter](/spreadjs/docs/spreadjs-collaboration-server/collaboration-framework/js-collaboration-ot/database-adapter)

### Key Features

* Frontend–backend separation for flexible deployment.
* Real-time synchronization of SpreadJS workbooks across multiple users.
* Scalable backend built on Node.js and WebSocket.
* SQLite-based storage for document state persistence.
* Customizable frontend hosting (Nginx, Apache, IIS, etc.).

### Project Structure

The project consists of **two separate directories**:

```plaintext
collaboration-server/   # Backend only – deploy to Node.js environment
│── server.js
│── init-database.js
│── package.json

collaboration-client/   # Frontend only – static site
│── public/
│   ├── index.html
│   ├── client.js
│   └── client.bundle.js  # generated by webpack build
│── webpack.config.js
│── package.json
```

## Specific Step

***

### Collaboration Server Setup

#### Step 1: Create the Project Directory

```bash
mkdir collaboration-server && cd collaboration-server
npm init -y
```

#### Step 2: Configure package.json

```json
{
  "name": "collaboration-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node ./server.js"
  },
  "dependencies": {}
}
```

#### Step 3: Install Dependencies

```bash
npm install @mescius/js-collaboration @mescius/js-collaboration-ot
npm install @mescius/spread-sheets-collaboration
npm install sqlite3 @mescius/js-collaboration-ot-sqlite
```

#### Step 4: Create server.js

```typescript
import http from 'http';
import sqlite3 from 'sqlite3';
import { Server } from '@mescius/js-collaboration';
import * as OT from '@mescius/js-collaboration-ot';
import { type } from '@mescius/spread-sheets-collaboration';
import { SqliteDb } from '@mescius/js-collaboration-ot-sqlite';

// Register the SpreadJS collaboration type
OT.TypesManager.register(type);

const httpServer = http.createServer();
const server = new Server({ httpServer });
const port = 8080;

// Initialize SQLite database and adapter
const db = new sqlite3.Database("./docs.db");
const sqliteDbAdapter = new SqliteDb(db);

// Configure OT document services
const documentServices = new OT.DocumentServices({ db: sqliteDbAdapter });
server.useFeature(OT.documentFeature(documentServices));

// Start the server
httpServer.listen(port, () => {
    console.log(`Collaboration server listening on port ${port}`);
});
```

#### Step 5: Initialize the Database

Create `init-database.js`:

```typescript
import sqlite3 from "sqlite3";
const db = new sqlite3.Database("./docs.db");
async function initSqliteDataTables(db) {
    const run = (sql) => {
        return new Promise((resolve, reject) => {
            db.run(sql, (e) => (e ? reject(e) : resolve()));
        });
    };
    await run(
        `CREATE TABLE IF NOT EXISTS documents (
            id TEXT PRIMARY KEY,
            type TEXT NOT NULL,
            version INTEGER NOT NULL,
            snapshot_version INTEGER NOT NULL
        )`
    );
    await run(
        `CREATE TABLE IF NOT EXISTS operations (
            doc_id TEXT NOT NULL,
            version INTEGER NOT NULL,
            operation TEXT NOT NULL,
            PRIMARY KEY (doc_id, version),
            FOREIGN KEY (doc_id) REFERENCES documents (id) ON DELETE CASCADE
        )`
    );
    await run(
        `CREATE TABLE IF NOT EXISTS snapshot_fragments (
            doc_id TEXT NOT NULL,
            fragment_id TEXT NOT NULL,
            data TEXT NOT NULL,
            PRIMARY KEY (doc_id, fragment_id),
            FOREIGN KEY (doc_id) REFERENCES documents (id) ON DELETE CASCADE
        )`
    );
}
// Call the initialization function
initSqliteDataTables(db);
```

>type=note
> Run this step only on the first setup or when resetting the database.
>
> ```bash
> node init-database.js
> ```

***

### Collaboration Client Setup

#### Step 1: Create the Frontend Project

```bash
mkdir collaboration-client && cd collaboration-client
npm init -y
```

#### Step 2: Configure package.json

```json
{
  "name": "collaboration-client",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack"
  },
  "dependencies": {}
}
```

#### Step 3: Install Dependencies

```bash
# SpreadJS & collaboration client packages
npm install @mescius/spread-sheets @mescius/spread-sheets-collaboration-addon
npm install @mescius/js-collaboration-client @mescius/js-collaboration-ot-client
npm install @mescius/spread-sheets-collaboration-client

# Build tools
npm install --save-dev webpack webpack-cli style-loader css-loader
```

#### Step 4: Create the `public` Folder and Files

Create and update the front-end HTML page: **public/index.html**

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SpreadJS Real-Time Collaboration</title>
    <script src="./client.bundle.js"></script>
</head>
<body>
    <div id="ss" style="width:100vw; height:95vh; border:1px solid darkgray;"></div>
</body>
</html>
```

Create and update the front-end JavaScript code: **public/client.js**

```auto
import * as GC from '@mescius/spread-sheets';
import '@mescius/spread-sheets-collaboration-addon';
import { Client } from "@mescius/js-collaboration-client";
import * as OT from "@mescius/js-collaboration-ot-client";
import { type, bind } from '@mescius/spread-sheets-collaboration-client';
import "@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css";

// Register the SpreadJS collaboration data type
OT.TypesManager.register(type);

// ===== IMPORTANT: Update this to your actual collaboration server address =====
// Example for local development:
const SERVER_URL = "ws://127.0.0.1:8080";

// Example for production:
// const SERVER_URL = "wss://collab.yourdomain.com";
// const SERVER_URL = "wss://your-app.herokuapp.com";

window.onload = async function () {
    // Initialize the SpreadJS workbook
    const workbook = new GC.Spread.Sheets.Workbook('ss');

    // Establish a client connection and join a collaboration room
    const conn = new Client(SERVER_URL).connect('room1');
    const doc = new OT.SharedDoc(conn);

    // Handle connection and document synchronization errors
    doc.on('error', (err) => console.error('Collaboration error:', err));

    // Fetch the document state from the server
    await doc.fetch();

    if (!doc.type) {
        // Create a new shared document with initial content
        workbook.getActiveSheet().getCell(0, 0).value("default content");
        await doc.create(workbook.collaboration.toSnapshot(), type.uri, {});

        // Bind the workbook to the shared document for real-time sync
        bind(workbook, doc);
    } else {
        // If shared document already exists, just bind to it
        bind(workbook, doc);
    }
};
```

Create and update the front-end project configuration: **webpack.config.js**

```auto
const path = require("path");

module.exports = {
  entry: "./public/client.js",
  output: {
    path: path.resolve(__dirname, "public"),
    filename: "client.bundle.js",
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};
```

#### Step 5: Build the Frontend

```auto
npm run build
```

After building, a file named `public/client.bundle.js` will be created.

#### Step 6: Deploy the Frontend

Upload the entire `public/` folder to any static hosting server (e.g., Nginx, Apache, IIS).

***

## Feature Description

| Feature | Description |
| ------- | ----------- |
| **Real-time Synchronization** | Edits on one client appear instantly on all others sharing the same document room. |
| **Document Persistence** | Server stores snapshots and operational history using SQLite. |
| **Frontend–Backend Separation** | Each part can be deployed and scaled independently. |
| **WebSocket Communication** | Lightweight and efficient real-time connection. |
| **Cross-Platform Hosting** | Works across any static web host and Node.js environment. |

## Usage Instructions

### Step 1: Start the Backend

```auto
cd collaboration-server
npm run start
```

Expected output: *Collaboration server listening on port 8080*

### Step 2: Host the Frontend

Deploy `collaboration-client/public/` to your static server.

### Step 3: Test Real-Time Collaboration

1. Open the frontend page in multiple browsers or devices.
2. Edit any cell in one instance.
3. Observe the changes reflected instantly on all connected clients.