Skip to main content

ElectricSQL Real-time Operations Dashboard

This guide shows how to set up ElectricSQL for real-time reactive views of the operations framework.

Overview

ElectricSQL provides:
  • Real-time sync: Changes in PostgreSQL instantly appear in connected clients
  • Reactive queries: UI updates automatically when data changes
  • Offline support: Works offline and syncs when reconnected
  • Type-safe: Full TypeScript support with generated types

Architecture

PostgreSQL (WAL) → ElectricSQL Sync → WebSocket → Clients (React/Vue/HTML)

Operations Tables:
- operations
- operation_actions
- operation_action_history

Setup Steps

1. Start Services

# Restart PostgreSQL with logical replication enabled
docker-compose down
docker-compose up -d

# Wait for services to be healthy
docker-compose ps

2. Run Electric Migration

# Apply the Electric migration to enable replication
docker exec -i activation-api-postgres psql -U postgres -d activation_api < scripts/electric-migrations/01_enable_electric_operations.sql

3. Verify Electric is Running

# Check Electric status
curl http://localhost:3000/api/status

# Should return: {"status":"active"}

4. Open the Dashboard

# Option 1: Use a simple HTTP server
npx http-server examples/ -p 8080

# Then open: http://localhost:8080/electric-operations-dashboard.html

# Option 2: Open directly in browser (may have CORS issues)
open examples/electric-operations-dashboard.html

Using Electric in Your Application

React Example

npm install electric-sql @electric-sql/react
import { useShape } from '@electric-sql/react'

function OperationsDashboard() {
  const { data: operations } = useShape({
    url: 'http://localhost:3000/v1/shape/operations_with_actions',
    params: {
      orderBy: 'operation_created_at DESC',
      limit: '50'
    }
  })

  return (
    <div>
      {operations?.map(op => (
        <div key={op.operation_id}>
          <h3>{op.operation_id}</h3>
          <span>{op.operation_status}</span>
          <p>Actions: {op.completed_actions} / {op.actions.length}</p>
        </div>
      ))}
    </div>
  )
}

Vanilla JavaScript Example

import { ShapeStream } from "electric-sql";

const stream = new ShapeStream({
  url: "http://localhost:3000/v1/shape/operations",
  params: {
    where: "customer_id=123",
    orderBy: "created_at DESC",
  },
});

stream.subscribe((messages) => {
  messages.forEach(({ value, operation }) => {
    if (operation === "insert") {
      console.log("New operation:", value);
    } else if (operation === "update") {
      console.log("Operation updated:", value);
    }
  });
});

TypeScript with Generated Types

# Generate TypeScript types from your schema
npx electric-sql generate --service http://localhost:3000

# Use generated types
import { Operations, OperationActions } from './generated'

const operations: Operations[] = await db.operations.findMany()

Real-time Features

1. Live Operation Status

// Subscribe to a specific operation
const { data } = useShape({
  url: "http://localhost:3000/v1/shape/operations",
  params: { where: `id='${operationId}'` },
});

// Updates automatically when status changes!

2. Action Progress Tracking

// Subscribe to all actions for an operation
const { data: actions } = useShape({
  url: "http://localhost:3000/v1/shape/operation_actions",
  params: { where: `operation_id='${operationId}'` },
});

// Calculate progress in real-time
const progress =
  actions.filter((a) => a.status === "completed").length / actions.length;

3. Live Notifications

// Subscribe to new completed operations
stream.subscribe((messages) => {
  messages.forEach(({ value, operation }) => {
    if (operation === "update" && value.status === "completed") {
      showNotification(`Operation ${value.id} completed!`);
    }
  });
});

Performance Optimization

1. Filtered Syncs

Only sync data you need:
// Only sync operations for specific customer
useShape({
  url: "http://localhost:3000/v1/shape/operations",
  params: {
    where: "customer_id=123 AND created_at > NOW() - INTERVAL '24 hours'",
  },
});

2. Indexed Queries

The migration creates indexes for efficient queries:
-- Already created in migration
CREATE INDEX idx_operations_customer_status ON operations(customer_id, status, created_at DESC);
CREATE INDEX idx_actions_operation_status ON operation_actions(operation_id, status);

3. Materialized Views

For complex aggregations, use materialized views:
CREATE MATERIALIZED VIEW operation_stats AS
SELECT
  customer_id,
  COUNT(*) as total_operations,
  COUNT(*) FILTER (WHERE status = 'completed') as completed_count,
  AVG(EXTRACT(EPOCH FROM (completed_at - created_at))) as avg_duration_seconds
FROM operations
GROUP BY customer_id;

ALTER MATERIALIZED VIEW operation_stats ENABLE ELECTRIC;

Troubleshooting

Electric Not Connecting

# Check Electric logs
docker logs activation-api-electric

# Check PostgreSQL replication
docker exec activation-api-postgres psql -U postgres -d activation_api -c "SELECT * FROM pg_replication_slots;"

Tables Not Syncing

# Verify Electric is enabled
docker exec activation-api-postgres psql -U postgres -d activation_api -c "
SELECT table_name
FROM electric.ddl_commands
WHERE status = 'enabled';
"

CORS Issues

If opening HTML directly in browser, use http-server:
npx http-server examples/ -p 8080 --cors

Advanced: Custom Sync Logic

Server-side Electric Integration

import { Electric } from 'electric-sql'

// In your operations service
class OperationsService {
  async createOperation(data: CreateOperationData) {
    // Regular PostgreSQL insert
    const operation = await this.db.query(...)

    // Electric automatically syncs to connected clients!
    // No manual push/WebSocket code needed

    return operation
  }
}

Webhook → Database → Electric → UI Flow

1. Sales Agent sends webhook

2. Webhook receiver updates operation_actions

3. PostgreSQL triggers WAL event

4. Electric detects change

5. UI updates instantly via WebSocket
This is exactly what you want for real-time operation tracking!

Resources

Next Steps

  1. ✅ Start Electric with docker-compose
  2. ✅ Run migration to enable tables
  3. ✅ Open dashboard to see real-time updates
  4. 🔄 Run webhook test and watch operations update live!
  5. 🚀 Build your own React/Vue dashboard with Electric hooks
I