Skip to content

Bridge Architecture

Deep dive into the Bridge API architecture, the central orchestration layer.

Overview

Container Details

PropertyValue
Containermediamagic-bridge
Port3100
RuntimeNode.js 20
FrameworkExpress.js

Directory Structure

bridge/
├── server.js              # Entry point
├── package.json           # Dependencies
├── Dockerfile             # Container build

├── config/
│   └── platforms.js       # Platform configuration

├── helpers/
│   ├── ayrshare/          # Social media
│   │   ├── analytics.js
│   │   ├── comments.js
│   │   ├── history.js
│   │   ├── schedule.js
│   │   └── sync.js
│   │
│   ├── assemblyai/        # Transcription
│   │   └── transcribe.js
│   │
│   ├── boxcast/           # Boxcast sync
│   │   └── sync.js
│   │
│   ├── bunny/             # CDN
│   │   ├── storage.js
│   │   └── upload.js
│   │
│   ├── captions/          # Caption generation
│   │   ├── burnCaptions.js
│   │   ├── captionPipeline.js
│   │   └── generateASS.js
│   │
│   ├── claude/            # AI analysis
│   │   ├── analyze-clips.js
│   │   ├── prompts.js
│   │   └── transcript-analysis.js
│   │
│   ├── cron/              # Scheduled jobs
│   │   └── collectAnalytics.js
│   │
│   ├── deepgram/          # Transcription
│   │   └── transcribe.js
│   │
│   ├── espocrm/           # CRM client
│   │   └── client.js
│   │
│   ├── ffmpeg/            # Video processing
│   │   ├── compile.js
│   │   ├── extract.js
│   │   ├── filmstrip.js
│   │   └── waveform.js
│   │
│   ├── n8n/               # Workflows
│   │   └── triggerWorkflow.js
│   │
│   ├── postgres/          # Analytics DB
│   │   ├── client.js
│   │   └── queries.js
│   │
│   ├── stockmedia/        # Stock media
│   │   ├── runway.js
│   │   ├── shutterstock.js
│   │   └── storyblocks.js
│   │
│   └── xserver/           # Platform automation
│       └── client.js

└── routes/
    ├── index.js           # Route registration
    ├── analytics.js
    ├── ayrshare.js
    ├── boxcast.js
    ├── broll.js
    ├── cdn.js
    ├── clips.js
    ├── comments.js
    ├── webhooks.js
    └── xserver.js

Request Flow

Key Components

server.js (Entry Point)

javascript
import express from 'express';
import routes from './routes/index.js';

const app = express();

// Middleware
app.use(express.json());
app.use(cors());

// Routes
app.use('/', routes);

// Health check
app.get('/health', (req, res) => {
  res.json({ ok: true, service: 'mediamagic-bridge' });
});

// Start server
app.listen(3100);

Route Registration

javascript
// routes/index.js
import { Router } from 'express';
import webhooks from './webhooks.js';
import analytics from './analytics.js';
import ayrshare from './ayrshare.js';

const router = Router();

router.use('/webhooks', webhooks);
router.use('/analytics', analytics);
router.use('/ayrshare', ayrshare);
// ... more routes

export default router;

Webhook Handler Pattern

javascript
// routes/webhooks.js
router.post('/platform-updated', async (req, res) => {
  const entity = req.body;
  
  try {
    // Check if queued for publishing
    if (entity.status === 'Queued') {
      // Determine platform endpoint
      const route = PLATFORM_ROUTES[entity.platform];
      
      // Forward to X Server
      const result = await xServerClient.post(route, entity);
      
      // Update EspoCRM
      await espoClient.update('PlatformPublish', entity.id, {
        status: 'Published',
        platformUrl: result.url,
      });
    }
    
    res.json({ success: true });
  } catch (error) {
    // Update with error
    await espoClient.update('PlatformPublish', entity.id, {
      status: 'Failed',
      apiResponse: error.message,
    });
    
    res.status(500).json({ error: error.message });
  }
});

Helper Pattern

javascript
// helpers/ayrshare/schedule.js
export async function schedulePost(data) {
  const response = await axios.post(
    'https://app.ayrshare.com/api/post',
    {
      post: data.content,
      platforms: data.platforms,
      scheduleDate: data.scheduledAt,
      mediaUrls: data.mediaUrls,
    },
    {
      headers: {
        'Authorization': `Bearer ${process.env.AYRSHARE_API_KEY}`,
      },
    }
  );
  
  return response.data;
}

Cron Jobs

Scheduled tasks run inside the Bridge container:

javascript
// helpers/cron/collectAnalytics.js
import cron from 'node-cron';

// Run every 6 hours
cron.schedule('0 */6 * * *', async () => {
  console.log('Collecting analytics...');
  
  // Fetch from Ayrshare
  const analytics = await fetchAyrshareAnalytics();
  
  // Store in PostgreSQL
  await storeMetrics(analytics);
  
  console.log('Analytics collection complete');
});

Platform Routes Configuration

javascript
// routes/webhooks.js
const PLATFORM_ROUTES = {
  'Rumble': { 
    livestream: '/rumble-create', 
    upload: '/rumble-episode' 
  },
  'YouTube': { 
    livestream: '/youtube-create', 
    upload: null 
  },
  'Boxcast': { 
    livestream: '/boxcast-livestream', 
    upload: '/boxcast-media-upload' 
  },
  // ... more platforms
};

Error Handling

Error Response Format

json
{
  "error": "Error message",
  "code": "ERROR_CODE",
  "details": {}
}

Database Connections

PostgreSQL Pool

javascript
// helpers/postgres/client.js
import pg from 'pg';

const pool = new pg.Pool({
  host: process.env.POSTGRES_HOST || 'postgres',
  database: process.env.POSTGRES_DB || 'mediamagic_analytics',
  user: process.env.POSTGRES_USER || 'mediamagic',
  password: process.env.POSTGRES_PASSWORD,
});

export async function query(text, params) {
  const result = await pool.query(text, params);
  return result.rows;
}

EspoCRM Client

javascript
// helpers/espocrm/client.js
export async function update(entity, id, data) {
  return axios.put(
    `${ESPOCRM_URL}/api/v1/${entity}/${id}`,
    data,
    {
      headers: {
        'X-Api-Key': process.env.ESPOCRM_API_KEY,
        'Content-Type': 'application/json',
      },
    }
  );
}

Extending the Bridge

Adding a New Route

  1. Create route file:
javascript
// routes/myfeature.js
import { Router } from 'express';
const router = Router();

router.post('/action', async (req, res) => {
  // Implementation
});

export default router;
  1. Register in index:
javascript
// routes/index.js
import myfeature from './myfeature.js';
router.use('/myfeature', myfeature);

Adding a New Helper

  1. Create helper directory and file:
javascript
// helpers/myservice/client.js
export async function doSomething(params) {
  // Implementation
}
  1. Use in routes:
javascript
import { doSomething } from '../helpers/myservice/client.js';

MediaMagic CRM Documentation